Repository navigation
Fix cmux agent hibernate for live Claude sessions - #18839
Draft
aryeh-stark wants to merge 1 commit into
Draft
aryeh-stark wants to merge 1 commit into
aryeh-stark wants to merge 1 commit into
Conversation
Manual hibernation refused every live Claude Code session as process_scope_unsafe, and reported a hibernation that succeeded as teardown_refused. - Scope hook-backed agents in the process-census index too: manual hibernation, memory-pressure reclaim and the pre-signal revalidation read it, and it never supplied hookProcessScopeProvider (manaflow-ai#17306 fixed only SharedLiveAgentIndexLoader). - Register cmux's detached `hooks claude inbox-wait` helper and terminate it with its agent, exempt only from the shared-TTY rule, carrying that evidence through scope, revalidation, signaling and exit observation. Read e_tdev NODEV as no TTY. - Let a manual teardown that commits wait for its exit observation and report the pane's settled phase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Contributor
|
All contributors have signed the CLA ✍️ ✅ |
Author
|
I have read the CLA Document v2.2 and I hereby sign the CLA |
This branch has not been deployed
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
cmux agent hibernate(#15308) couldn't hibernate a live Claude Code session. On 0.65.0, every request for an idle, off-screen, restorable Claude was refusedprocess_scope_unsafe, even a bareclaudewith only synchronous cmux hooks. With that fixed, the normal wrappedclaudewas still refused. After that, a hibernation that worked was reported asteardown_refused. Three bugs, all on this path; after this change the command hibernates both launches andcmux agent wakebrings Claude back.RestorableAgentSessionIndex.loadIncludingProcessDetectedSnapshotsbacks manual hibernation, memory-pressure reclaim and every teardown's pre-signal revalidation, but it callsloadwithouthookProcessScopeProvider. A live hook record falls back tocontainsUnrelatedProcess: true. Fix Agent Hibernation never selecting live Claude Code sessions #17306 added the provider toSharedLiveAgentIndexLoaderonly. Both loaders now shareSharedLiveAgentIndexLoader.hookProcessScopeProvider(processSnapshot:processArgumentsProvider:).asyncRewakehookcmux hooks claude inbox-waitdetached: a child of the agent leading its own session and process group, with no controlling terminal.agentHibernationProcessScope, signaling and exit observation all require one TTY.CmuxAgentHelperProcessnow registers that argv. A process counts as a registered helper only if it is a direct child of the agent, runs the registered argv withCMUX_*env for this panel, has no controlling terminal, is alone in a process group it leads, and has no children. It stays in the termination set and is exempt only from the TTY rule. That evidence (cmuxHelperProcessIDs,ScopedProcessTermination.isCmuxHelper) is carried through the index entry and record,teardownIsStillSafe(must be unchanged), the final signal check (still detached, still the registered argv; its own group gets SIGTERM), and the refreshed exit epoch on the escalation and retry paths.e_tdev == NODEVnow reads as no TTY, asKernelPortProcessTablealready treats it, instead of a device every detached process shares.commitConfirmedTeardownreturnsfalsefor.committedAwaitingExit, the normal outcome (SIGTERM sent, exit observed asynchronously), andhibernateNowmaps anyfalsetoteardown_refused. A.manualteardown that commits now waits for its exit observation and succeeds only once the pane is.hibernated. Routine and memory-pressure batches are unchanged.Still refused: a user's detached background job, an unregistered cmux hook (
auto-name), the helper argv scoped to another surface, inside the agent's process group or with a child, and any change of process identity, group or terminal between scope and signal.Testing
On a tagged Debug build of v0.65.0 (
dda24fbd2) plus this change:./scripts/test-unit.sh testover 15 suites (ClaudeHookSessionLivenessTests,AgentHibernationProcessSignalBoundaryTests,AgentHibernationProcessSnapshotCoordinatorTests,CmuxTopProcessTreeTests,AgentHibernationProcessTerminationTests,AgentHibernationTerminationFailureTests,AgentHibernationBackgroundWorkTests,AgentHibernationManualRequestTests,SharedLiveAgentIndexAgentLivenessTests,AgentQuitTerminationCoordinatorTests,AgentHibernationPlannerSwiftTests,CmuxTopSnapshotScopeTests,AgentResumeLivenessTests,CompletedRestoredAgentGenerationTests,AgentHibernationTests): 170 tests passed.NODEVis no TTY.process_scope_unsafe. With it, each answeredhibernated: true, thenwoke: true, with Claude's prompt back on screen in 2 to 7 s, overagent.hibernate/agent.wakeon the socket and throughcmux agent-hibernation hibernate|wake:claudewith only synchronous cmux hooks;claude. Its teardown terminated Claude, the spool forwarder, two MCP servers and theinbox-waithelper, and none survived.Not yet run on this branch's base (main
cd85f00): building and testing it is in progress, so this PR is a draft. Main's ghostty and bonsplit pins differ from v0.65.0, andRestorableAgentSession.swiftis the only one of these files main changed; the patch applies to it without conflict. Every other file that uses the changed types is identical to v0.65.0.Changelog
Fixed:
cmux agent hibernatehibernates an idle Claude Code session instead of refusing it asprocess_scope_unsafe, and no longer reports a completed hibernation asteardown_refusedProof
CLI and socket only; terminal output to follow from the main-based tagged build.
Checklist
Seen while verifying, not changed here
caffeinate -i -t 300child with noCMUX_*env, so a manual hibernation in that window answersteardown_refused(the signal-time scope check, or a revalidation race when it exits). It succeeds once Claude stops it.AgentResumeLaunchGuardclaim isn't released when its agent is hibernated, only afterclaimTTL.--setting-sources '') loses it, so the resume command fails.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Fixes
cmux agent hibernatefor live Claude Code sessions: previously every request for an idle, off-screen Claude was refused withprocess_scope_unsafe, and a hibernation that succeeded was reported asteardown_refused. After this change both bare and wrapped launches hibernate, andcmux agent wakebrings Claude back.Bug Fixes
asyncRewakehook (cmux hooks claude inbox-wait) runs detached with no controlling terminal, breaking the shared-TTY rule; it's now registered as a helper and terminated with its agent, exempt only from the TTY rule.e_tdev == NODEVnow reads as no terminal.teardown_refused; it now waits for the exit observation and succeeds only once the pane is hibernated. Routine and memory-pressure reclaims are unchanged.Still refused: a user's detached background job, an unregistered cmux hook, the helper argv scoped to another surface or inside the agent's process group, helpers with children, and any process identity, group, or terminal change between scope and signal.
Known limits, not changed here: a
caffeinatechild lingers ~15–20 s after a Claude turn so hibernation in that window still answersteardown_refused; waking within 60 s of an earlier wake is refused by the resume guard's claim TTL; a launch command captured with an empty argument loses it on resume.Written for commit bf83891. Summary will update on new commits.