Skip to main content
  1. The Scheduler fires; agent-api asks the Runtime to spawn (it touches no docker itself).
  2. The container mounts the granted workspaces at /workspace (no clone) + brokers creds.
  3. The agent resumes from the session file in the rw folder (continuity is a file), runs the runner, and commits freeform changes.
  4. It emits events on its Stream; the container is reaped when idle.
The workspace folder (+ its session file) is the only durable state; the container is disposable.

Implemented — the live path

A dispatch is the in-container worker agent_api.worker. The Runtime injects everything it needs as env + a bind-mount, and the worker drives the runner over the mounted folder:
trigger → Scheduler → Runtime spawns the `agent` container  (CMD: python -m agent_api.worker)
  ├─ bind-mounts the workspace folder at /workspace          (ported in, not cloned)
  ├─ injects the signed dispatch token + REDIS_URL + the unit:<id>:in / unit:<id>:out topics + `start`
  └─ brokers the model credential                            (never in the dispatch envelope)
worker → one governed turn:  runner → workspace.v1 re-validate → git commit
  ├─ XADD each UnitEvent to unit:<id>:out                    (the Stream)
  └─ block on unit:<id>:in for the next message; idle ⇒ exit ⇒ container reaped  (TTL-on-idle)
Continuity is files in the workspace. Both the session id (.claude/.session) and the chat transcript are saved in the folder — claude-code’s transcript dir is symlinked into <workspace>/.claude/projects — so a fresh container resumes the same conversation from the durable git folder, no warm container needed.
Proven end-to-end on docker: a unit.v1 dispatch → isolated vexa-agent-<id> container → a real claude turn → a workspace.v1-governed commit → events on unit:<id>:out. Code: core/agent/services/agent-api/src/agent_api/worker.py (the harness), core/runtime/src/runtime_kernel/docker_backend.py (mount + credential brokering).

The same run, any substrate

The flow above is the Docker path (the open-core default). agent-api never spawns anything itself — it hands the Runtime a runtime.v1 workload, and the kernel’s pluggable backend turns that same workload into a child process, a container, or a Kubernetes Pod (RUNTIME_BACKEND=k8s) — same lifecycle, same dispatch, same worker. Only how the container is created changes; the run does not. The per-backend mechanics — and what the k8s path does and does not wire up yet — are in Runtime → Where it runs.