docs: merge the #417 and #392 subagent-steering designs into one - #450
Merged
Conversation
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>
This was referenced Aug 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:writeSubagentDetailwrites 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:subagentIdproducessa-<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
sa-<ordinal>-<hash>, already stable across runs and already in persisted artifacts. The backgroundu32demotes to an internal index. Retained, addressable subagents with parent-child steer messaging #417's names become aliases, never identity, preserving its own harness-assigned-sender rule.triggerflag rather than Codex's two tools, so the expensive case is visibly the exception. Delivery stays queued and never awaited, which is the invariant that stops mutual sends between two busy agents deadlocking, and which the existing admission counter's comment already documents the hard way.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.