Add cloud machine join CLI
End-to-end rollout still requires the trusted helper, legacy CUA hook, app Screen integration and transactional recovery.
Adds development-only acpmux host join: a bounded cmj_ token arrives on stdin, the transport-owned helper supplies the public WireGuard key, and the redeemed cmm_ credential is stored in a 0600 file. The daemon reads that credential in-process through meshRelay: {url, credential: "join"}. Tokens and credentials are never printed or passed through argv, environment or URLs. The installer owns service installation.
--status --json exposes enrollment, relay, heartbeat, revocation, consent and lastRefusal. Consent is shared across daemon tags for the OS user under the password-entry home’s .acpmux/machine-consent/{enrolled,consent,refusal}.json, never selected by HOME or ACPMUX_HOME. The directory is 0700 and records are 0600. Enrollment durably requires consent before redemption; defensive detection of current-home development records imports no grants. _acpmux/machine_consent_set requires a person-proven local Unix connection. A TTY alone cannot grant consent. _acpmux/machine_consent_get returns consentRequired, consent and the latest refusal. Local _acpmux/machine_consent_refused records a refusal without granting access.
Status reports running-helper consent support as unknown, and successful or idempotent joins warn that older live helpers may remain ungated until they exit. No process is killed or restarted.
The v2 bridge asks machine/consent over its admitted helper connection before every tool call. It denies missing, mismatched, malformed or timed-out responses; the child’s ACPMUX_HOME cannot choose the consent authority. The admitted helper’s current tools/list readOnlyHint determines observation tools, which need screen permission. Actions and unknown or ambiguous tools need screen and control; malformed inventory fails closed. The hand rechecks consent after owner approval. A failed credential save explains that the token was consumed and directs the user to fix storage, revoke the machine row and obtain a fresh token, without printing secrets.
Independent Codex gpt-6-astra high/fast review returned SHIP at 48543fcb76358aabf0f6da1efacd0ef52c6efda3; final delta review returned SHIP at 0466959088166ec279f118aa491a9991e44c6e8f (log /tmp/hb-b-astra-04669590.log, session 01a187af-324e-7bc3-a512-55fc0da317e7).
At 48543fcb76358aabf0f6da1efacd0ef52c6efda3, compile, standard integration, all eight disposable-account process tests, six authority tests, the hand regression and strict all-target clippy passed in 40879552303, broker job f22aeb4ce3b3448eb8f763baab4436e8. The final delta moves test fixtures and registers the deliberate shared-root exception.
Red regressions: alternate-home bypass 40856996496; actual post-redemption write failure 40856512919; independent screen denial 40853584644; hand revocation 40847727626; stdin/pairing 40848326736; consent requirement 40849402652; trusted driver inventory 40874715493. Additional controlled regression runs: canonical cross-tag authority 40879559148, job 41f14722e74e441eaf9021066457969b; idempotent marker repair 40879565643, job 45050ed1e81345659068be1f9eae80d2; namespace durability retry 40878383920, job 23b4b5de876043b395f4b4e88ca2be4f. At a65f075d, run 40878392062 passed six authority unit tests and all eight isolated process tests. Shared-authority process tests use a disposable OS account in remote CI so tests exercise the real password-entry authority without touching the runner’s machine state.
Base-red evidence at 48543fcb: protocol job 123466278784 and inventory job 123466279088 each contain only the known test_live_raw_v12_layout_and_history_contracts_are_exact / new-pane-right cols-versus-pane failure (64 tests, one failure), verified against base comparisons 40861456335 and 40853653971. The state-root lint fix at 0466959088166ec279f118aa491a9991e44c6e8f records the explicit exception above and moves test literals out of product-source counting. Focused checks, consent tests and strict all-target clippy passed in 40880744178, job c136871ffc094dc3bb7c8a367bd54b31.
The helper must implement machine/consent from its established app-owned daemon authority and enforce consent at execution time. Legacy cmux-cua is not consent-gated by this PR until its upstream hook ships and is pinned; tracked in https://github.com/manaflow-ai/cmuxterm-hq/issues/5053. App Screen consent and automatic transactional credential recovery are separate follow-ups. The bridge fails closed with an older helper. No end-to-end enrollment or release validation is claimed. No released acpmux or app supports pre-marker cloud enrollment: the installer checks a capability introduced only here. Branch-only development records are not a supported cross-tag upgrade path; rerun join to establish the canonical enrollment marker.
The state-root lint has one deliberate exception for the per-OS-user consent resolver: isolating this security authority per build would let another app tag bypass enrollment or revocation. Product paths still resolve from the OS password entry; test fixtures live in a separate test module.
Size: enrollment, relay credential use and consent enforcement ship together so enabling join cannot omit its access checks. Their shared state-machine tests and disposable-account harness account for much of this roughly 2,100-line change. Platform API and transactional credential recovery are separate PRs.
Leo's words (2026-10-29, via claude-sr2): "we dont like iroh for various reasons... i think personally dealing with it was kinda weird and flakey? i meant didnt i have a little idea to like "what if we had our own tailscale-like service?"" and earlier: "do our own version of Tailscale. That's what they kind of settled on."
Leo's words (2026-10-29 ~03:30Z): "just have this sort of thing for, I guess, general onboarding of adding remote machines and whatnot and whatever, which includes, I guess, screen sharing potentially."
Agent session: agent session