permissions hook helper
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 194 lines 5.3 kB view raw view rendered
1# chook 2 3A PreToolUse hook for Claude Code that gives you granular control over what Claude can do, with an interactive review TUI for building rules from real usage. 4 5Zero dependencies. Single JS file. Works with any Claude Code session on your machine. 6 7## Install 8 9```bash 10ln -s /path/to/chook/chook.mjs /usr/local/bin/chook 11cp example.toml ~/.config/chook.toml 12``` 13 14Add to `~/.claude/settings.json`: 15 16```json 17{ 18 "hooks": { 19 "PreToolUse": [ 20 { 21 "matcher": "*", 22 "hooks": [ 23 { 24 "type": "command", 25 "command": "node /path/to/chook/chook.mjs run" 26 } 27 ] 28 } 29 ], 30 "PostToolUse": [ 31 { 32 "matcher": "*", 33 "hooks": [ 34 { 35 "type": "command", 36 "command": "node /path/to/chook/chook.mjs post" 37 } 38 ] 39 } 40 ] 41 } 42} 43``` 44 45The PostToolUse hook enables macOS notifications when Claude is waiting for your approval. 46 47## How it works 48 49Every time Claude tries to use a tool, the hook checks your rules: 50 511. **Deny rules** checked first — hard block, Claude sees your `reason` message 522. **Allow rules** checked next — auto-approved, no prompt 533. **No match** — passthrough to Claude Code's normal permission flow 54 55``` 56Claude tries tool → deny? → BLOCKED (with guidance) 57 → allow? → AUTO-APPROVED 58 → neither? → normal Claude Code prompt 59``` 60 61## Config 62 63Default location: `~/.config/chook.toml` (override with `--config`) 64 65### Deny rules 66 67```toml 68[[deny]] 69tool = "Bash" 70command_regex = "^rm .*-rf" 71reason = "Use rm on specific files, or ask the user to run this manually." 72 73[[deny]] 74tool = "Bash" 75command_regex = "&|;|\\||`|\\$\\(" 76reason = "BLOCKED: You MUST run exactly ONE command per Bash call." 77 78[[deny]] 79tool = "Read" 80file_path_regex = "\\.(env|secret|pem|key)$" 81reason = "Ask the user to provide the needed values." 82``` 83 84The `reason` string is shown to Claude, so write it as guidance for what to do instead. 85 86### Allow rules 87 88```toml 89# Auto-allow file ops in the project directory 90[[allow]] 91tool = "Read" 92restrict_to_cwd = true 93file_path_exclude_regex = "\\.\\." 94 95# Auto-allow /tmp 96[[allow]] 97tool = "Read" 98file_path_regex = "^/tmp/" 99 100# Auto-allow safe bash commands 101[[allow]] 102tool = "Bash" 103command_regex = "^git " 104command_exclude_regex = "push.*--force" 105 106# Auto-allow specific subagents 107[[allow]] 108tool = "Task" 109subagent_type = "Explore" 110``` 111 112### Rule fields 113 114| Field | Tools | Description | 115|---|---|---| 116| `tool` | all | Tool name to match (required) | 117| `reason` | all | Message shown to Claude on deny | 118| `restrict_to_cwd` | file tools | Restrict to the directory where Claude was started | 119| `file_path_regex` | Read, Write, Edit, Glob, NotebookEdit | Regex the file path must match | 120| `file_path_exclude_regex` | file tools | Regex that rejects the match | 121| `command_regex` | Bash | Regex the command must match | 122| `command_exclude_regex` | Bash | Regex that rejects the match | 123| `subagent_type` | Task | Exact match on subagent type | 124| `prompt_regex` | Task | Regex the prompt must match | 125| `prompt_exclude_regex` | Task | Regex that rejects the match | 126 127### Auditing 128 129```toml 130[audit] 131audit_file = "/tmp/chook-audit.json" 132audit_level = "matched" # off | matched | all 133``` 134 135## Commands 136 137### `chook run` 138 139Hook handler. Reads tool JSON from stdin, outputs permission decision to stdout. This is what Claude Code calls. 140 141### `chook post` 142 143PostToolUse handler. Cancels pending notifications when a tool completes. 144 145### `chook validate` 146 147Check your config for errors. 148 149``` 150$ chook validate 151Configuration is valid! 152 Deny rules: 5 153 Allow rules: 11 154 Audit file: /tmp/chook-audit.json 155 Audit level: matched 156``` 157 158### `chook review` 159 160Interactive TUI for reviewing denied/passthrough tool uses and adding rules. 161 162Entries are grouped into smart suggestions: 163- Bash commands grouped by command name (e.g. `git`, `npm`, `cargo`) 164- File operations grouped by project directory with `restrict_to_cwd` 165- Dangerous commands like `rm` get automatic `command_exclude_regex` for dangerous flags 166 167Navigate with `j`/`k`, press `a` to allow, `d` to deny, `s` to skip, `q` to quit. 168 169### `chook allow-last` 170 171Add an allow rule from the most recent audit entry. 172 173### `chook deny-last` 174 175Add a deny rule from the most recent audit entry. 176 177## Workflow 178 179The fast feedback loop when Claude gets blocked: 180 1811. Claude tries something, gets prompted or blocked 1822. `Ctrl-Z` to background Claude 1833. `chook allow-last` to allow it (or `chook review` to see all recent entries) 1844. `fg` to resume 185 186Rules are live immediately — the config is read on every hook invocation. 187 188## Notifications 189 190When a tool passes through to Claude's normal permission flow and Claude is waiting for your approval, a macOS notification fires after 15 seconds. This way you'll notice if you're in another window. The PostToolUse hook cancels the notification if the tool completes quickly (meaning it was auto-approved by Claude's own settings, not actually waiting). 191 192## Inspired by 193 194[claude-code-permissions-hook](https://github.com/kornysietsma/claude-code-permissions-hook) by Korny Sietsma — a Rust implementation of the same idea. chook is a JS port with added interactive review and notifications.