Agent pane: a Cloud chat's prompt names the hand-off turn the app opened for it
Agent pane: a prompt that starts a turn in a chat on a Cloud machine goes under the hand-off turn the app opened for it (handoff-<turn>-<id>), so acpmux on the machine reports that turn and the owner hears when it runs, needs them, finishes or fails.
Leo, 2026-10-28: "whatever's convenient for cloud, like that can be productionized, operationalized, we ought to just put out there"
Leo, 2026-10-28: "you can just say ... where should this chat run and stuff, and that's just about it ... it's somewhere in the cloud, and then it gets managed for you."
What changes
cloudHandoffTurn.ts(new): the page asks the appcloud.handoffTurn {sessionId}and reads{turn}. It waits at most 2.5 s and never rejects.namesHandoffTurnmatches a wholehandoff-<1ā15 digits, no leading 0>-prefix, the way acpmux'snamed_turnreads one.direct.tssendNow: once the chat is known, a prompt that starts a turn asks for its turn and goes ashandoff-<turn>-<id>. The row, delivery and gesture ticket all key on that id from then on. Nothing is asked for:- a steer;
- a prompt behind a running turn or the queue;
- a Retry whose id already names a turn (it keeps its id, so acpmux dedupes it).
- One ask per chat at a time. A second send while an ask is out waits for it and goes behind it under its own id. If the selected chat changes during the ask, the prompt goes back to its sender and nothing is drawn or sent.
App.tsx: the page asks only when the app's ready reply sayscloudHandoffs: trueand the chat runs on a Cloud machine (cloudMachineID). An app without the Swift side never says so, so on its own this PR changes nothing.
The app side (cloud.handoffTurn, which makes the session's hand-off at its first turn and begins each later one, plus the gesture pick that reads a labelled id as the same prompt) is #26919 (Swift, held), stacked on #26716 (the hand-off watcher).
Known limits
- If the app answers after the 2.5 s wait, the prompt has already gone under its own id and that turn is not reported. The turn the app opened stays
startingin the store, and the chat's next prompt that starts a turn names it, so nothing gets stuck. - Prompts queued or steered into a running turn start no turn of their own and are not reported separately.
- The first bubble of a Cloud chat's turn draws after the app's answer, at most 2.5 s later.
Tests
cloudHandoffTurn.test.ts: turn parsing, the id, the timeout, the ask gate, the whole-prefix match.test/agent-pane-cloud-handoff-turn.test.ts(a fake daemon recordssession/prompt):- the prompt goes as
handoff-3-p-1; - with no turn it goes under its own id;
- a steer, a Retry's named id, and a page with no ask all ask nothing;
- a non-turn
handoff-ā¦id still asks; - two quick sends make one ask, in order;
- a chat change during the ask sends and draws nothing.
- the prompt goes as
- cmux-ci (Linux pool): those tests,
agent-pane-not-sent-retryandagent-pane-blank-promptpass, andbun run checkis green.
Risk: low for local chats, because the gate is false unless the app opts in. For Cloud chats, the first send of each turn waits up to 2.5 s.
Agent session: agent session
š¤ Generated with Claude Code