worktree_session is model-callable, so it runs mid-turn. ctx.switchSession cannot be called from inside a tool: it tears down the agent that is awaiting the tool result, and ctx.waitForIdle() would deadlock on our own execution.
The prior art avoids this by registering no LLM tool at all. We cannot — the tool is the whole point for autonomous runs.
Shape worth trying
Arm in the tool, switch at settle. The SDK has the hook already:
agent_settled — "ctx.isIdle() is true here unless another extension started a new run."
tool returns { outcome: "…" } → agent stops issuing calls
→ pi.on("agent_settled") → ctx.switchSession(prepared, {
withSession: ctx => ctx.sendUserMessage(continuation)
})
This is the existing armed-handoff pattern with the transport swapped out. The pending-handoff refusal that blocks every later tool call still applies, and for the same reason: once the move is armed, nothing else should touch the old checkout.
buildContinuationMessage survives unchanged and finally has a first-class delivery mechanism — sendUserMessage on the replacement context, rather than a positional argument on a relaunched CLI.
The outcome contract
relaunch-scheduled is now a lie about the mechanism even when it is true about the consequence. Either rename it (switch-armed?) or redefine it as transport-agnostic — the agent's required behaviour is identical either way: stop issuing tool calls, the task continues in the replacement.
manual-restart should become unreachable on this path. path-target survives only as an explicit execution: "paths" request, no longer as a fallback for a missing multiplexer.
Headless is the prize here. modes/print-mode.js:71 wires switchSession, so a -p run can hop for the first time — but confirm that a print-mode agent loop actually survives replacement before promising it. If it does not, paths remains the honest default there and the tool must keep saying so.
Constraints
The rule that a scheduled hand-off is the only path that requests shutdown is specified in docs/specs/2026-08-02-unified-worktree-transitions.md and covered by the suite. Under an in-process switch nothing requests shutdown at all, so that invariant needs restating rather than deleting.
Overlaps #10 — the create/enter inlining that issue wants extracted is the code this one rewrites.
worktree_sessionis model-callable, so it runs mid-turn.ctx.switchSessioncannot be called from inside a tool: it tears down the agent that is awaiting the tool result, andctx.waitForIdle()would deadlock on our own execution.The prior art avoids this by registering no LLM tool at all. We cannot — the tool is the whole point for autonomous runs.
Shape worth trying
Arm in the tool, switch at settle. The SDK has the hook already:
This is the existing armed-handoff pattern with the transport swapped out. The pending-handoff refusal that blocks every later tool call still applies, and for the same reason: once the move is armed, nothing else should touch the old checkout.
buildContinuationMessagesurvives unchanged and finally has a first-class delivery mechanism —sendUserMessageon the replacement context, rather than a positional argument on a relaunched CLI.The outcome contract
relaunch-scheduledis now a lie about the mechanism even when it is true about the consequence. Either rename it (switch-armed?) or redefine it as transport-agnostic — the agent's required behaviour is identical either way: stop issuing tool calls, the task continues in the replacement.manual-restartshould become unreachable on this path.path-targetsurvives only as an explicitexecution: "paths"request, no longer as a fallback for a missing multiplexer.Headless is the prize here.
modes/print-mode.js:71wiresswitchSession, so a-prun can hop for the first time — but confirm that a print-mode agent loop actually survives replacement before promising it. If it does not,pathsremains the honest default there and the tool must keep saying so.Constraints
The rule that a scheduled hand-off is the only path that requests shutdown is specified in
docs/specs/2026-08-02-unified-worktree-transitions.mdand covered by the suite. Under an in-process switch nothing requests shutdown at all, so that invariant needs restating rather than deleting.Overlaps #10 — the create/enter inlining that issue wants extracted is the code this one rewrites.