Skip to content

Repository files navigation

Agent Supervisor

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?

Architecture

                         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.

Implemented

  • immutable session manifests and generation-fenced agent bindings;
  • journal-before-dispatch effect records with terminal receipts and explicit outcome_unknown reconciliation;
  • 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.

Deliberate boundaries

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.

Workspace

  • domain: pure identifiers, semantic messages, and state transitions
  • protocol: versioned serializable boundary types
  • ports: traits owned by the kernel rather than adapters
  • runtime: provider-neutral agent loop over provider and tool ports
  • agent-supervisor: executable, CLI, SQLite state, contract support, and concrete OpenAI-compatible and root-confined tool adapters
  • paper-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.

Development

cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo run -p agent-supervisor -- contract check contracts/upstream-v1

Try a live turn

The 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 pending

State 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.

Native terminal client

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.

Simulated trading authority demo

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_ID

The 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.

About

Experimental Rust supervisor for external AI agents: durable attempts, authority tiers, effect receipts, interruption, and crash recovery.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages