Development marketplace for cc-allow bash permission control
npx claudepluginhub dannycoates/cc-allowBash command permission control for Claude Code
Permission control for Claude Code tools. Evaluates bash commands, file operations (Read/Write/Edit), search tools (Glob/Grep), and WebFetch URLs against configurable rules to allow, deny, or defer to Claude Code's permission system.
mvdan.cc/sh/v3/syntax for accurate bash parsing[bash], [read], [write], [edit], [glob], [grep], [webfetch])curl | bashcat /etc/passwd denied if /etc/** is in Read deny list)Bash is inherently dangerous. This tool isn't a substitute for your human judgement. Whatever you let your LLM run is your responsibility.
Add the marketplace:
/plugin marketplace add dannycoates/cc-allow
Install the plugin:
/plugin install cc-allow@dannycoates-cc-allow
The plugin automatically downloads binaries on first session start.
Download from releases or build from source:
go install github.com/dannycoates/cc-allow/cmd/cc-allow@latest
# Evaluate a bash command (default)
echo 'rm -rf /' | cc-allow
# Exit code: 2 (deny)
# Evaluate file tool permissions
echo '/etc/passwd' | cc-allow --read
echo '/project/src/main.go' | cc-allow --write
echo '/home/user/.bashrc' | cc-allow --edit
# Evaluate search tool permissions
echo '/etc' | cc-allow --glob
echo '/home/user/project' | cc-allow --grep
# Evaluate WebFetch URL permissions
echo 'https://example.com' | cc-allow --fetch
# With explicit config
echo 'ls -la' | cc-allow --config ./my-rules.toml
# Hook mode for Claude Code (reads JSON from stdin)
cc-allow --hook
# Validate and inspect config
cc-allow --fmt
/allow-rulesThe /allow-rules slash command provides a conversational interface for managing cc-allow rules. Tell it what you want in plain English and it figures out the right config changes.
The command determines where to write rules based on your phrasing:
| Scope | Keywords | Config file |
|---|---|---|
| Session (default) | "for now", "temporarily", or no scope mentioned | .config/cc-allow/sessions/<id>.toml |
| Project | "always", "permanently", "this project" | .config/cc-allow.toml |
| Global | "globally", "everywhere", "all projects" | ~/.config/cc-allow.toml |
# Session-scoped (default) — allow docker for this session
/allow-rules allow docker
# Session-scoped — temporary override
/allow-rules let me use curl for now
# Project-scoped — permanent rule
/allow-rules always allow npm install in this project
# Global — applies everywhere
/allow-rules globally deny rm -rf
# Deny rules
/allow-rules block curl | bash
# File tool rules
/allow-rules allow reading /var/log/**
# Complex rules
/allow-rules allow git push but ask for --force
The command reads the appropriate config, makes the change, validates with --fmt, and tests with a matching command to confirm.
| Code | Action | Meaning |
|---|---|---|
| 0 | allow | Command explicitly allowed |
| 1 | ask | Defer to Claude Code's permission system |
| 2 | deny | Command explicitly denied |
| 3 | error | Configuration or parse error |
Configs are loaded from multiple locations (loosest to strictest):
~/.config/cc-allow.toml - Global defaults<project>/.config/cc-allow.toml - Project rules (in source control)<project>/.config/cc-allow.local.toml - Local overrides (gitignored)<project>/.config/cc-allow/sessions/<id>.toml - Session-scoped (auto-cleaned)--config <path> - Explicit configRules are merged across configs: deny always wins, allow beats ask, ask means "no opinion."
version = "2.0"
[bash]
default = "ask"
dynamic_commands = "deny" # block $VAR or $(cmd) as command names
[bash.allow]
commands = ["ls", "cat", "grep", "git", "go", "npm"]
[bash.deny]
commands = ["sudo", "rm", "dd"]
message = "Dangerous command blocked"
More specific rules win regardless of order:
# Allow rm in general (specificity: 100)
[[bash.allow.rm]]