fix(cx-gakp): persist Claude permission suggestions

Closed
TE
23d ago
+6484-1404

Summary

acpmux's Claude stdio adapter now answers Claude Code's can_use_tool asks the way Claude Code itself does.

  • Allow always. The adapter keeps Claude's permission_suggestions with the control request id. When the person picks allow_always, it returns them unchanged as updatedPermissions, which is the only way Claude installs the rule. allow_once never sends them. "Allow for this session" is offered only when Claude sent at least one suggestion; an empty or missing list hides it, so there is no "always" option that does nothing.
  • Reject. The pane labels the reject "No, tell Claude what to do differently" and moves focus to the composer. acpmux used to send a plain deny, so Claude carried on with the turn by itself. The person's reject_once now sends {"behavior":"deny","message":…,"interrupt":true}, which is Claude Code's own "No, and tell Claude what to do differently". The shape comes from the Claude CLI 2.1.299 bundle: its SDK can_use_tool response schema is {behavior:"deny", message, interrupt?: boolean}, and the handler logs SDK permission prompt deny+interrupt and aborts the turn. Cancels, errors and unknown options still send the plain deny.

Verification

The behavior test runs at the product boundary: fork_through::claude_permission_answers::claude_gets_the_persons_permission_answer_as_claude_code_defines_it. The person answers three scripted can_use_tool asks from fake_claude.py, each carrying permission_suggestions, and the test checks the control response Claude Code receives for each.

Both runs used the same fleet command: scripts/ci/cmux-tui-rust-check.sh test claude_gets_the_persons_permission_answer.

  • Red, on test commit 2df7fae16ec5 (before the fix): panicked at claude_permission_answers.rs:94:5 left: Null right: true. That is the interrupt assertion; the allow_once and allow_always assertions passed.
  • Green, on merged head 7851c01fc38b (fix 5bbddb8a6c87 + base merge 705b5d752d18): test fork_through::claude_permission_answers::claude_gets_the_persons_permission_answer_as_claude_code_defines_it ... ok (1 passed).

Local checks: cargo fmt --check -p acpmux and scripts/cmux-next/crash_ratchet.py both pass. No unit tests were added.

Changelog

Fixed: Claude's "Yes, and don't ask again" now saves Claude's suggested permission rule, and "No, tell Claude what to do differently" stops Claude's turn so it waits for your message.

🤖 Generated with Claude Code