Architecture overview
ArcFlow stacks a single Rust execution engine under multiple language and network surfaces. Every path validates workflow specification JSON, schedules steps, emits trace data policy traces, and optionally persists recovery state. Understanding the layers makes it easier to place auth, Postgres, and Qdrant in the right tier.
Layer model
At the top sit the surfaces: Python SDK, TypeScript SDK, arcflow-server, arcflow-relay, static browser SDK (@arcflow/static), CLI, VS Code extension, and WASM (alpha). Each surface translates its native API into the same workflow and run envelope the engine expects.
Below that is workflow specification JSON: workflow definitions, agent definitions, run requests, and exec_config. Normative schemas are documented in workflow schema. See Workflow specification for how contract-first design keeps SDK and HTTP behavior aligned.
The engine (arcflow-core) performs validate, schedule, execute, trace, and recover. Entry point for runs is WorkflowEngine::execute_with_config. Linear runs use sorted steps; graph runs use the graph scheduler in workflow/graph/scheduler.rs.
Persistence and external services split by concern:
| Backend | Role |
|---|---|
| PostgreSQL | Runs, recovery checkpoints, HITL interrupt state, trace persistence, workflow registry, static product sites |
| Qdrant + LLM APIs | Vector memory, embeddings, rerank, provider chat completions |
Postgres is mandatory for POST /v1/runs on the server. Embedded SDK runs can skip Postgres unless you enable recovery or registry features. Relay is stateless and forwards to the server with scoped runtime keys.
Design principles
These principles show up in code review and deployment checklists:
| Principle | Meaning |
|---|---|
| Contract-first | workflow JSON and normative schemas precede surface-specific APIs |
| Typed errors | workflow ErrorCode values map to structured HTTP JSON on the server |
| trace data policy traces | Metadata only in traces: no prompt text, tool args, or chunk content |
| Self-hosted keys | LLM and embedding keys in environment variables, never in browser bundles |
| Recovery optional | exec_config.recovery_enabled gates Postgres persistence for resume |
Static product flow
The static product path serves public websites: a browser talks to Relay, Relay talks to the server, the server executes against LLM and RAG backends. Site tokens and origin allowlists replace exposing server API keys in JavaScript.
Sequence in prose:
- The browser sends
POST /v1/sites/{site_id}/runsto Relay with a site token and anOriginheader that matches the site configuration. - Relay validates the origin and applies per-site rate limits. On success it forwards
POST /v1/runstoarcflow-serverusing a scoped runtime key that limits which workflows the site may run. - The server resolves the workflow (often via registry semver, e.g.
runPublished("chat", "^1.0.0", message)), executes througharcflow-core, and returnsrun_idand status to Relay, which passes them to the browser. - The browser polls trace via Relay:
GET /v1/sites/{site_id}/runs/{run_id}/trace, which proxies toGET /v1/runs/{id}/traceon the server. Events are metadata-only (trace data policy).
Concrete browser API:
Operators provision sites and publish chat workflows through the admin API (POST /v1/admin/sites, knowledge ingest, POST.../workflows/chat/publish). Details live under static-product/.
Note: Server-sent events for live run streaming are not implemented (streaming deferred). Browser UX today polls trace for TokenEmitted and completion events.
Backend integration flow
Backend services integrate directly with arcflow-server when they already own auth and tenancy. This path is typical for internal tools and multi-tenant SaaS backends.
Sequence in prose:
- The client sends
POST /v1/runswithAuthorization: Bearer <ARCFLOW_SERVER_API_KEY>and optionallyIdempotency-Keyfor deduplication within the server window. - The server persists a run row in PostgreSQL, then invokes
execute_with_configon the engine. - During execution the engine writes recovery checkpoints and trace events to Postgres when
recovery_enabledis true. Linear recovery can resume from the last committed step index; graph checkpoint fields exist but full resume dispatch is partial (Graph recovery resume). - The server returns
run_id,trace_id, and initialstatus(oftenRunning). - The client polls
GET /v1/runs/{run_id}for terminal status, result payload, errors, or HITL interrupt metadata. Trace export usesGET /v1/runs/{run_id}/trace.
Example run request body:
Alternatively use "workflow_ref": { "name": "chat", "version": "^1.0.0" } instead of an inline workflow object, not both.
If Postgres is unavailable, POST /v1/runs returns 503. Health checks: GET /health (process up), GET /ready (Postgres connected, migrations applied).
Where to go next
| Question | Page |
|---|---|
| Which binary or package do I run? | Surfaces and when to use them |
| Linear vs graph execution | Execution model |
| Trace field rules | Trace data policy |
| Production vs deferred | Maturity and known gaps |