acpmux: a move that stops a running turn continues it where the chat lands
Leo, 2026-11-01, on the Cloud differentiators list (manaflow-ai/cmuxterm-hq#5846, item 1: "Move a live chat between laptop and Cloud, both ways, mid-turn"): "those all seem good".
What changes
Moving a chat whose turn is running (Move to Cloud, Bring Back Local, acpmux session move --interrupt, any _acpmux/transfer_begin {interrupt: true}) used to stop the turn and leave it stopped: the chat landed idle on the other machine and someone had to type "continue".
Now transfer_begin logs the cut turn's continuation before it stops the turn. This is the same continuation a daemon restart queues (restart_resume.rs), with reason: "moved":
- The bundle's queue carries it at its head, so on the target it runs as soon as
transfer_finishlands the chat, ahead of what waited behind the turn. The turn goes on there. - A move that does not happen (
transfer_abort, a stalled client's abort, or a begin that fails after the Stop) puts it back in the queue here, at its head, and runs it (queue_carried). transfer_begin's answer and itstransfer_outrecord name it (continues).- Its text says the chat moved and that processes it started (dev servers, watchers) did not come with it. It quotes the cut prompt and steers and lists unfinished tool calls, as the restart continuation does.
- It is logged before the Stop because a Stop leaves a turn no continuation. The Stop then goes through
cancel_turn_for_replacement, so a Stop during compaction does not withdraw it.
Because it is an ordinary queued record, there is no new wire and no new capability:
- An older target restores and runs it in log order. Only the head placement needs this build, through
Cut::queuedinqueue.rsrestore_queue. autoResumeDelaysMs: []turns it off, as it does every continuation, and so does the attempt cap.
Scope
This is acpmux only. The app still never passes --interrupt (CloudMoveCLI), so a running chat's Move to Cloud is refused today. Passing it, with the folder sync landing after the freeze, is the next PR. That one is coordinated with the seeding helper (git-seed-v1).
Does not touch #28859's files beyond transfer_out.rs's begin. There it adds lines before the bundle is made and does not change the approval gate.
Tests
tests/hub_integration/transfer.rs:a_moved_chat_keeps_...: the target runs history, then the moved continuation (quotinguntil-cancel,auto_resume_scheduled {reason: moved, promptId: p-turn},begin.continues == p-turn~resume-1), then the queue once.a_chat_being_moved_..._aborted_move_gives_it_back: after the abort, the continuation runs here before the queue.
- The Cloud and Bring Back journeys (
cmux-tui/tests/cloud_move_journey.rs,bring_back_journey.rs) already move with--interruptand count by text, so they still hold.
Results: see the cmux-ci receipts below.
Changelog
none
š¤ Generated with Claude Code
Agent session: agent session
Summary by cubic
Moves that stop a running turn (Move to Cloud, Bring Back Local, acpmux session move --interrupt) no longer leave the chat idle: the turn's continuation is queued before the stop, so it runs where the chat lands, or back here if the move doesn't happen. cmux link agent move --sync copies the folder's last changes once the chat is frozen, so the continued turn finds its edits on the target.
- The continuation is an ordinary
queuedrecord withreason: "moved"at the queue's head, and the move also logs aqueue_ordernaming it first so it stays ahead even where a guarded receive drops prompt provenance. autoResumeDelaysMs: []and the attempt cap turn it off, as they do every continuation.- A failed sync, or a pull that conflicts, gives the chat back; a conflict pull names the files.
- The mac app's Move to Cloud and Bring Back Local now pass
--interruptand--sync, so a running chat moves mid-turn instead of being refused.