Repository navigation
Claude subagents: forward a foreground subagent's text and thinking - #1042
Merged
zeronsh[bot] merged 3 commits intoOct 26, 2026
Merged
Conversation
This was referenced Oct 25, 2026
alexandre-vl
marked this pull request as ready for review
October 25, 2026 21:04
7 of 10 tasks
zeronsh
Bot
force-pushed
the
subagents/forward-subagent-text
branch
from
October 26, 2026 19:23
20cddd4 to
f10c848
Compare
The ● N badge counted every tagged stream the engine opened a sink for, while the lanes card lists only the chat's spawn chips. Claude Code tags a forked skill's traffic with its Skill call's id, the agents a subagent starts with their own Agent call ids, and a skill passed as `/<name>` with `forked-command-<name>`. None of them is a spawn chip of the chat, so the badge could read 3 over an empty card (zeronsh#999). A sink (its own doc, one unit on the badge) now opens only for a spawn chip of the chat (`is_chat_spawn`). Traffic tagged with any other id stays in the journal. A forked skill is the chat's own subagent, though. The Claude adapter sets each Skill call aside until its task starts, which comes ahead of all the fork's traffic, and re-decodes it then as a spawn named after the skill (`Agent: /review`). Its traffic then has a card and a tab to feed. An inline skill starts no task, and its result drops it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude Code leaves the text and thinking blocks of a foreground subagent (or a forked skill) out of the stream unless asked, so its tab showed tool calls only (zeronsh#1000). Runs now set CLAUDE_CODE_FORWARD_SUBAGENT_TEXT=1, which "enables the same behavior" as `--forward-subagent-text` (https://code.claude.com/docs/en/cli-reference). The variable rather than the flag: a CLI older than 2.1.211 ignores it, but refuses an unknown flag. The CLI then forwards subagents "at every nesting depth" (https://code.claude.com/docs/en/headless). The spawn gate keeps the agents a subagent starts in the journal, instead of badging the chat with docs no card lists (zeronsh#999). The adapter already emitted tagged text blocks. Tagged thinking blocks now become the subagent's reasoning, in block order. A background subagent sends them unasked, so its tab gains its reasoning too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zeronsh
Bot
force-pushed
the
subagents/forward-subagent-text
branch
from
October 26, 2026 20:54
f10c848 to
e4b6fd7
Compare
Contributor
There was a problem hiding this comment.
Security audit clean: Rust and test fixtures only, plus PNG demo media (verified real PNGs). No dependency, build, CI or network changes; the one runtime change sets CLAUDE_CODE_FORWARD_SUBAGENT_TEXT=1 on the claude child. Reviewed the spawn gate (#1041's commit, included here) and the tagged-thinking fold; both look correct. Rebased onto main (98abb77). Locally: harness lib 446, claude 36, codex 45, doc 151, proto 89, engine sessions 22, all passing; clippy and rustfmt add nothing new.
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 #1000.
A foreground subagent's tab showed its tool calls and nothing else. Unless asked, Claude Code leaves the text and thinking blocks of a foreground subagent, or of a forked skill, out of the stream. Runs now ask for them, and the adapter folds the thinking blocks they bring.
It needs #1041's spawn gate. Once asked, the CLI forwards subagents "at every nesting depth" (Follow subagent messages). Without the gate, the agents a subagent starts would each open a doc no card lists, and the pill would climb again (
1→3in the A/B on #1000).What changes
build_commandsetsCLAUDE_CODE_FORWARD_SUBAGENT_TEXT=1(crates/harness/src/claude/mod.rs:349), which "enables the same behavior" as--forward-subagent-text(CLI reference). It's the variable rather than the flag because a CLI older than 2.1.211 ignores the variable, but exits on a flag it doesn't know. Aclaudestarted inside the run inherits the variable. Outside stream-json print mode the CLI ignores it "so that nested invocations keep working when it's set process-wide" (environment variables). A nested stream-jsonclaude, such as an Agent SDK script orclaude -p --output-format stream-json, forwards its own subagents' text too, which only adds tagged frames to its stream.thinkingblocks become the subagent's reasoning, in block order with its text and tool calls (crates/harness/src/claude/normalize.rs:728). A signature-only block is skipped, and each thought ends with a blank line, like text blocks. Text blocks were already folded, but they never arrived. A background subagent sends its thinking unasked (live-2.1.228-background-subagent.jsonl, lines 62 and 72), so its tab gains its reasoning too.Testing
cargo test --locked:-p zeron-harness --lib --test claude --test codexgives 447, 36 and 45 passed, 3 and 4 ignored as onmain.-p zeron-doc --liband the engine suites give the same counts as on Claude subagents: count and open only this chat's spawns #1041.runs_ask_the_cli_to_forward_subagent_textreads the variable off the built command. Without the line it fails withleft: None right: Some("1").subagent_assistant_blocks_emit_tagged_reasoning_text_and_callsfeeds a signature-only thinking block, two thoughts, a text block and a tool call, and expects exactly"Plan it.\n\n","Then list.\n\n", the text, the call. Folding the empty block, or keeping a thought's trailing space and no blank line, fails it.captured_live_forwarded_foreground_subagent_replays_in_orderreplays frames from Claude Code 2.1.310 run with the variable (live-2.1.310-foreground-subagent-forwarded.jsonl). The subagent's events come out as thinking, "The sky is blue.",echo hi, thinking, "The grass is green.", in that order; without the fold,["sky", "exec", "grass"]. The capture skips the main thread's 79 frames before itsAgentcall (28.6 KB, mostly partial deltas), which no assertion reads. One thought that named the account's connectors was reworded.captured_live_background_subagent_frames_replay_correctlynow also counts the background subagent's two thoughts (2.1.228 capture, lines 62 and 72). Without the fold:left: 0 right: 2.claudedriver andsessions.rs: no commit touches them between v0.2.121 and this branch's base.execexec, reasoning, "The grass is green."exec, "The grass is green."exec, reasoning, "The grass is green."Only this branch sets the variable, and its background run's journal holds each sentence once: the variable doubles nothing.
Agentcall in the same setup forwarded its thinking and text. So Claude: open each Workflow agent's live transcript #785, which replays Workflow agents from their transcript files, shows nothing twice./fanout's tab now has the skill's thinking and its reply. The agents it starts forward their text too, and it stays in the run journal (3 and 1 text deltas under their ids, no doc).c04e3749) after these runs, with no conflict. Merged there with the other five PRs of this series (Claude subagents: count and open only this chat's spawns #1041, Claude subagents: give a typed /skill's fork a chip and a tab #1043, Claude subagents: fill a typed fork's tab while the CLI holds it #1044, Fork: settle the running subagent chips a fork copies #1045, Providers: a switch to turn native subagents off #1046), it passes every suite above again, plus the rest of CI's selection, sync'smock-servertests,zeron-mcpand the UI'ssettings::tests, each executable checked to be built from that merge. The one failure, preview'sbackgrounded_scrubbed_terminal_and_out_of_tree_servers_stay_attributed, fails the same way on v0.2.124 alone, on this Mac.The sky is blue., theechocall,The grass is green.and two thoughts, and the pill matched the rows in all 14 samples.Known limits
stream_eventframes, none of them tagged.Screenshots
Offscreen renders of the production
Shell(Window::render_to_image), attached to each engine, with the subagent's tab open;docs/media/forward-subagent-text/README.mdsays how they were made. The media are in their own commit,20cddd40, if you'd rather drop them before merging.Full windows
Need help on this PR? Tag
@codesmith-botwith what you need.