Agent pane: tagged asks at the end of a turn show as a next-step card

Merged
TE
3d ago
+918-2

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 without run_in_background, the hub arms one timer for it. If the call is still in flight when it fires, acpmux sends Claude Code's background_tasks for 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 in process/list with origin auto_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_SECS in the daemon's environment sets the wait; 0 turns 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_tasks takes auto: true, so what acpmux moves is not marked as the person's (user_backgrounded stays for Ctrl-B).
  • 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_start when the chat has the acpmux server (so it outlives hibernation), else run_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-ok comment 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 of classify_command (the same loose split, now also past timeout N and sudo), so there is one command reader.
  • docs/background-processes.md says 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 without bg_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_integration processes: a foreground shell with no Ctrl-B goes to the background after the wait (background_tasks with its tool_use_id, turn ends, listed auto_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
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.md notes the card is missing on the phone; the phone shows the tagged line as prose.