Skip to content

feat(tool): arm the switch in the tool, perform it at agent_settled #20

Description

@neilwashere

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions