acpmux: trust a worktree cmux made, and never gate a chat that already works
On 2026-10-21 the directional-motion lane on huge-blue locked up. Its chat lives in /home/leo/.cmux/worktrees/cmux/directional-motion, and every send from the app failed with "Not sent: trust.pending" until someone ran cmux setup trust <folder> by hand. Two things in the acpmux daemon's trust gate caused it. This PR fixes both:
- A worktree cmux made is trusted with no question.
- Before: a worktree only took its repository's acpmux decision. If nobody had pressed Trust in cmux for that repository, every chat in
~/.cmux/worktrees/<project>/<name>waited ontrust.pending. Claude's own trust of the main checkout didn't count, because Claude's level is per path. - After: a linked worktree that git wrote directly at
~/.cmux/worktrees/<project>/<name>is trusted the same way the agent-home folders cmux makes are. The check uses the samerepository()check that already refuses forged.gitfiles. This holds on every host, because each daemon checks its own home. - Still refused: an explicit Don't trust, for either the worktree or its repository, and an agent's own untrusted level for the worktree or its repository. A plain folder under
~/.cmux/worktreesis still asked about, and so is the repository itself. - Auto-trust Off: like the agent-home folders, the rule holds even with
agents.trust.autoTrustoff, because cmux made the folder. That setting covers only the person's project roots and organizations. - Web clients: the rule reports
auto: "worktree", so like an auto-trust rule it is not a person's answer for a Web client. A worktree holds its repository's content, so a remote browser still waits for a person.
- Before: a worktree only took its repository's acpmux decision. If nobody had pressed Trust in cmux for that repository, every chat in
- Trust never gates a chat that is already working.
- Before: a chat that a coordinator started over the unix socket (which is not gated) in a folder nobody answered for refused the app pane's prompts with
trust.pending, even while its agent was running turns there. - After: once a chat has run a turn on this daemon (it has a
last_turn, or a turn is running),trust.pendingno longer refuses itssession/prompt,session/set_mode,session/set_config_optionor_acpmux/set_tools. That includes the queued-prompt dispatch check. - Still refused:
- An explicit Don't trust still refuses the chat (
trust.untrusted). - A Web client still waits for a person's decision.
- A chat moved or imported from another daemon keeps its
last_turn, so it counts as running here too. - A chat that was only created (agent started, no prompt yet) still waits for the answer before the pane's first prompt. So does a chat whose only turns are an adopted conversation's replayed history or a fork's copy of its parent's.
- A fork, a side session (
btw) and a handoff still check their own folder, because each starts an agent of its own.
- An explicit Don't trust still refuses the chat (
- Before: a chat that a coordinator started over the unix socket (which is not gated) in a folder nobody answered for refused the app pane's prompts with
This is daemon side only. The app's Trust button belongs to the palette-audit lane, and the paused-queue item has its own PR.
Risk: risk:high (folder-trust policy in the daemon's trust gate).
Changelog
Fixed: a chat in a worktree cmux made, or one that is already working, no longer refuses your messages with "trust.pending".
Tests
cargo test -p acpmux --test local_app_trust_gate a_worktree_cmux_madeanda_running_chat_is_not_held_by_an_open_trust_question: integration tests through the app's connection.cargo test -p acpmux --lib a_worktree_cmux_made_is_trusted_with_no_question: the rule itself, including Don't trust on the repository or the worktree, an agent's untrusted level (worktree and repository), a Web client still waiting, a plain folder, and the repository staying unanswered.
Red on the test commits (base plus tests): ./scripts/verify-cmux-tui-hosted.sh --filter question at 940818a2f51ad9ab5284a44efbfc7d6abefa2f41: https://github.com/manaflow-ai/cmux/actions/runs/39686176119. test (linux) failed on trust::scope_tests::a_worktree_cmux_made_is_trusted_with_no_question, and the lib failure stops the integration targets. macOS was still queued.
Green on the head: same filter at 9477fa991491c1fde1e948a9d2d6afa40340c459: https://github.com/manaflow-ai/cmux/actions/runs/39687136572. test (linux) passed with all three new tests. macOS was still queued. The head c69158b4 changes only a comment after 9477fa99.
Observed / Not run
- Observed on huge-blue: the three new tests fail on the red commits. The worktree read
"level":"unknown", and the app's prompt to a running chat got{"reason":"trust.pending"}. They pass on the fix.local_app_trust_gate,subsession_trust,peer_integrationand thetrustunit tests pass locally on the head.cargo clippy -p acpmux --all-targets -D warningsandprepush-gate.pyare clean. The full localcargo test -p acpmuxrun stopped on temp-folder permission tests (session_tmp,store::permission_tests), which refuse this host's group-writable TMPDIR; the hosted run and PR CI cover those. The folder name comes from cmux-git's newworktree_root_path, so the state-roots ratchet stays at its baseline. - Not run: no Swift code changes, so there was no app build. I didn't try the change against the live daemons, because they're shared and I didn't restart any.
Agent session: huge-blue
š¤ Generated with Claude Code