Repository navigation
[coordination] Supervision graph as configured platform data — hierarchy belongs to the platform, not inside an agent #183
Description
Design: docs/supervision.md. Extends #154, which deferred cross-agent work until "a real second consumer beyond Coder" existed — configurable multi-layer supervision is that consumer.
The observation
Coder has a two-level hierarchy: Overseer coordinates across repos → each repo's Pilot → Engine. The structure is right. It lives in the wrong place — inside the agent rather than in the platform.
Three things hardcode it:
| Hardcoded as | Where | Consequence |
|---|---|---|
| Target is a repo | drive_claude(repoId, instruction) |
You cannot delegate to an agent. The type forbids it. |
| Coordinator is a route | POST /:instanceId/coding/overseer |
Supervision is code, not configuration. |
| Depth fixed at 2 | Overseer → Pilot → Engine, by construction | No third layer is expressible. |
No table anywhere describes who supervises whom. So supervision cannot be configured, inspected, or reused — every future agent needing a coordinator would rebuild the Overseer.
Supervision is a different edge from choreography
agent_connections (0056) routes an emitted FACT to another instance — deliberately decoupled, a producer must not know its consumers. Correct for the lead chain. Supervision is not that edge:
| Choreography (built) | Supervision (missing) | |
|---|---|---|
| Verb | emit a fact | assign a goal |
| Addressing | producer doesn't know consumer | supervisor names the subordinate |
| Result | nothing returns | result returns; supervisor is accountable |
| Failure | dead-letter + replay | escalate to the supervisor |
| Shape | fan-out | tree |
Modelling supervision as an event connection would lose the return path and the accountability — the entire point. But both need at-least-once handoff, idempotency and trace correlation, which migration 0058 already provides, so supervision reuses the delivery outbox rather than growing a second reliability mechanism (same argument that re-scoped #17).
Scope
- Owner-scoped edge:
supervisor_instance_id → subordinate_instance_id(both instances belong to one user, as connections already enforce). - DAG validation at wiring time — A supervises B supervises A is now reachable by configuration, not just a code bug, and it is an unbounded money-spending loop. Reject at create time, when the human is present.
- Handoff rides the 0058 outbox; parent trace flows down every hop so a three-level delegation renders as ONE tree (the
traceId→ child run →chain.linkmechanism already built for the pump). - Wiring API + validation; console surface tracked with [console] Agent-to-agent connections have no UI — the pump is invisible #182.
- Depends on [coordination][deferred] First-class delegate(target, goal) registry primitive #156 (generalize
delegatetarget fromrepoIdto a supervisable entity) — that type change is the smallest useful first step.
Acceptance
- A user can configure instance A to supervise instance B without code.
- A cycle is rejected at wiring time with a readable message.
- A delegation survives a transient subordinate failure (outbox retry) and dead-letters visibly when exhausted.
- A multi-level delegation renders as a single correlated trace.
- Coder's Overseer is re-expressible in the primitive; the hardcoded route can then come out.
Companions: #184 (budget), #185 (authority containment). Both are cheap to build in now and expensive to retrofit.
Activity
feat(coordination): delegate to a TARGET, not a repoId (#156)
feat(coordination): supervision graph as configured platform data (#183)
feat(coordination)!: supervision lends a goal, never privileges (#185)
serge-ivo commentedon Aug 3, 2026
Core landed in
c465deb(migration 0060).Shipped:
agent_supervisiontable ·lib/supervision-graph.ts(pure rules) ·lib/supervision.ts(store) ·GET/POST/DELETE /v1/instances/:id/supervision, scoped to the supervisor and mirroring the connection routes.Three calls worth recording:
agent_connections, deliberately. Choreography emits a fact to unknown consumers; supervision names a subordinate and owns the result. Merging them would lose the return path and the accountability. They share the delivery substrate (the 0058 outbox), not the shape.MAX_DEPTH. There is a test pinning exactly that case.Graph walks are visited-guarded throughout, so pre-existing cyclic rows terminate rather than hanging a Worker.
29 tests. Still open on this ticket: reusing the 0058 outbox for the delegation handoff itself, and the console surface (#182).
feat(coordination): delegation budget — shared root pool, reserved be…
feat(coder2): declare the Coder as data — two templates, no bespoke c…
feat(mcp): make composing a multi-agent system self-serve (#182, #183, …
serge-ivo commentedon Aug 4, 2026
Done in
c465deb(migration 0060), console UI in802d764. Verified live: cycle, self-supervision and second-supervisor all rejected against production with readable messages. Three Repo Coders now run under one Coder Lead.fix(supervision): the roster fits, and the count rides in front of it…