claude-code-permissions-hook
v1.2.0
Published
A PreToolUse hook for Claude Code that provides granular control over which tools Claude can use
Maintainers
Readme
Command Permissions Hook for Claude Code
A PreToolUse hook for Claude Code that provides granular control over which tools Claude can use, with support for allow/deny rules, pattern matching, and security exclusions.
NOTE: This is a workaround for current (December 2025) limitations in Claude Code permissions - setting Bash permissions doesn't work consistently. Built following Anthropic's hook guidelines.
This may be short-lived as Anthropic improves permissions.
Features
- All configuration is via a single JSON file - see example.json for an example
- Allow/deny rules with regex pattern matching for tool inputs
- Exclude patterns for handling edge cases (e.g., block
..in allowed paths) - Audit logging of tool use decisions to JSON file
Documentation
- Configuration Guide - How to write rules for each supported tool
- Tool Input Schemas - Reference for Claude Code tool input formats
Installation
npm install -g claude-code-permissions-hookOr use with npx:
npx claude-code-permissions-hook validate --config example.jsonConfiguration
Create a JSON configuration file (see example.json):
{
"audit": {
"audit_file": "/tmp/claude-tool-use.json",
"audit_level": "matched"
},
"allow": [
{
"tool": "Read",
"file_path_regex": "^/Users/korny/Dropbox/prj/.*",
"file_path_exclude_regex": "\\.\\."
},
{
"tool": "Bash",
"command_regex": "^cargo (build|test|check|clippy|fmt|run)",
"command_exclude_regex": "&|;|\\||`|\\$\\("
},
{
"tool": "Task",
"subagent_type": "codebase-analyzer"
}
],
"deny": [
{
"tool": "Bash",
"command_regex": "^rm .*-rf"
},
{
"tool": "Read",
"file_path_regex": "\\.(env|secret)$"
}
]
}Audit Levels
off- No auditingmatched(default) - Audit only tool use that hits a rule (allow/deny)all- Audit everything including passthrough
Claude Code Setup
Add to .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "npx claude-code-permissions-hook run --config ~/.config/claude-code-permissions-hook.json"
}
]
}
]
}
}Usage
Validate Configuration
npx claude-code-permissions-hook validate --config example.jsonRun as Hook (reads JSON from stdin)
echo '<hook-input-json>' | npx claude-code-permissions-hook run --config example.jsonRun Tests
npm testHow It Works
flowchart TB
Start@{shape: rounded, label: "Claude attempts<br/>tool use"}
ReadInput[Read JSON from stdin]
LoadConfig[Load & compile<br/>JSON config]
LogUse[Log tool use<br/>to file]
CheckDeny@{shape: diamond, label: "Deny rule<br/>matches?"}
CheckAllow@{shape: diamond, label: "Allow rule<br/>matches?"}
OutputDeny[Output deny decision<br/>to stdout]
OutputAllow[Output allow decision<br/>to stdout]
NoOutput[No output<br/>passthrough to<br/>Claude Code]
EndDeny@{shape: rounded, label: "Tool blocked"}
EndAllow@{shape: rounded, label: "Tool permitted"}
EndPass@{shape: rounded, label: "Normal permission<br/>flow"}
Start --> ReadInput
ReadInput --> LoadConfig
LoadConfig --> LogUse
LogUse --> CheckDeny
CheckDeny -->|Yes| OutputDeny
CheckDeny -->|No| CheckAllow
CheckAllow -->|Yes| OutputAllow
CheckAllow -->|No| NoOutput
OutputDeny --> EndDeny
OutputAllow --> EndAllow
NoOutput --> EndPass
classDef processStyle fill:#e0e7ff,stroke:#4338ca,color:#1e1b4b
classDef decisionStyle fill:#fef3c7,stroke:#d97706,color:#78350f
classDef denyStyle fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
classDef allowStyle fill:#d1fae5,stroke:#10b981,color:#064e3b
classDef passStyle fill:#f3f4f6,stroke:#6b7280,color:#1f2937
classDef startEndStyle fill:#ddd6fe,stroke:#7c3aed,color:#3b0764
class ReadInput,LoadConfig,LogUse processStyle
class CheckDeny,CheckAllow decisionStyle
class OutputDeny,EndDeny denyStyle
class OutputAllow,EndAllow allowStyle
class NoOutput,EndPass passStyle
class Start,StartEnd startEndStyleDeny rules are checked first (block), then allow rules (permit). No match = passthrough to normal Claude Code permissions.
See the Configuration Guide for detailed rule syntax and security patterns.
Programmatic Usage
You can also use this package as a library:
import {
processHookInput,
validateConfig,
loadAndCompileConfig,
processHookInputWithCompiledConfig,
} from 'claude-code-permissions-hook';
// Simple usage - load config and process input in one call
const result = processHookInput('/path/to/config.json', hookInput);
console.log(result.decision); // 'allow', 'deny', or 'passthrough'
console.log(result.reason); // reason string if matched
// For better performance when processing multiple inputs
const compiled = loadAndCompileConfig('/path/to/config.json');
const result1 = processHookInputWithCompiledConfig(compiled, input1);
const result2 = processHookInputWithCompiledConfig(compiled, input2);
// Validate a config file
const { denyCount, allowCount } = validateConfig('/path/to/config.json');Development
npm install # Install dependencies
npm run build # Build TypeScript
npm test # Run tests
npm run lint # Type checkLogging
Audit file (JSON): Records tool use to audit_file. Set audit_level to off, matched (default), or all.
Diagnostic log (stderr): Errors are written to stderr.
License
See LICENSE file for details.
