Skip to main content

Architecture

autodev is a Rust workspace organized around one rule: policy, storage, execution, orchestration, and presentation should not quietly take responsibility from one another.

Crate boundaries​

CrateOwns
autodev-modelTyped entities and pure rules for planning, story workflows, evidence, events, cost, metrics, and retries
autodev-storeMarkdown planning files, git-backed history, repository write locking, and the FleetStore runtime port
autodev-bridgeAgent harness adapters, process and transcript observation, environment policy, confinement, and mechanical evidence helpers
autodev-fleetThe reconciler that schedules waves and advances turns, review, integration, gates, apply, retries, and recovery
autodev-workflowThe coordinator workflow language as Rust structs: the verb catalog, typed nodes with a closed kind enum per domain, DAG validation, the builder the built-ins are written with, and the YAML encoding
autodev-canvasThe declarative canvas vocabulary, schema validation, datasource bindings, resolution, and encoding
autodev-cliCommand parsing, human/JSON rendering, the central daemon, and the loopback operator workspace for board, fleet, conversation, workspace, daemon, and the read surfaces

The CLI is deliberately thin: model decisions belong in the model crate, filesystem facts in the store, harness behavior in bridges, and lifecycle orchestration in the fleet.

Two durable surfaces​

Planning store​

Planning is repository content. The loader reads the working tree so an uncommitted edit is still a real edit rather than an invisible one.

docs/stories/ story contracts
docs/epics/ epic contracts
docs/designs/ referenced designs
docs/decisions/ architectural decisions
docs/glossary/ shared terminology

Files use Markdown bodies and typed frontmatter. A malformed or unrepresentable file becomes a load issue; the loader does not silently drop it and pretend the entity is absent. Git history supplies planning lifetime data without a second mutable counter.

Fleet store​

Runtime state lives behind the FleetStore trait. An unregistered repository may use its local .autodev/fleet.sqlite backend in process. A registered workspace instead reaches the daemon's one global ~/.local/share/autodev/fleet.sqlite over HTTP; if the daemon is unavailable, the store is unreachable rather than replaced with a local history. The memory, local SQLite, and HTTP implementations run the same executable store contract.

Waves and workers are typed, individually revisioned records; updates use compare-and-set so a stale writer receives a conflict instead of overwriting newer state. Workspace-scoped records inside the daemon-owned database are enforced by the executable store contract.

Handoffs and deliveries are append-only facts. Events have a strict sequence, timestamp, and actor. Transcripts are stored once by reference and bounded by an explicit budget.

Control projection​

The daemon's client surface projects the two durable surfaces into the embedded operator workspace. Its opening snapshot includes board entities and whole-store delivery facts; its websocket continues from the store event sequence. Browser filters, layout preferences, open drawers, and time-travel cursors are view state only.

Canvas documents are validated declarations over a closed widget vocabulary. Datasource handles are resolved by the host under the current principal's grants; declarations cannot carry scripts or credentials.

Execution boundary​

AgentBridge is the port between autodev and an agent harness. Built-in adapters support Codex, Claude Code, and an operator-provided command template. A bridge is responsible for launching one turn, streaming output, observing the process and git result, and reporting usage honestly.

Bridges do not decide that work is acceptable. The host independently builds evidence and the fleet owns the transition to review, integration, and delivery. Repository configuration binds named bridges to roles, so planning data never needs a vendor-specific model identifier.

Concurrency and serialization​

The expensive read/write-isolated work overlaps where its artifacts do not share a mutable target: worker turns use separate worktrees, and review turns use separate read-focused checkouts. Capacity is configured independently from how many stories a wave batches.

Integration and base-ref advancement are serial by design:

  • each integration must start from the current accepted tip and gate the tree it creates;
  • each apply advances the shared base ref only after the post-merge result has passed its gate.

Parallelizing either operation would let two green decisions be made against trees that omit one another.

Process topology​

browser
│ HTTP + websocket, loopback :7777
▼
daemon client + drive ───────┐
│ dyn FleetStore
CLI ─────────────────────────┤
├── unregistered repository → local .autodev/fleet.sqlite
│
└── registered workspace → HTTP/JSON :7788 → daemon → global fleet.sqlite

The daemon owns runtime state and registered-workspace drives. The browser client and machine API are listeners in that same process but remain on separate sockets. serve retains a temporary standalone compatibility path; it is not the normal topology. A board read in an unregistered repository remains available with no daemon running.

Configuration surfaces​

PathPurpose
.autodev/fleet.tomlBridges, role bindings, validation and gate commands, environment policy, capacity, retry, resource, and transcript limits
.autodev/workflows.tomlOptional repository story-workflow definitions that shadow matching built-ins
.autodev/coordinator.yamlOptional repository coordinator workflow graphs, applied over the built-in; inspect the result with autodev workflow show
.autodev/fleet.sqliteRuntime state for an unregistered repository, or legacy history awaiting import after registration
~/.local/share/autodev/fleet.sqliteOne daemon-owned runtime store, globally shared and workspace-scoped
Platform data directoryCentral workspace registry, endpoint record, token material, and the global daemon store

The architecture keeps the core model portable while the repository decides how to run it. The trust and evidence boundary stays in the host around every configured harness.