regex-permissions
A Claude Code plugin that lets you write permission rules using regex instead of wildcards.
Installation
Install permanently — inside Claude Code, run:
/plugin marketplace add amehmeto/regex-permissions
/plugin install regex-permissions@amehmeto-regex-permissions
Or try it for a single session:
git clone https://github.com/amehmeto/regex-permissions.git
claude --plugin-dir ./regex-permissions
Then add your rules under the regexPermissions key in .claude/settings.json or .claude/settings.local.json (project or global). See Configuration below.
Updating the Plugin
--plugin-dir loads directly from the source directory — no cache, changes apply on restart
- Marketplace installed (
@local-plugins) uses a cache in ~/.claude/plugins/cache/ — run /reload-plugins inside Claude Code to pick up updates without restarting
- If
/reload-plugins doesn't pick up changes, clear the cache manually: rm -rf ~/.claude/plugins/cache/local-plugins/regex-permissions and restart
Configuration
Add your regex rules under the regexPermissions key in your settings file. This key is separate from Claude Code's native permissions key — both can coexist without conflict. All four config files are loaded and merged additively.
{
"regexPermissions": {
"suggestOnPassthrough": true,
"deny": [
{ "rule": "Bash(^git\\s+push\\s+.*--force\\b(?!-))", "reason": "No force push" }
],
"ask": [
{ "rule": "Bash([;|&`$#])", "reason": "Shell metacharacters detected" }
],
"allow": [
"Bash(^\\S+\\s+--help$)",
"Bash(^git\\s+(status|log|diff|show|branch))",
"Glob|Grep(.*)"
]
}
}
See regex-permissions.example.json for a full annotated config.
Rule Syntax
Rules use the Tool(pattern) format — the tool name and content pattern are both regexes:
Tool name regex ──┐ ┌── Content regex
Bash(^git\\s+status)
String form — for most rules:
"Bash(^git\\s+push)"
Object form — when you need reason or flags:
{ "rule": "Bash(^git\\s+push)", "reason": "Confirm before pushing", "flags": "i" }
Tool-name-only form — omit parentheses to match any content. Useful for MCP and Skill tools where the plugin cannot inspect input fields:
{
"deny": [
{ "rule": "mcp__github__merge_pull_request", "reason": "No merge via MCP" }
],
"allow": [
"mcp__github__list_pulls",
"Glob|Grep|WebSearch"
]
}
The flags field applies to the content regex only (tool names are always case-sensitive).
Tool Matching
The tool name portion is an anchored regex — it must match the full tool name (^(?:...)$). Bash matches only Bash, not BashExecutor or MyBash. Use alternation for multiple tools:
"Edit|Write|Read(\\.(ts|js|py)$)"
The content pattern matches against the tool's primary field:
| Tool | Pattern matches |
|---|
| Bash | command |
| Edit/Write/Read | file_path |
| WebFetch | url |
| Grep/Glob | pattern |
| WebSearch | query |
| Other tools | First of: command, file_path, url, pattern, query |
Requiring Reasons
Enable requireReason to enforce that every rule includes a reason field. Rules without one (including all string-form rules) are silently skipped, falling through to native permissions.
{
"regexPermissions": {
"requireReason": true,
"deny": [
{ "rule": "Bash(^sudo)", "reason": "No sudo" }
],
"allow": [
{ "rule": "Bash(^git\\s+status)", "reason": "Read-only git" }
]
}
}
This is opt-in — when requireReason is not set or false, string rules and object rules without reason work normally. Skipped rules are visible with REGEX_PERMISSIONS_DEBUG=1.
If any of the four config files sets requireReason: true, it applies to all merged rules.
Suggesting Rules on Passthrough
Enable suggestOnPassthrough to get regex suggestions whenever a tool use doesn't match any rule. Instead of silently passing through to native permissions, the plugin returns ask with a suggested regex to add:
{
"regexPermissions": {
"suggestOnPassthrough": true,
"allow": ["Bash(^git\\s+status)"]
}
}
When you run docker compose up (no matching rule), the approval prompt includes:
No matching regex rule. Suggested: "Bash(^docker\s+compose\b)"
Suggestions are context-aware:
- Bash: extracts the command and subcommand, skips wrappers (
sudo, env, nohup, time) and env var assignments (FOO=bar)
- Edit/Write/Read: suggests a file extension pattern like
Edit(\.tsx$)
- WebFetch: suggests a domain-based pattern like
WebFetch(^https?://docs\.github\.com(/|$))
- MCP/unknown tools: suggests a tool-name-only rule
Guarding Native Permissions