Architecture
Orchestrator, workers, truth boundaries, and the execution model.
Autopilot splits into three layers:
- Orchestrator — the control plane. Owns tasks, runs, workflow progression, events, artifacts, and durable previews.
- Workers — execution nodes. Run on real machines with real repo access, toolchains, and credentials.
.autopilot/— repo-authored policy. Agents, workflows, environments, providers, and handlers — all versioned in git.
Every client (CLI, bound conversations, future Worker App) operates over the same primitives. The orchestrator is the system of record. Workers execute. The repo defines the rules.
At a glance
| Layer | Owns | Does not own |
|---|---|---|
| Orchestrator | Tasks, runs, workflow progression, events, artifacts, durable previews | Runtime sessions, worktrees, local credentials |
| Worker | Runtime execution, repo access, per-run worktrees, raw local session state | Workflow truth, shared operational state |
| Repo config | Agents, workflows, environments, providers, handlers | Mutable runtime state |
Orchestrator
The orchestrator is the system of record for operational state. It:
- Stores tasks, runs, workers, leases, events, and artifacts
- Advances workflows based on explicit step outputs
- Serves durable preview URLs from stored artifacts
- Exposes the API used by the CLI and future clients
- Dispatches notification and conversation-provider flows when configured
It does not execute AI sessions itself.
Start it with:
autopilot server startWorker
A worker is a long-running execution node on a host machine. It:
- Claims pending runs from the orchestrator
- Executes through a runtime adapter
- Uses real repo access, toolchain access, and machine-local credentials
- Creates isolated git worktrees per run
- Stores raw transcript/session state locally
- Reports summaries, outputs, and artifacts back to the orchestrator
Start it with:
autopilot worker startFor local development, autopilot start still exists as a convenience shortcut that boots both processes.
Repo-authored config
Autopilot policy lives in .autopilot/ and stays reviewable in git:
.autopilot/
├── company.yaml
├── project.yaml
├── agents/
├── workflows/
├── environments/
├── providers/
└── handlers/That keeps workflows and operator policy:
- versioned
- diffable
- branchable
- editable without a separate admin UI
Truth boundaries
Use this mental model when deciding where something belongs:
| Place | Put here |
|---|---|
| Repo filesystem | Authored config and reviewable policy |
| Orchestrator DB/API | Shared operational state and durable artifact metadata/content |
| Worker-local state | Raw transcripts, local sessions, worktrees, resolved secrets |
This is the key architectural boundary: the orchestrator owns shared truth, while workers own machine-local runtime reality.
Execution flow
The normal path is:
- A task is created
- A workflow attaches and selects the current step
- The orchestrator creates a run
- A worker claims the run
- The worker executes through its runtime adapter
- The worker reports summary, outputs, and artifacts
- The orchestrator stores results and advances the workflow
- If the next step is
human_approval, the task blocks until an operator acts
This is intentionally explicit. Autopilot is not hiding a giant chat loop behind the scenes.
Workflow I/O
Workflows declare step outputs directly in YAML. The engine adds the machine-readable output suffix automatically, then routes using named output fields.
Current capabilities:
- explicit
next - ordered
transitions on_approve,on_reply,on_reject- source-run summary forwarding
- explicit
input.artifacts
That is enough for plan/review/implement loops without turning the workflow engine into a rules platform.
Runtime adapters
Autopilot does not ship its own AI runtime. Workers execute runs through adapters that wrap existing AI tools you already have installed and subscribed to.
The adapter model works like this:
- The worker resolves a binary on the host machine (e.g.
claude,codex,opencode) - The adapter spawns that binary as a subprocess with the run's prompt and instructions
- The adapter feeds the run context (task, instructions, MCP config) to the subprocess
- The subprocess does the actual AI work using your existing subscription
- The adapter parses the result back into Autopilot's structured format (summary, outputs, artifacts)
This means:
- No new AI vendor. Autopilot reuses the AI tools and subscriptions you already pay for.
- No API key management for models. The adapter delegates to the CLI tool, which handles its own auth.
- New runtimes are just new adapters. Adding Codex or OpenCode support means implementing the same
start → parse → returncontract against a different binary.
Today: Claude Code
The shipping adapter spawns the claude CLI. It supports:
- One run per worker at a time
- Per-run git worktrees for isolation
- Structured outputs and artifacts
- Session resumption via local session refs (for same-worker continuation)
- MCP integration — the worker injects Autopilot's task/run tools so the AI can inspect and create tasks during execution
Works with any Claude plan that includes CLI access (Pro, Team, Enterprise).
Codex, OpenCode
The same adapter model applies to Codex and OpenCode. The worker spawns codex or opencode instead of claude, feeds the same RunContext, and parses the result back into the same structured format.
The adapter interface is intentionally minimal — start(context), onEvent(handler), stop(). Adding a new runtime means:
- Map the runtime kind to a binary name
- Build the CLI arguments from the
RunContext - Parse the output into
RuntimeResult
Worker routing, capability advertisement, and run targeting already support multiple runtimes per worker. You can run a Claude Code worker and a Codex worker side by side, and the orchestrator routes runs based on the required_runtime field in workflow steps.
Durable previews
Preview URLs are orchestrator-backed, not worker-hosted.
Current flow:
- The worker collects previewable files from the run worktree
- Those files are sent back as
preview_fileartifacts - The orchestrator stores them durably
- The orchestrator serves them via
/api/previews/:runId/*path - A
preview_urlartifact points to the entry page
That means previews survive worker shutdown. If the worker laptop goes offline, the orchestrator can still serve the preview.
Important: preview URLs are not automatically public. They are served through the orchestrator's normal access model.
Pack distribution
Reusable integration material — providers, handlers, workflows, skills, context — is distributed through packs.
- Desired packs are declared in
.autopilot/company.yaml - Packs are resolved from git-backed registries
autopilot syncmaterializes pack files into.autopilot/and writes a lockfile- Installed files are normal repo config — editable, reviewable, version-controlled
This keeps integrations installable without hardcoding them into the core. See Packs and Distribution for the full model.
Providers, handlers, and surfaces
Autopilot extends through a provider/handler model:
- Providers are authored YAML under
.autopilot/providers/— integration instances that declare capabilities and secret refs - Handlers are Bun scripts under
.autopilot/handlers/— executable adapters that do protocol-specific work - Surfaces are human-facing channels (Telegram, Slack, email) built over providers, handlers, and conversation bindings
- The orchestrator invokes handlers with typed envelopes, validates results, and executes the real primitives
Current operations:
| Operation | Purpose |
|---|---|
notify.send | Send an outbound notification |
intent.ingest | Turn inbound payload into task creation |
conversation.ingest | Turn inbound conversation payload into task actions |
Surface integrations arrive as packs, not hardcoded features. See Providers and Handlers for the extension model and Telegram Surface for the first real example.
Security model
Auth and verification live at the orchestrator boundary:
- Inbound webhooks are verified by provider-declared
auth_secretrefs - Surface-specific headers (e.g., Telegram's
X-Telegram-Bot-Api-Secret-Token) are recognized natively - Generic providers use
X-Provider-Secretfor webhook auth - Workers authenticate via join tokens during enrollment
- Better Auth capabilities are reused for session management and OAuth flows where they fit
Handlers normalize provider-specific details but do not invent private auth subsystems. Webhook signatures, headers, and verification steps are always explicit and inspectable in the provider config and handler code.
Provider secrets are declared as references, not values. The orchestrator resolves them at handler invocation time and passes only the scoped subset needed for that operation.
Async operator model
The current product is still CLI-first.
The intended async loop is:
- A task or run reaches an actionable state
- An operator is notified out of band
- The operator inspects via CLI or a bound external conversation
- The operator replies, approves, or rejects
- The workflow continues
Current operator surfaces:
autopilot inboxandautopilot inbox --watchautopilot tasks approve|reject|replyautopilot runs show- durable
preview_urlartifacts - optional provider-driven notifications and conversation bindings
That is the current architecture in practice: control plane on the orchestrator, execution on workers, and a CLI-first async loop over explicit workflow primitives.
For deployment topology, multi-worker patterns, and the cloud-first model, see Cloud and Deployment.