Skip to content

Fork: settle the running subagent chips a fork copies - #1045

Merged
zeronsh[bot] merged 4 commits into
zeronsh:mainfrom
alexandre-vl:subagents/fork-settles-chips
Oct 26, 2026
Merged

zeronsh[bot] merged 4 commits into
zeronsh:mainfrom
alexandre-vl:subagents/fork-settles-chips

Conversation

@alexandre-vl

@alexandre-vl alexandre-vl commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1001.

Forking a chat while one of its subagents ran left that subagent spinning in the fork forever. The fork copies the source's entries as they are, so the spawn chip came across running, and no run in the fork will ever settle it. The copy now settles it failed, as the engine already does for a running chip it can no longer follow: at run end (crates/engine/src/sessions.rs:4824), and in the restart sweep, which settles running chips in completed parent turns too (mark_abandoned_streams, crates/engine/src/doc_host.rs:949-973). The source keeps its own chip and its real outcome.

The fork's session card. On v0.2.121, an hour after the fork, Subagents still lists Sleep for 70 seconds as running. On this branch it shows 1 finished.

What changes

  • Fork. ForkSideChat already resolved the copied Input parts. It now also settles each copied tool part whose subagent is Running (crates/engine/src/rpc.rs:2753-2763). The subagentRef, settled chips and the source are left alone.

Testing

  • macOS 27.0, rustc 1.99.0: cargo test --locked -p zeron-engine --lib --test side_chats --test restart_resume --test e2e gives 630 passed (5 ignored), 7, 11 (1 ignored) and 29 (2 ignored).
  • CI now runs side_chats: it is named right after restart_resume in the engine's list of integration binaries (scripts/ci/test-core.sh:27), which didn't include it. Providers: a switch to turn native subagents off #1046 adds the same change, so the two merge in either order.
  • a_fork_settles_the_running_subagent_chips_it_copies (crates/engine/tests/side_chats.rs:405, next to the six other ForkSideChat tests) forks one entry holding a running chip, a done chip and an open question. The fork gets (main--sub--running, failed), (main--sub--done, done) and an answered question; the source keeps running, done and its open question. It fails at side_chats.rs:510 with the fix reverted (left: ([(Some("main--sub--running"), Some(Running)), …], [true])), with a copy that drops the ref (left: ([(None, Some(Failed)), …], [true])), and with the question left open (left: (…, [false])).
  • Live, Claude Code 2.1.310 with Haiku, on headless engines with their own data dirs. A chat starts one background Agent whose prompt asks for sleep 90 in the foreground, ends its turn, and is forked while that subagent still runs: the source's chip read running just before the fork in both runs. Claude Code's Bash tool refused the sleep 90 as a standalone sleep, so the subagent ended on its own, after the fork.
    • v0.2.122: the fork's chip read running right after the fork and still did 146 s later, while the source's had gone done.
    • This branch: the fork's chip read failed, its subagentRef intact, from the first read after ForkSideChat returned to the last, 149 s later. The source's went from running to done. The subagent doc behind that ref still serves the subagent's transcript, which is what the red chip opens when the transcript blob isn't there (crates/ui/src/shell.rs:4624).
  • Rebased onto v0.2.124 (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: forward a foreground subagent's text and thinking #1042, 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, Providers: a switch to turn native subagents off #1046), it passes every suite above again, plus the rest of CI's selection, sync's mock-server tests, zeron-mcp and the UI's settings:: tests, each executable checked to be built from that merge. The one failure, preview's backgrounded_scrubbed_terminal_and_out_of_tree_servers_stay_attributed, fails the same way on v0.2.124 alone, on this Mac.
    • Live on that merged build, the same fork: its chip read failed in all 30 samples over 149 s, and the source's went from running to done.
  • Not run: Windows and Linux, the full app by hand.

Known limits

Screenshots

Offscreen renders of the production Shell (Window::render_to_image), attached to each engine; docs/media/fork-settles-subagents/README.md says how they were made. They come from an earlier run than the one under Testing: v0.2.121, with a subagent running sleep 70. The media are in their own commit, 54e5490f, if you'd rather drop them before merging.

v0.2.121, an hour after the fork This branch
The fork's chip: Agent Sleep for 70 seconds with a running indicator The fork's chip: Agent Sleep 70 seconds in red, no running indicator

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

alexandre-vl and others added 4 commits October 26, 2026 21:37
A fork copies the source's entries as they are, so a subagent still
running there kept a `running` chip in the fork. No run in the fork ever
settles it: the chip and its lanes-card row spun forever (zeronsh#1001).

The copy now settles it `failed`, like run end and the restart sweep
do. The chip keeps its ref, so it still opens the subagent's transcript.
The source keeps its own.

CI now runs the engine's `side_chats` tests, where the fork tests live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: zeronsh[bot] <346184242+zeronsh[bot]@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: zeronsh[bot] <346184242+zeronsh[bot]@users.noreply.github.com>
@zeronsh
zeronsh Bot force-pushed the subagents/fork-settles-chips branch from 3890c01 to de0cb10 Compare October 26, 2026 21:52

@zeronsh zeronsh Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security audit clean: engine-only change to ForkSideChat (settles copied running spawn chips failed, matching run end and the restart sweep), one test, docs, media PNGs (no trailing data), and side_chats added to the CI test list. Rebased onto main; locally on Linux: side_chats 7/7, restart_resume 11, e2e 29 pass; the new test fails with the fix reverted; no new clippy warnings in touched files. Reflowed the docs/mcp.md paragraph. Thanks!

@zeronsh
zeronsh Bot merged commit ae1ec6a into zeronsh:main Oct 26, 2026
20 checks passed
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.

[Bug]: Forking a chat copies running subagent chips, which spin forever in the fork

2 participants