Skip to content

spawn_agent cross-runner: remaining work (codex origin + deferred) #361

Description

@mariorha

Remaining work from the design doc rsworkspace/docs/spwan-agent-cross-runner.md, confirmed via a two-sided adversarial audit against the real implementation (commit 97b5993b, worktree swarm/20260618T212853Z-0d60/spawn-cross-runner). No todo!/unimplemented!/stubs in the spawn paths.

Already implemented (verified — do not redo)

  • PR1–PR9: DONE. model + find_by_model fail-loud on multi-match + unavailable-model error (registry.rs, spawn_routing.rs); spawn Bridge retargeted to the resolved prefix with a per-prefix cache; spawn_depth via meta, persisted atomically + MAX_SPAWN_DEPTH=3 guard before spawning (G4); shared plain-NATS forwarding primitive + session_id rewrite + dead HTTP path removed (spawn_handler.rs) (G1); multi-level cancel cascade (G5); bounded structured result with transcript_ref/branch_ref with a real producer (publish_transcript) (G6); isolated workspace fail-loud + uncommitted overlay + change-aware teardown + GC by TTL/parent-close (G7); prefix-qualified disambiguation (PR6); tracked handle (status/result subjects) + collect_spawn + idempotency (reuse_or_insert) (PR7); async concurrency + per-parent caps + per-spawn tool allowlist enforced destination-side (PR8); identity + OTel + emitted protobuf accounting event (PR9). Protos under proto/trogonai/spawn/v1/. Typed config.
  • Kill-switch / feature-flag (ADR-0007): cross_provider_enabled / env SPAWN_CROSS_PROVIDER_ENABLED, enforced by cross_provider_gate (same-runner always allowed).
  • G8 two layers: registry pre-check (error) + runtime failure → handle Failed.

Verification status: cargo build --workspace ✅ compiles clean; unit tests ✅ (runner-tools+registry 258, runners 802, spawn-specific 41 — 0 failures).

Remaining work

Codex (PR10 — partial by design)

  • Codex as spawn ORIGIN: expose spawn_agent (and collect_spawn) as MCP tools to the Codex CLI subprocess. Today it only works as a destination.
  • Codex destination does not parse SpawnMeta: new_session (trogon-codex-runner/src/agent.rs:339) ignores req.meta → it does not honor spawn_depth, per-spawn allowed_tools, identity, or destination-side provisioning. (G7 isolation still holds via the parent's workingDirectory.)

Cross-runner environment (G3)

  • Opt-in propagation of MCP/egress via the spawn contract: SpawnMeta (proto + domain) has no mcp/egress fields. The "do not propagate" default is implemented; the opt-in mechanism to propagate specific MCP servers / egress policy when a task needs them is missing.

Hosted plane (deferred — HARD dependency for hosted)

  • Auth/tenant/quota Gateway: net-new, general infra. Spawn ships the hooks (identity via meta, accounting, caps), but the plane that triggers/enforces them is missing.
  • Cancel-on-quota: the serve_spawn_quota_cancel hook (spawn_cancel.rs) exists but is not wired into any runner main → inert until (a) a runner serves it and (b) the gateway's quota trigger exists.

Other deferred

  • Genuinely-remote cross-host: clone_workspace_at clones from a local repo_root and is gated off (destination_provisioning=false). The remote descriptor (repo + ref + sync from another host) is missing. v1 = shared FS.
  • Tool-capability guarantee (runner-owned): no supports_tools in registry/runner; v1 assumes "advertised ≡ tool-capable".
  • Registry record protobuf migration (ADR-0009): acp_prefix/models are still untyped JSON in metadata (registry.rs:205). Migrate-when-touched.

Optional optimizations (not v1)

  • Parallel dispatch (async/handle already provides concurrency).
  • Auto-merge fast-path (CI-gated); today a changed worktree is persisted for explicit reconciliation.

Verification (pending: needs infra/credentials) — belongs to THIS issue

  • Integration over real NATS (spawn_forwarding_integration.rs): run with NATS/Docker up (streaming with rewritten session_id + spawn_id attribution; status/result on the handle subjects). Not executed today without a server.
  • Cross-provider normalization test (v1 gate, after PR4): verify ACP normalizes forwarded session/update between providers (a parent of one provider correctly receives chunks from a child of another). Does not exist — the current integration test only exercises plain-NATS forwarding + handle subjects with a mock, not the normalized cross-provider new_session/prompt path.
  • Cross-provider E2E with real APIs (P3): spawn a sub-agent of another provider end-to-end with real API calls (grok spawns claude and it responds with tokens): acp.grok → claude-opus-4-6, acp → grok-4, acp → openai/gpt-4o. Requires the runners up with ANTHROPIC_TOKEN/XAI_API_KEY/OPENROUTER_API_KEY (ask before using credentials). Not to be confused with Test mid-session model switching end-to-end (incl. real credentials) #359 (that is the E2E for mid-session model switching, a different feature).

Note (not a bug, worth tracking)

  • The status/result/accounting messages are protobuf types but are serialized with serde_json::to_vec on the internal {prefix}.spawn.* subjects, whereas the doc says "binary on internal paths". The contract stays typed (drift-proof); it is an encoding detail, not a missing feature.

Design doc: rsworkspace/docs/spwan-agent-cross-runner.md · Implementation: commit 97b5993b · Related: #291

Metadata

Metadata

Assignees

Labels

rustPull requests that update rust code

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions