Skip to content

docs: merge the #417 and #392 subagent-steering designs into one - #450

Merged
justrach merged 1 commit into
release/0.0.242from
docs/subagent-steering-design
Aug 6, 2026
Merged

docs: merge the #417 and #392 subagent-steering designs into one#450
justrach merged 1 commit into
release/0.0.242from
docs/subagent-steering-design

Conversation

@justrach

@justrach justrach commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Closes the design half of #417 and #392. No behaviour change; this is the reconciliation both issues were blocked on.

The two issues describe one mechanism from two directions: #417 from addressability (durable child registry, children reachable by name, messages that steer a running child), #392 from resumption (a task id from spawn, follow-ups that continue the same worker, a queue-vs-trigger split). Neither is implementable without most of the other, and built separately they would produce two id schemes, two registries and two message paths.

Three findings from grounding the merge against the source

#392's central premise is false. It argues resume is "plumbing, not new state" because the worker transcript already persists under .graff/subagents/. It does not. cards.zig:writeSubagentDetail writes a final report plus metadata as markdown: no message history, no tool-call record, no provider state. Resuming a worker "with its accumulated context" therefore requires persisting history that is currently discarded when the pool thread finishes. #392 is materially larger than its own estimate.

Identity half-exists, twice. Background spawns already carry a stable id and a mutex-guarded session-global registry (AgentJob / g_agent_jobs), but in memory only, so it dies with the process. Separately, cards.zig:subagentId produces sa-<ordinal>-<hash> for inspect links. Two schemes naming one concept; unifying them is a prerequisite, or the registry keys on one and the persisted artifacts on the other.

The arc collides with #441. That issue excludes subagents from the append-only transcript on the grounds their history is never persisted by design, while #392/#417 require exactly that history. Both defaults are right for their own case, so the resolution is opt-in retention per spawn (retained: true): #441 keeps its default and gains one documented exception, unretained workers keep today's behaviour byte for byte, and the model gets a real cost signal at the moment it knows whether a follow-up is likely.

What the merged design settles

Open questions are listed rather than silently decided: retention default for workflow workers, a tighter worker transcript cap given fan-out, and whether a tombstoned child's transcript is swept immediately or with the session.

The two issues describe one mechanism from two directions (addressability
vs resumption) and are not separately implementable: resumption needs an
identity that outlives the spawn, and addressing needs somewhere for a
completed child's state to live. Built apart they would produce two id
schemes, two registries and two message paths.

Grounding the merge against the source turned up three things worth
recording:

- #392's premise is false. It assumes the worker transcript already
  persists under .graff/subagents/, making resume "plumbing, not new
  state". writeSubagentDetail persists a final report plus metadata as
  markdown, with no message history, no tool-call record and no provider
  state. Worker-history persistence is the first slice, not a detail.
- Identity partly exists already: background spawns carry a stable id and
  a mutex-guarded registry, but in memory only, so it dies with the
  process. And there are already TWO id schemes (cards.zig's sa-<ord>-<hash>
  and the background u32) that must be unified first or the registry keys
  on one and the artifacts on the other.
- The arc collides with #441, which excludes subagents from the
  append-only transcript by design while #392/#417 require exactly that
  history. Resolved as opt-in retention per spawn, so #441 keeps its
  default and gains one documented exception, and unretained workers keep
  today's behaviour byte for byte.

Steering unifies to one delivery call with a trigger flag rather than
Codex's two tools, keeping the queued-never-awaited invariant that stops
mutual sends between busy agents deadlocking.

Co-Authored-By: Codegraff <blackfloofie@codegraff.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant