Agent Supervisor is experimental Rust infrastructure for treating external AI agents as long-running, unreliable processes. It explores durable identity, lifecycle management, execution authority, interruption, crash recovery, and evidence capture without attempting to replace the agents it supervises.
The project is a research prototype, not a production security boundary or a general agent framework. Its purpose is to make a narrower systems question concrete:
What must a host record and control so that an external agent can stop, crash, resume, or be replaced without corrupting authoritative state?
clients
CLI / TUI / JSON-RPC
|
v
+--------------------+
| Agent Supervisor |
|--------------------|
| attempts + leases |
| authority + policy |
| effects + receipts |
| recovery + evidence|
+----------+---------+
|
SQLite state
|
+-----------------+-----------------+
| | |
v v v
hosted loop Codex app-server ACP process
host-owned tools managed tools worker-owned tools
The trust tier is explicit rather than inferred from the agent name:
| Tier | Supervisor guarantee |
|---|---|
hosted |
The supervisor owns the model loop and every model-visible effect. |
managed |
Cognition is external, but model-visible effects cross the supervisor's tool host. |
external |
The supervisor owns attempt lifecycle and observations; the agent retains its own tools and effects. |
- immutable session manifests and generation-fenced agent bindings;
- journal-before-dispatch effect records with terminal receipts and explicit
outcome_unknownreconciliation; - foreground interruption and crash recovery without silently replaying billable inference or ambiguous effects;
- durable delegation with claims, heartbeats, leases, fencing, and exactly-once result delivery;
- a hosted provider loop, a restricted Codex app-server adapter, and a generic ACP adapter exercised with independent agent processes;
- before/after Git observations that remain separate from an external agent's claims;
- an engine-neutral Rust TUI and newline-delimited JSON-RPC gateway;
- a simulation-only paper-trading consumer that pressure-tests approval, idempotency, and ambiguous-outcome handling without broker connectivity.
Agent Supervisor does not provide model inference, a universal agent class, a workspace sandbox, browser automation, remote execution, semantic memory, or a workflow-graph framework. Those belong to supervised agents or dedicated execution systems until a concrete invariant requires otherwise.
The original compatibility fixtures remain as a byte-pinned, effect-free
upstream corpus under contracts/upstream-v1; Python is not imported or
executed at runtime. The ownership decision and rejected alternatives are
recorded in the v0.2 architecture decision.
domain: pure identifiers, semantic messages, and state transitionsprotocol: versioned serializable boundary typesports: traits owned by the kernel rather than adaptersruntime: provider-neutral agent loop over provider and tool portsagent-supervisor: executable, CLI, SQLite state, contract support, and concrete OpenAI-compatible and root-confined tool adapterspaper-trader: a separate, simulation-only authority application that consumes kernel identity and trust types without putting trading concepts in the kernel
Crates are created only for real dependency boundaries. Concrete adapters stay
as modules in agent-supervisor until another executable, an optional dependency, or an
independently distributed component needs them. Subsystem names alone are not
a reason to create a package.
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo run -p agent-supervisor -- contract check contracts/upstream-v1The live path supports OpenAI, OpenRouter, and custom OpenAI-compatible
endpoints. Credentials are read only from the selected environment variable;
they are never accepted as command-line arguments. agent-supervisor chat exposes
root-confined read-only workspace inspection plus leaf delegation. Common
credential paths such as .env, .ssh, and .git are denied even when they
are beneath that root.
export OPENROUTER_API_KEY="..."
cargo run -p agent-supervisor -- chat \
--provider openrouter \
--model your-model-id \
--root . \
"Read the project README and explain the architecture."For a local server that needs no credential:
cargo run -p agent-supervisor -- chat \
--provider custom \
--base-url http://127.0.0.1:11434/v1 \
--model your-model \
"Say hello."To use an existing authenticated Codex installation as the cognitive engine while the supervisor retains tool and session authority:
cargo run -p agent-supervisor -- chat \
--engine codex \
--codex-command /absolute/path/to/codex \
--model gpt-5.6-sol \
--reasoning low \
--root . \
"Read Cargo.toml and list the workspace packages."This does not copy ChatGPT credentials into Agent Supervisor. Codex app-server
owns its login and model connection; the supervisor exposes only its frozen
dynamic tools and journals every resulting invocation. Ephemeral chat uses an
ephemeral worker thread. Durable sessions persist a generation-fenced worker
binding and branch each later turn from the exact last Codex turn committed by
the supervisor; uncommitted worker history is therefore excluded after a
crash. Reasoning
effort defaults to low for a new Codex session and is frozen with the
authority profile in its immutable engine configuration; pass --reasoning medium, high, or another supported level when creating the session if a
larger budget is worth the latency.
To supervise a generic ACP agent while leaving its model connection and tool loop outside the supervisor:
cargo run -p agent-supervisor -- chat \
--session acp-demo \
--engine acp \
--acp-command /absolute/path/to/goose \
--acp-arg=acp \
--acp-permissions deny \
--root . \
"Inspect this project."ACP mode deliberately gives a weaker guarantee than the Codex dynamic-tool
bridge: the external agent owns its effects. The supervisor owns attempt
lifecycle, canonical conversation continuity, generation-fenced agent
bindings, conservative outcome_unknown recovery, and bounded before/after
Git evidence. A later turn may use a different ACP executable; Agent Supervisor
creates a fresh ACP session and supplies only committed supervisor history.
Every accepted attempt freezes the observed agent name, version, external
session identity, authority profile, and external trust tier before work
begins, so interrupted and unknown attempts retain their own attribution after
a replacement agent runs.
The latest completed worker binding remains only a fenced resume projection. See
docs/acp-supervision-experiment.md for the tested guarantees,
limitations, real Goose/OpenCode results, and the build-vs-reuse conclusion.
Add --session NAME to create a durable lineage or resume it in a later
process. Its provider, model, prompt, tool catalog, and root are immutable:
cargo run -p agent-supervisor -- chat --session demo \
--provider openrouter --model your-model-id --root . \
"Inspect this repository."
cargo run -p agent-supervisor -- chat --session demo "What did you find?"
cargo run -p agent-supervisor -- session list
cargo run -p agent-supervisor -- effect pendingState defaults to ~/.agent-supervisor/state.db; use the global --state PATH
option for an isolated database. The runtime writes every tool plan to its
effect ledger before dispatch and records its terminal result afterward.
effect pending exposes records left between those writes by an interrupted
process; it does not retry them automatically.
agent-supervisor tui is the minimal engine-neutral reference client. It starts the
same stdio gateway as a supervised child with literal arguments, then renders
only gateway sessions, canonical messages, streaming text, tool activity,
approvals, and lifecycle state:
cargo run -p agent-supervisor -- tui \
--engine codex \
--codex-command /absolute/path/to/codex \
--model gpt-5.6-sol \
--reasoning low \
--root .The Codex process inherits the existing authenticated login; Agent Supervisor
does not copy its credential. Press n to create a session, Enter to resume or send,
Esc to interrupt a running turn, and F2 to return to the session picker.
Terminal effects show an allow-once/deny prompt. On completion or interruption,
the client discards its temporary stream and reloads the gateway's canonical
session projection. Restarting the TUI therefore does not depend on UI state.
The footer shows the agent implementation and its honest supervision tier:
hosted for the supervisor-owned direct loop, managed for a restricted Codex
app-server worker whose effects cross ToolHost, and external for ACP agents
that retain their own tool loop. These tiers describe guarantees; they are not
cosmetic engine labels.
paper-trader is a deliberately separate application proving that the generic
authority primitives can supervise a consequential domain workflow without
turning Agent Supervisor into a trading engine. It never opens a network
connection, loads broker credentials, or places a live order.
An agent proposal includes its source attempt, identity and trust tier plus the symbol, side, quantity, order type, limit price, and rationale. The application allocates an independent effect identity, applies a deterministic paper-only risk policy, requires allow-once or denial, and dispatches only an approved proposal to a local idempotent broker simulator. For example:
PAPER_DB=/tmp/agent-supervisor-paper.db
cargo run -p paper-trader -- --state "$PAPER_DB" propose \
--source-attempt-id turn-example \
--agent-name goose \
--agent-trust external \
--symbol SPY --side buy --order-type limit \
--quantity 10 --limit-price-cents 50000 \
--rationale "paper-only trend hypothesis"
# Use the returned order_id.
cargo run -p paper-trader -- --state "$PAPER_DB" tui ORDER_IDThe native TUI shows the agent claim separately from deterministic risk and
broker evidence. It can inject a crash after broker acceptance or a lost
response, then reconstruct from a fresh process. Reconciliation commits a
queryable idempotent receipt or conservatively records outcome_unknown; it
never guesses or automatically retries ambiguity. See
docs/paper-trading-authority.md.
New sessions can use delegate_task for focused independent work. In
agent-supervisor chat, children remain synchronous and return their bounded
summaries to the current turn. In agent-supervisor gateway, the frozen tool
contract instead queues a durable child immediately. A fenced, heartbeating worker runs that
child in its own immutable session, and its terminal result enters the parent
exactly once with the next explicit user turn. Both modes give children only
the read-only tools and no recursive delegation. Existing sessions retain the
tool behavior frozen in their original catalog. Gateway clients can inspect or
cancel these runs with delegation.list, delegation.status, and
delegation.cancel; cancellation is durable before the worker is signalled.
The same durable runtime is also reachable through a minimal long-lived stdio JSON-RPC host consumed by the native TUI:
cargo run -p agent-supervisor -- gateway \
--provider openrouter --model your-model-id --root .This command emits protocol frames for a client rather than drawing a UI. It
supports foreground streaming and recovery plus durable background delegation.
Accepted prompts and delivered background events are captured atomically
before provider work. A gateway restart exposes abandoned foreground or child
work as outcome_unknown without replaying billable inference. See
docs/tui-gateway.md for the exact supported method set,
launch command, and current limitations.
New gateway sessions additionally expose a real shell-backed terminal tool.
Every call blocks on the connected client's approval overlay; the plan is
journaled before the prompt, and once or deny is persisted before dispatch
or rejection. The
working directory is the frozen root, but an approved command is not filesystem
sandboxed. See docs/terminal-approvals.md.
The bounded contracts, foreground turns, synchronous children, and durable gateway workers all use the same runtime.