Architecture
Pieces#
Canvas (apps/canvas)#
A SolidJS single-page app. Hand-written SVG renderer (no xyflow, no reactflow). Edits run through flowStore, which keeps the canonical FlowGraph JSON in memory; persistence is autosave-to-localStorage plus an explicit Save to the backend.
When ScaiKey OIDC is configured, the canvas authenticates via PKCE and exchanges the auth code for tokens through the backend's BFF (POST /v1/auth/exchange). A dev-token fallback exists for environments without ScaiKey.
ScaiFlow API (apps/api)#
FastAPI backend exposing /v1/*. Owns:
- Flow CRUD + deploy (
/v1/flows) — list, get, create, update, delete, deploy, run-tests, list versions. - Auth (
/v1/auth/*) — runtime ScaiKey config, BFF token exchange + refresh,/v1/me. - Admin (
/v1/admin/*) — ScaiKey-driven user/group sync, super_admin role grants, tenant flow visibility for tenant admins. - Catalog (
/v1/catalog/*) — per-tenant private flow packages. - Lookups (
/v1/scaiqueue/*,/v1/scaibunker/*,/v1/scaigrid/*,/v1/scaicore/*) — read-only proxies into ScaiGrid so the canvas never holds tenant API keys. - Webhooks (
/v1/webhooks/scaikey) — ScaiKey-signed events that update the local user/group mirror. - CRDT relay (
/v1/flows/{id}/syncWebSocket) — Yjs document fan-out for real-time editing.
Persistence is split: SQLAlchemy async on MariaDB for metadata (Alembic-managed schema), filesystem or S3 for the actual flow JSON content (keyed by flows/{tenant_id}/{flow_id}/v{version}.flow.json, never updated in place).
Compiler (apps/compiler)#
A Python library, not a service. compile_flow(flow_json, output_format="yaml") turns flow JSON into either:
- A YAML manifest for ScaiGrid (
POST /v1/modules/scaicore/cores) — the default, the deploy artifact. - A SCIR MessagePack IR bundle (
output_format="ir") — the upstream-canonical binary form, useful for verification and direct-runtime experiments. - A
.scaitext source (output_format="scai") — deprecated, mostly for inspection.
The same compiler runs in the API backend (for the live preview + deploy paths) and in the standalone CLI.
ScaiGrid (control plane)#
External — see the ScaiGrid docs. Accepts the YAML manifest, persists the Core, can optionally publish it as a chat model. ScaiFlow talks to ScaiGrid via the scaigrid-client SDK.
ScaiCore (runtime)#
External — see the ScaiCore docs. Actually executes invocations against the Core that ScaiGrid persisted. ScaiFlow doesn't talk to ScaiCore directly; the deployed Core does the runtime work.
Auth flow at a glance#
The single ScaiKey client_id is shared by the canvas (browser) and the backend. The backend keeps the client_secret server-side; the canvas hands the auth code over for exchange.
ScaiGrid accepts the user JWT directly (its audience is the ScaiKey client_id, which ScaiGrid trusts), so the same token flows end-to-end. For non-user contexts (cron jobs, background sync), the backend falls back to a per-tenant sgk_* API key stored in ScaiVault under tenants/{tenant_id}/scaigrid_api_key.