Resume a local Copilot loop instead of relaunching it under the same name - #248
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tqv8Rx8SGsLCjJQYCUjiFr
…name A user's dials.log showed loops resumed by the daemon after every restart and nothing else — no duplicate visible, because the launch that makes one never wrote a line. Copilot has no hook to bank its resume ID, and only the remote path banked it from outside; locally the daemon rediscovered the session directory on every ensure while the app's open path read only the pointer. Any local Copilot loop whose zmx session was gone (a reboot, or a turn-based loop, which the daemon never ensures) was relaunched by the pane as `copilot --name graphcode-<id>` from its goal: a second Copilot session for one loop, and the daemon's next resume picked the newest directory, orphaning the original. - The daemon banks a Copilot session's directory name locally, the twin of the remote bank fragment: after a resume that took, and after a fresh launch once the new directory appears. - The pane makes the same choice from the same lookup (`ZmxSessionLauncher.resumableSessionID`), banking a discovered ID before its script reads it. - The pane's liveness check is the daemon's husk-aware one. An agent that died leaves its shell at a prompt, which answered `zmx get`; the pane joined the corpse. The husk is killed and the launch proceeds as if the session were gone, so the resume-or-fresh verdict stays measurable. - Every local agent launch goes through the one script and logs its branch, so `open fresh` appears in the dial log where it used to be silent. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tqv8Rx8SGsLCjJQYCUjiFr
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.
Summary
A user's
dials.logshowed loops resumed by the daemon after every restart and nothing else. No duplicate was visible in it because the launch that makes one never wrote a line.Copilot has no hook to bank its resume id, and only the remote path banked it from outside. Locally the daemon rediscovered the session directory on every ensure, while the app's open path read only the banked pointer. So any local Copilot loop whose zmx session was gone (a reboot, or a turn-based loop, which the daemon never ensures) was relaunched by the pane as
copilot --name graphcode-<id>from its goal: a second Copilot session for one loop. The daemon's next resume then picked the newest directory and orphaned the original.remoteIDBankFragment: after a resume that took, and after a fresh launch once the new directory appears. Samebank copilot-iddial-log line as remote.ZmxSessionLauncher.resumableSessionID), banking a discovered id before its script reads it.zmx get, so the pane joined the corpse. The pane now uses the daemon'sended=-aware check, kills the husk, and proceeds as if the session were gone, so the resume-or-fresh verdict stays measurable.open freshandopen husk-killedappear in the dial log where the fresh launch used to be silent. The script runs under/bin/zshbecause the alive check uses$'\t'.Not in this PR, noted by a peer loop on the board: the daemon's alive check swallows
zmx lserrors, so a transient zmx failure reads as "missing" andzmx runtypes a second launch into a live session.Verification
xcodebuild testin the worktree: 1479 passed, 0 failed (5 new or updated tests inLocalSessionResumeTestsandDialLogTests).swiftlint lint: 0 errors.swift format lint --strict: clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01Tqv8Rx8SGsLCjJQYCUjiFr