Skip to content

fix(hooks): load a host's permission rules once, OpenCode included - #4458

Open
KuSh wants to merge 2 commits into
developfrom
fix/host-rules-loaded-once
Open

KuSh wants to merge 2 commits into
developfrom
fix/host-rules-loaded-once

Conversation

@KuSh

@KuSh KuSh commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up to #4349.

Summary

  • permissions::HostRules holds a host's rules, read from disk once: deny/ask/allow lists, or OpenCode's ordered last-match-wins list. HostRules::load(host, agent) replaces load_rules_for and the OpenCode branch in check_command_for_agent; each host's arm also says whether that host judges the command its hook hands back.
  • Every rtk hook <agent> processor and rtk hook check decide through decision::decide_for_host: the verdict of the typed command, the shared decision, and, on a host that judges the final command (OpenCode), no rewrite whose verdict differs. The rules are loaded once and the typed verdict is computed once.
  • rtk hook check --agent opencode now gives the plugin's answer. It printed rtk git status (exit 0) where rtk hook opencode answers {}, e.g. git status under {"*": "deny", "git status": "allow"}, git push origin main under {"git push *": "ask"}.
  • rtk discover judges transcript commands through the same HostRules (Claude Code's, still read once per run) instead of its own deny/ask/allow struct.

When the skip applies, hook check prints the generic No rewrite for: <cmd>; saying that the rewrite would change the verdict could be a follow-up.

Test plan

  • cargo fmt --all && cargo clippy --all-targets && cargo test --all (4169 passed)
  • Differential against develop (cf018af): 9 hook processors, rtk rewrite, rtk hook opencode and rtk hook check for all 18 agents, over 3 settings layouts × 9 commands (783 runs per side). The only difference is hook check --agent opencode on git status under the [OpenCode] RTK rewrite breaks existing Bash permission allowlists by adding rtk before permission evaluation #4195 policy. rtk discover --all on a synthetic transcript gives the same report as develop (its group labels vary run to run on develop too).
  • Mutation check: 20 of 21 mutations of the new decisions are killed by tests. The survivor is the recall bookkeeping's deny condition, unchanged from develop and untested there too.
  • New tests: hook check vs the plugin over 7 policies × 6 commands, each host reading its own rule file and no other, delegates reading Claude Code's rules and rules-file agents none, Claude Code keeping its rewrite beside an opencode.json.

🤖 Generated with Claude Code

`HostRules` holds a host's rules, either deny/ask/allow lists or OpenCode's
ordered last-match-wins list, read from disk once. Every `rtk hook <agent>`
processor and `rtk hook check` decide through `decide_for_host`: the verdict
of the typed command, the shared decision, and, on a host that judges the
command its hook hands back (OpenCode), no rewrite whose verdict differs.
This replaces `load_rules_for` and the OpenCode branch in
`check_command_for_agent`.

`rtk hook check --agent opencode` now gives the plugin's answer: it reported
a rewrite the plugin skips, e.g. `git status` under
`{"*": "deny", "git status": "allow"}`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rtk-wshm-sync-bot

Copy link
Copy Markdown

wshm · Automated triage by AI

📊 Automated PR Analysis

🐛 Type bug-fix
🟡 Risk medium

Summary

Introduces HostRules::load to read a host's permission rules (deny/ask/allow lists or OpenCode's ordered list) from disk exactly once, replacing load_rules_for and the ad-hoc OpenCode branch. Adds decide_for_host, shared by every rtk hook <agent> processor and rtk hook check, which also drops a rewrite on hosts (OpenCode) that judge the final command if the rewrite's verdict differs from the typed command's verdict, fixing a prior discrepancy where rtk hook check --agent opencode di…

Review Checklist

  • Tests present
  • Breaking change
  • Docs updated

Analyzed automatically by wshm · This is an automated analysis, not a human review.

`rtk discover` kept its own deny/ask/allow struct for Claude Code's rules.
It now holds the same `HostRules` the hooks load, still read once per run,
and `load_permission_rules` is private to `permissions` again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant