Agent pane: tagged asks at the end of a turn show as a next-step card
Leo: "but why not in cmux" (on a slow-command hook that had gone into his own agent tooling only).
An agent session sat in one turn for about 80 minutes: it ran about 40 shell commands in the foreground (worktree setup, loops of GitHub reads, long remote calls), and Claude Code moved each to the background only when its own timeout hit. This puts the fix in acpmux, so every cmux NEXT Claude chat gets it.
What changes
- Any foreground shell, after 60 s (
hub/auto_background.rs): when a Claude Code chat's own turn starts a Bash call withoutrun_in_background, the hub arms one timer for it. If the call is still in flight when it fires, acpmux sends Claude Code'sbackground_tasksfor that call, the same request Ctrl-B sends (process/background). Claude Code answers the call with "running in background", the turn goes on, and the shell is listed inprocess/listwith originauto_backgrounded. This covers commands no list can know (a person's own scripts).- Stop conditions: the timer ends when the call is no longer in flight (finished, or the turn ended), when Claude Code moved it, or when Claude Code refused. While the call still waits and nothing moved (a permission card, say), it asks again one interval later. Weak references only; one timer per call (
auto_background_armed, cleared as each ends). No per-token work: armed once per shell call. ACPMUX_AUTO_BACKGROUND_SECSin the daemon's environment sets the wait;0turns it off.- A subagent's shells are not timed (their updates are not the turn's own); a follow-up can extend it.
- The translator's
background_taskstakesauto: true, so what acpmux moves is not marked as the person's (user_backgroundedstays for Ctrl-B).
- Stop conditions: the timer ends when the call is no longer in flight (finished, or the turn ended), when Claude Code moved it, or when Claude Code refused. While the call still waits and nothing moved (a permission card, say), it asks again one interval later. Weak references only; one timer per call (
- Known-slow commands, before they start (
bg_hook.rs): the session plugin's existing PreToolUse Bash hook (__bg-hook) now also turns away a known-slow command run in the foreground:cargo build/test/clippy/nextest/bench,swift build/test,xcodebuild,gh run watch,gh pr checks --watch, dev servers (npm run dev,pnpm dev,next dev,vite dev, ...),tail -f,watch. The deny names the background call to send instead:bg_startwhen the chat has the acpmux server (so it outlives hibernation), elserun_in_background: true. The same call again runs as asked (the hook's existing turn-away-once record), as does a command with a# fg-okcomment or one that backgrounds itself (&,nohup,setsid). Help and version flags (--help,xcodebuild -list) pass.- The hook reads commands with
host_load::for_each_command, factored out ofclassify_command(the same loose split, now also pasttimeout Nandsudo), so there is one command reader.
- The hook reads commands with
docs/background-processes.mdsays both.
Codex chats: nothing new, and none needed. Codex's shell tool has no run_in_background flag, but its unified exec hands a long command back to the agent as a running background terminal after a short wait, so a Codex turn never blocks on one; acpmux already lists those (codex_app_server/background.rs). process/background stays refused for Codex chats, and the hook is Claude Code's plugin only.
Tests
bg_hook: known-slow vs quick commands (wrappers,bash -lc, help flags,# fg-ok,&,nohup), the deny with and withoutbg_start, quick commands pass.hub::auto_background: which updates arm it (a call or the update that brings an early-named call's command; not background, not finished, not other kinds), the env knob.hub_integrationprocesses: a foreground shell with no Ctrl-B goes to the background after the wait (background_taskswith itstool_use_id, turn ends, listedauto_backgrounded); turned off, it stays until Ctrl-B (user_backgrounded).
Risk: a behaviour change for every Claude chat: a foreground command longer than a minute now returns to the agent as a background task instead of its output; the agent is told when it ends and reads its output from the task. Turned off with ACPMUX_AUTO_BACKGROUND_SECS=0.
Agent session: agent session
๐ค Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith ยท Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Finished turns whose answer ends on a tagged ask โ one [taste], [outward], [irreversible], [physical], or [for you] question, optionally with its answer list โ now draw as a next-step card under the answer: the question, a muted detail line, and the answers as buttons (or Yes and Not now for a yes/no question), the first carrying โโฉ. Clicking a button sends that answer as the next prompt; once a prompt follows the turn, the card folds to the question and the answer in grey.
- The card appears only for a single clear tagged question in a finished turn's answer; ordinary prose, fenced or quoted text, running or stopped turns, and a follow-up from another agent keep the ask in the prose.
- Read-only panes (View Only) draw the question and answer without buttons; the recap card steps aside for these asks.
- โโฉ sends the first answer through the composer's empty-prompt path, so the composer's own rules hold โ never in the Quick Composer, shell mode, a running turn, or with a draft, and never while a question or permission card waits; the keycap shows only where the key is wired.
parity-mac.mdnotes the card is missing on the phone; the phone shows the tagged line as prose.