Repository navigation
cmux NEXT: the app takes over a stray acpmux on its home instead of refusing it - #23598
Conversation
…ed; its launch agent is found (red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ca9-5ac5-7692-adfc-a3ae828256ca&host=huge-blue
… move to the bundled daemon); a launch agent that runs it is booted out Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ca9-5ac5-7692-adfc-a3ae828256ca&host=huge-blue
|
Owned by acpmux-unify on huge-blue · session |
|
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)
Not verified: macOS jobs did not run: compile and app tests were skipped on CI passes on Written by Tour of |
…id, boots it out without disabling it, and trusts only the socket's own peer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ca9-5ac5-7692-adfc-a3ae828256ca&host=huge-blue
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. |
|
Bead |
…s is the daemon, never an app; a failed bootout falls back to the shutdown request Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ca9-5ac5-7692-adfc-a3ae828256ca&host=huge-blue
|
Review (independent Claude subagent, acpmux-unify lane): SHIP at 8d2a276 This is the third review. The first two failed (d6a14bb, 1ce6a13); every finding from them is fixed:
Scope: another install's daemon ( Low residuals are listed in the body. Swift 6 compile checked by reading. |
|
Review (independent Claude review subagent): SHIP at 046a080 One base merge of feat-cmux-next ea0e0ed. Reviewed the full PR diff from that base plus the merge's effect on the APIs the PR uses (all present with the same signatures). No defects. Two non-blocking notes: a failed takeover is not retried in the same process (deliberate, no loop), and a bootout that stops the daemon but returns non-zero shows one refusal before the next attempt starts the bundled daemon. |
|
Shipped in:
|
In progress. The review of d6a14bb FAILED; its findings were fixed in 1ce6a13. The re-review of 1ce6a13 FAILED on the parent-pid match (it could boot out a terminal app that started the daemon); fixed in 8d2a276. The re-review of 8d2a276: PASS (low notes below). risk:high (daemon lifecycle): held for coord-deputy before merge.
One acpmux per machine (hq plans/cmux-next/acpmux-one-daemon.md, step 2). When the daemon on the app's acpmux home is not one any cmux install runs, the app now takes it over instead of refusing it. Examples are a
~/.local/bin/acpmuxstarted by launchd (com.acpmux.daemon) or by the CLI's autostart. Before this change, the server peer check refused that daemon because its executable is not the app's, and every chat said acpmux did not start.AcpmuxStrayDaemon.isStray): the daemon's executable (proc_pidpath, symlinks resolved) is neither the app's acpmux nor inside any.app/Contents/. Another cmux install's daemon is not stray: NIGHTLY shares~/.acpmuxwith older builds, and the peer check's existing rules still decide those (lead decision 2026-10-10).handOffIfStray) runs only where the app may start a daemon (findOrStartwithstartsDaemon), before the version handoff. It is the same move as an update handoff: the old daemon stops, its agents detach, and the bundled daemon starts and adopts them. It acts only when the daemon reportsagentHosts; an older one would end its agents, so it keeps running and stays refused, as before. It runs at most once per pid per app process.application.*job either. It reads theserviceslist oflaunchctl print gui/<uid>, then confirms the job withlaunchctl print gui/<uid>/<label>(pid = N). If it finds one, the app runslaunchctl bootouton it, so KeepAlive does not start it again. launchd's SIGTERM goes through the sameshutdown_allas_acpmux/shutdown, so the agents detach (agent hostssetsid). The job is not disabled:acpmux host setup/updatebootstrap that samecom.acpmux.daemon, and launchd refuses a disabled one. A later login may start it again. If the bundled daemon already holds the home, that stray copy fails on the lock and KeepAlive retries it about every 10 s (the throttle) until it is fixed by hand or byhost update. If the stray wins, the app takes it over again. A bootout that fails falls back to the shutdown request. If no launchd job runs it, the app sends_acpmux/shutdownover the socket.LOCAL_PEERPID,AcpmuxServerPeer.socketPeer), and only when its pid equals the pid the daemon reports. That pid's executable must be stray and the peer must run as this user. Before this, the code acted on the pid the daemon reported, without checking it.Risk: high. This stops a daemon the app did not start, and it boots out the launchd job that runs it (until the next login). It happens only for a daemon on the app's own home that runs outside every app bundle and has agent hosts, and no running agent is ended.
No capture: nothing on screen changes, except that chats connect where they used to say acpmux did not start.
Tests (
AcpmuxStrayDaemonTests), committed first in ed07687 (red):chatsReachTheBundledAcpmuxWhenAStrayDaemonHoldsTheHomestarts the same-tree acpmux from alocal/bincopy on a home, then the app's host from its ownbincopy. Without the fix, the app's start is refused (daemonRefused, other executable). With it, the daemon then runs from the app's bin with a new pid.onlyADaemonOutsideEveryAppBundleIsStraycovers what counts as stray.theLaunchdJobThatRunsTheStrayDaemonIsFoundByItsPidcovers finding the job by pid in the services list and reading a job's pid.Observed / Not run
scripts/cmux-next/prepush-gate.py(no new violations).cmux-ci run --class light --script scripts/ci/run-swift-testing-suites.sh --arg Packages/macOS/CmuxNexton a macOS mini (PR CI skips these suites because they need the same-tree acpmux):chatsReachTheBundledAcpmuxWhenAStrayDaemonHoldsTheHomealone on base 7eed529 (scratch branchcmux/acpmux-absorb-stray-red@ 34cbc8b). It fails:the app's launch failed: daemonRefused(holder: …/local/bin/acpmux, … reason: "the socket's peer is …/local/bin/acpmux, not the acpmux this app runs"). The red commit ed07687 itself does not compile the test target, becauseAcpmuxStrayDaemondoes not exist yet, so the base run is the behavioural red.AcpmuxStrayDaemonTestspass,AcpmuxBundleReplacedTestspasses, and no suite was skipped for needing the same-tree acpmux.fleet/compile-check, Release compile, fast tier and generated files are green.cmux-next swift testfails, but none of its failing tests are on this change's path. They are sidebar render counts, the morphing card, page hibernation, Chief row titles and settings words, while this diff only changes the daemon start inAgentPaneHost.findOrStart. Base push runs skip swift test, and other open PRs fail different UI suites in the same job.Tour the appfailed while setting up its runner.launchctl bootoutthat exits non-zero while it is still stopping the job, and a socket that is already gone, can fail one chat open; the next open finds nothing on the socket and starts the bundled daemon. (2) A launchd job that starts the stray as a child (not matched, by design) with KeepAlive can restart it. Each later open then takes it over again: agents are kept, but CLI clients on the stray are disconnected each time.Changelog
Changed: cmux NEXT takes over an acpmux daemon it did not start (such as
~/.local/bin/acpmux) instead of refusing it, so chats connect and the agents keep running.Leo-ask: ask-ddceee64a4
Agent session: huge-blue
🤖 Generated with Claude Code