cmux NEXT: NIGHTLY's Chief runs on the app's acpmux, not a daemon of its own
Plan: manaflow-ai/cmuxterm-hq#2699 (one acpmux per machine per user; Leo, 2026-10-20: "you should prob unify the acpmux running situations").
What changes
Until now NIGHTLY's Chief ran its turns, compactor and subagents on a daemon of its own (~/.cmux/chief/default/acpmux), apart from the app's ~/.acpmux. On cosmic-gray that meant two NIGHTLY daemons, and Chief's subagents and the lanes could not see each other.
With this change, NIGHTLY's Chief home (ChiefHome.usesAppAcpmux: buildID com.cmuxterm.app.nightly, not isolated) runs on the app's own acpmux:
HomeBrainHost.resolvegives the host the app's acpmux environment (the same~/.acpmuxthe panes resolve) plusOPTCHAT_ACPMUX_SUPERVISED=1, so optchat-chief waits for that daemon and never spawns it. Its stop path leaves alone a daemon it did not start (stop_started_acpmux). It does not setOPTCHAT_ACPMUX_SHARED: in that mode the last Chief to leave runsdaemon shutdown --end-agents, which would end the person's chats.- The app's daemon now starts with
ACPMUX_CHIEF_MUX_HOME=<Chief home>in its own environment (AgentTabPaneSource), which acpmux's built-in Chief presets need (chief_builtins.rs).ACPMUX_PROBE_HARNESSESstays unset, so the daemon probes every harness. The subagent pinned keys come from the app daemon's own environment (CMUX_BUNDLED_CLI_PATHand the app sockets). HomeBrainHost.startfirst starts the app's daemon through the local pane host (prewarm, the normal find-or-start path). It skipsAcpmuxChiefHandoff: the Chief path never stops the app's daemon.- Chief tabs (host
chief:<id>) attach through the local pane host. There is no Chief heal and nomux.parentrouting, since there is only one daemon. The app's own version handoff heals it. - Quit's End Sessions no longer ends a Chief daemon here (
ChiefHostStop.endChiefSessions).QuitAgentsends the app's daemon right after, keeping none of the Chief's sessions (ChiefHostStop.appAcpmuxEndKeep), so the Chief's turn, compactor and subagents end with the person's agents. - ErrorJournal stops reading the old Chief daemon log; the app's
~/.acpmux/daemon.logcovers it. - Each start moves over a host this app did not launch on the app's acpmux (the previous build's after an update, or one whose bundle was replaced): it hands off when idle, else it stops. Then the Chief home's old daemon ends with its agents, but only at a start where none of its sessions is in a turn (a subagent the Chief started may still be working after the Chief went idle); until then it keeps running. It never ends while a named Chief (
c/<id>) runs on it, and the app's daemon is never ended. - The Chief resolves the daemon of the app's build (
AppEnvironment.build), the same one its panes use. - Kill switch:
CMUX_CHIEF_OWN_ACPMUX=1in the app's environment (e.g.launchctl setenv, then relaunch) brings the old per-home daemon back. At that launch, a running host this app launched on the app's acpmux hands off when idle (else it stops) and restarts on the Chief's own daemon, wherechief:<id>tabs then attach (ChiefAppAcpmuxMove.leaveAppAcpmux). It is read once per process, so the tab wiring, the error journal and the Chief host always agree. (A Debug Settings toggle was dropped in review: some consumers resolved before the settings file loaded.)
DEV, staging and isolated Chiefs are unchanged: they keep their per-build Chief daemon (cx-is1kf).
Why the gap is accepted instead of handing off: if the app's daemon is the same build but was started without ACPMUX_CHIEF_MUX_HOME (by the CLI, or with the kill switch on), the Chief path keeps it running. Built-in codex turn presets fail closed until that daemon's next start, which is the next update's version handoff. Stopping the daemon that runs the person's chats from the Chief path is worse than a codex-preset gap, and the first NIGHTLY with this change hands the old-build daemon off anyway (AcpmuxVersionHandoff) and starts it with the new env.
Not changed / follow-ups
- The Chief's old daemon's session records stay on disk and are not imported. Its open subagent tabs (
chief:<id>) whose sessions live only there no longer attach, and the agents of that daemon end once it is idle (above). - Named (non-default) Chiefs that the owner daemon starts (
chief_brains.rs) still share the Chief home's acpmux, and so doescmux chieflaunched without the app (cli/chief/launch.rs). Follow-up. HomeChiefFiles.acpmuxConfigFile(the "CodeRouter route configured" hint) still reads the Chief home'sacpmux/config.json. Follow-up.CMUX_CHIEF_OWNER_SOCKETis not in the app daemon's env, so built-in subagents fall back to the app sockets. Follow-up if Chief subagents need the owner socket directly.
Tests
ChiefAppAcpmuxTests: NIGHTLY's host resolves the app's acpmux home with OPTCHAT_ACPMUX_SUPERVISED=1 and no OPTCHAT_ACPMUX_SHARED; a DEV build keeps <chief home>/acpmux; usesAppAcpmux holds only for NIGHTLY's own non-isolated home without the kill switch; the kill switch parses only 1; the Chief resolves the same daemon as the app build's panes; the move plan restarts only hosts this app did not launch on the app's acpmux; the old daemon ends only when no session (the Chief's included) is in a turn; End Sessions keeps no Chief session on the app's acpmux; with the kill switch, only the host this app launched on the app's acpmux restarts.
Observed / Not run
- Ran:
scripts/cmux-next/prepush-gate.py(no new violations). Independent review of b5373fb: FAIL on the toggle and the old daemon's agents; both fixed in cc972a8. Re-review of cc972a8: FAIL. (1)ChiefAppAcpmuxMovewas main-actor isolated under the module's default isolation, socmux-next swift testfailed to compile on b5373fb; it isnonisolatednow. (2) A census that timed out (nil) still ended the old daemon; now an unknown census is not idle and a later start ends it (tested). Both fixed in eca0d23. Re-review of eca0d23: FAIL. (1) End Sessions kept the Chief's sessions on the app's daemon (its defaultkeep: .chief), so they outlived the quit; now it keeps none when the Chief runs there. (2) The kill switch did not move a running host off the app's acpmux; now it does at the next launch. Tests first in aea1f69 (red), fixes in b98275d. Re-review of b98275d: PASS (low notes only, below). - Known residual (low): when the launch cannot read the new host's pid, the mark falls back to the host lock read right after launch, which the host may not have written yet. The next start then restarts that host once.
- Known residual (low, from the eca0d23 review): a subagent on the old Chief daemon that waits for a permission answer counts as in a turn, so that daemon stays until it is answered or ends; and a dead old daemon with a stale socket leaves its agent processes (no turn is ever cut). A host from before 23e6fdf (no hand-off support) is still stopped at once, as before this PR.
- Known residuals (low, from the b98275d review), for a follow-up: (1) with
keep: .nothingthe quit'sknownChiefset is not cleared, so a Retry after a shutdown in progress can report agents ended while a Chief subagent host still holds its lock; (2) after the kill switch moves the host, its earlier Chief sessions on~/.acpmuxare kept by later End Sessions until ended by hand; (3) two apps on one Chief home with different app daemons (Debug-only env) restart each other's host; (4) a mark is written for a launched host that lost the lock race, so the survivor restarts once. - Not run: the Swift compile and tests. This lane runs on a Linux host, so CI compiles. No live dogfood yet; cosmic-gray moves to this after it ships in a NIGHTLY (plan step 5).
No capture: nothing on screen changes. The Chief's host, daemon wiring and quit end change; Chief subagent tabs look the same, they now attach to the app's daemon.
Changelog
Changed: cmux NEXT's Chief runs its subagents on the app's own acpmux daemon, so they show beside your other sessions.
Agent session: huge-blue
🤖 Generated with Claude Code