acpmux: a background task tells its chat when it ends; bg_* results lead with a summary line
Merged
TE
2d ago+526+526+012345678901234567890123456789-19-19-01234567890123456789
Leo's words (2026-11-03): "hmm claude code desktop's summarization of tool calls/parsing of them seem kinda good? we should bea bel to do that AND have condensed tools that are callable in acpmux/cmux-next..."
What
The acpmux MCP server's background-task tools become condensed tools, and a background task wakes its chat when it ends.
Contract (every condensed tool): an optional description argument (a few words: what the call is for; the transcript titles the row with it), and a result whose first text line is a one-line outcome, also returned as structuredContent.summary, with structuredContent.status = ok | failed | running.
bg_starttakesdescription(kept with the task;bg_list,bg_outputand the end message name the task by it) andnotify.- With
notify, when the task exits, is stopped, is killed or is lost, the daemon sends ONE message into that chat: a tool notice fromacpmuxtitled with the summary line (Background command finished: <description or command> (exit 0)), with the task id, its command and its last 20 lines of output. It is never steered into a running turn; it waits behind it, like a lane report. notifydefaults to true in the MCP tool (false at the raw_acpmux/bg/startRPC). The tool is the agent-facing path, and the PreToolUse hook sends Claude'srun_in_backgroundshells there. Those shells already tell the agent when they finish, so with the default on, routing them to the daemon loses nothing. An agent that wants silence passesnotify: false.- Every
bg_*result's first line is the summary:bg_startgivesrunning;bg_output,bg_stopand each listed task giverunning/ok/failedby state and exit code (okonly for exit 0);bg_listgives a count (3 background tasks: 1 running, 1 ok, 1 failed),runningwhile any task runs, elsefailedif any failed.
How (no polling)
hub/bg_notify.rs: for a notify task the daemon starts a thread that blocks inflockon the runner's liveness lock. The runner holds that lock until it has written its exit record, and the kernel frees it if the runner dies (lost). The thread then hands off to the runtime, which sends the notice.- Exactly once: the prompt id is
bg-done-<task>, sent withresend, so a second send (for example, a crash between the send and the mark) is answered from the chat's log and never runs again. On acceptance,<task>.notifiedis written next to the record. At startup the daemon (bg_notify_resume) watches only notify tasks with no mark, and sends at once for a task that ended while no daemon ran. - No message goes to a stopped, closing or purged chat, or from a daemon that is shutting down, or for a record of another folder generation. A watcher holds only a
Weakhub. description/notifyare stored in the runner's record (bg_run::Spec/Record, serde-defaulted, so older records still read).
Tests
hub_integration::bg_tasks::a_task_with_notify_tells_its_chat_once_when_it_ends: one notice on exit, with the summary line, exit code and the last 20 lines; none fornotify: false; thesummary/statusfields.hub_integration::bg_tasks::a_task_end_is_sent_once_across_a_restart: an end that is already sent is not sent again by the next daemon, and an end that came while no daemon ran is sent once by the next one.- Unit:
bg_run::tests::a_tasks_outcome_is_one_line_and_a_status,acpmux_mcp_bg::tests::a_lists_outcome_counts_its_tasks,hub::bg_notify::tests::a_notice_body_carries_the_last_lines.
Observed / Not run
- Ran at head
732c85c287a43afe88228c2b77c347e79f568d00on the fleet (fast-checks run 41601847615):cargo test -p acpmux --test hub_integration bg_taskspassed 13/13, including the two new tests;cargo test -p acpmux --lib acpmux_mcppassed 36/36;cargo clippy -p acpmux --all-targets -- -D warningswas clean. - Not run: the whole acpmux suite, and a live agent chat getting the notice in the app (only the hub's fake agent).
Changelog
- Added: an agent's background command (acpmux
bg_start) now tells its chat once when it ends, and background-task tool results start with a one-line summary.
Agent session: agent session
š¤ Generated with Claude Code