Repository navigation
acpmux: a runner for background tasks that outlive the agent - #26446
Merged
Merged
Conversation
Collaborator
Author
|
Owned by an agent session · session |
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 27, 2026 23:33 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 27, 2026 23:34 — with
GitHub Actions
Inactive
teamleaderleo
force-pushed
the
hotswap-opus/session-bg-runner
branch
from
October 27, 2026 23:47
e8e1f69 to
60faacd
Compare
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 00:13 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 00:13 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 00:48 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 00:49 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 01:03 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 28, 2026 01:03 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 01:08 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 01:16 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 01:19 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 01:31 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 01:32 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 01:45 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 28, 2026 01:45 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 01:50 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 01:58 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 02:01 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 02:29 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 02:30 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 02:48 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 28, 2026 02:48 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 02:53 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 02:54 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 28, 2026 03:55 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 03:59 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 03:59 — with
GitHub Actions
Inactive
teamleaderleo
had a problem deploying
to
artifacts
October 28, 2026 04:03 — with
GitHub Actions
Failure
teamleaderleo
force-pushed
the
hotswap-opus/session-hibernate
branch
from
October 28, 2026 10:31
8c76472 to
a93fbf4
Compare
Base automatically changed from
hotswap-opus/session-hibernate
to
feat-cmux-next
October 28, 2026 13:27
Leo: "also when it comes to hibernation...can't you hibernate the agent but not hibernate the bg tasks?" acpmux __bg-run holds a lock for its task's life, opens a stop FIFO, spools the task's output into two segments named by their start (newest 8 MiB), starts /bin/sh -c COMMAND as a new session's leader, records it, and stops it (SIGTERM, then SIGKILL after 5 s, to the task's own group, only before reaping the leader) on a FIFO byte or SIGTERM. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495
… dies of SIGPIPE Review fixes. The runner ignores SIGPIPE (the task gets it back), so a closed answer pipe is an error that stops the task. The leader stays unreaped until the pipe ends, so output a child it left writes later is kept and a stop still reaches that child through the group id; a stop whose SIGKILL leaves the pipe open ends the wait after its grace. A spool write failure is recorded (outputError) and the pipe is still drained. A start that fails removes its FIFO and first segment. Tasks run under bash where /bin/bash exists, like the agent's Bash tool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495
…nd holds no pipe The runner reaped the leader at the pipe's EOF, even while a stop waited out its grace, so a member that ignored SIGTERM with its output sent elsewhere outlived the stop. The reap now waits for the stop's SIGKILL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495
… the task gets exactly its env Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495
…el before any stop, and says a spool it cannot list Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495
…p it cannot wait for, cleans a start a signal cut short, and stops spooling when a segment will not go A stop after the reap changes nothing. SIGCHLD is reset to default and a failed waitid marks the group unknown, so nothing signals it. Every way out of a stop lets the reap go on. Records carry the folder's generation from the spec. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495
teamleaderleo
force-pushed
the
hotswap-opus/session-bg-runner
branch
from
October 28, 2026 13:28
36d228a to
4e87527
Compare
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 13:28 — with
GitHub Actions
Inactive
Contributor
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
web and size checks: green |
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 13:29 — with
GitHub Actions
Inactive
The runner (`acpmux __bg-run`) is its own process: a stop before its task starts and the end of its task both end it with process::exit, since its stop and spool threads may still block in reads. The crash ratchet's acpmux exit.waived row goes from 4 to 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495
Collaborator
Author
|
Bead |
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 13:59 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
ci-routing-agent
October 28, 2026 13:59 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 14:15 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
sentry-dsyms
October 28, 2026 14:15 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 14:22 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 14:34 — with
GitHub Actions
Inactive
teamleaderleo
temporarily deployed
to
artifacts
October 28, 2026 14:39 — with
GitHub Actions
Inactive
Contributor
|
Shipped in:
|
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Leo: "also when it comes to hibernation...can't you hibernate the agent but not hibernate the bg tasks?"
Part 1 of 4: the runner. Part 2 (#26463) adds the daemon's methods, the idle-gate rule, the hibernation test and docs/hibernation.md. Part 3 (#26659) ends a purged chat's tasks. Part 4 (#26447) adds the agent's MCP tools and the Claude Code hook.
Why a runner
A harness cannot keep its own background shells alive. We checked both harnesses directly:
run_in_backgroundshell runs in its own session.claude --resumereports it "stopped ... left no completion record" and cannot stop it.terminate_all_processes(core/src/session/handlers.rs:584), and dropping a process handle kills its group (unified_exec/process.rs:638).What
acpmux __bg-run(src/bg_run.rs) runs one task. The daemon starts it in a session of its own (part 2), so it outlives the harness and the daemon.<id>.lockfor the task's whole life (the lock, not a pid, says the task runs);<id>.ctl;bash -c COMMAND(/bin/shwhere there is no/bin/bash, matching the agent's Bash tool) as the leader of a new session, with no signals blocked and SIGPIPE back to its default. It then writes<id>.json(written to a temp file and renamed, always under one lock) and answers one line. If the record or the answer fails, it stops the task, so no task runs unrecorded. The runner ignores SIGPIPE, so a closed answer pipe is an error it handles, not a death. A start that fails removes its FIFO and first segment.<id>.out.<start>, named by where each starts in the whole output. The files alone define what is kept, so a crash cannot leave them disagreeing with a record.waitid(WNOWAIT)and reaps it only once the pipe ends. The zombie keeps the group id the task's, so a stop still reaches children the leader left behind, and it marks the leader reaped under the same lock it signals under, so it never signals a freed group id.outputError, and the pipe keeps being drained so the task never blocks. A read that loses every retry against a rotation is an error ("read again"), never an empty output.outputError) rather than keep a third. Records carry their folder's generation (acpmux: background tasks the daemon owns outlive a hibernated agent #26463).setsid cmd &). That output is still the task's, and a dev server may run for days. A stop ends the wait.New timers, loops and watchers
Each one, with when it stops and what cleans it up:
sigwaitloop). It lives as long as the runner process, which exits right after the leader is reaped.There is no polling anywhere.
Tests
bg_run::tests::the_spool_keeps_two_segments_and_reads_across_themchecks:End to end, the runner is exercised in #26463's hub integration tests: hibernation, the cap, FIFO stop, SIGKILL after an ignored SIGTERM, a child that ignores SIGTERM and holds no pipe, late output after the leader exits, binary output, purge.
Fleet Linux at the exact head 7c08a5f (rebased onto feat-cmux-next with #26127 and #26174):
cargo clippy -p acpmux --all-targets -D warningsclean;cargo test -p acpmux --lib -- bg_run2 passed.Crash ratchet: the runner's two
process::exitcalls (a stop before the task starts, and the end of the task) are reviewed// crash-allowwaivers. The runner is its own process, and its stop and spool threads may still block in reads. The baseline's waived acpmux exit row goes from 4 to 6. The ratchet's other row, cmux-tui-core unwrap at 1150, is red the same way on base.Review
Review (codex gpt-6-astra high, fast): SHIP at 7c08a5f (round 8 reviewed the crash-allow waivers; round 7, a fresh review after the rebase at 4e87527 with the patches unchanged from round 6's SHIP at 36d228a, it found no overlap with #26174 and confirmed that the idle census does not see the runner, which runs in its own session).
Fleet, whole stack at 6e2602f (run 40638654802): clippy clean for acpmux and cmux-tui;
hub_integrationbg_tasks, session_hibernate and processes: 58 passed; lib bg_run, bg_hook, acpmux_mcp, protocol, idle and the config test: 27 passed;tests/agent_tools.rs: 2 passed; cmux-tui bg_steer and instructions: 2 passed.Risk
Low on its own: nothing starts the runner until part 2.
Agent session: agent session
🤖 Generated with Claude Code