A policy engine for Claude Code tool permissions. Define policies that automatically allow, deny, or prompt for each tool call.
Claude Code asks permission before running tools like Bash commands, file writes, etc. Toolgate lets you codify your permission preferences as composable policies — so git status is always allowed, destructive commands are always denied, and everything else prompts as normal.
// toolgate.config.ts — auto-allow curl to localhost
import { definePolicy, allow, next } from "toolgate";
import { safeBashCommand } from "toolgate/policies/parse-bash-ast";
export default definePolicy([
{
name: "Allow curl localhost",
description: "Permits curl commands targeting localhost",
handler: async (call) => {
const args = await safeBashCommand(call);
if (!args) return next();
if (args[0] === "curl" && args.some((a) => /^https?:\/\/localhost/.test(a))) {
return allow();
}
return next();
},
},
]);bun install -g toolgate# Register the PreToolUse hook globally
toolgate init
# Optionally, create a project-specific config
toolgate init --projectThis registers a PreToolUse hook in ~/.claude/settings.json. Toolgate ships with 50 built-in policies that are always active.
Optionally add project-specific policies in toolgate.config.ts (project root or .claude/). These run before built-in policies:
import { definePolicy, deny, next } from "toolgate";
export default definePolicy([
{
name: "Deny dangerous commands",
description: "Blocks rm -rf",
handler: async (call) => {
if (call.tool === "Bash" && call.args.command?.includes("rm -rf")) {
return deny("Destructive command blocked");
}
return next();
},
},
]);Project policies run first, then built-in. The first non-next() verdict wins.
A policy is an object with name, description, and an async handler function:
import { allow, deny, next, type Policy } from "toolgate";
const denyRmRf: Policy = {
name: "Deny rm -rf",
description: "Blocks destructive rm -rf commands",
handler: async (call) => {
if (call.tool !== "Bash") return next();
if (call.args.command?.includes("rm -rf")) {
return deny("Destructive command blocked");
}
return next();
},
};
export default denyRmRf;| Verdict | Effect |
|---|---|
allow() |
Permit the tool call silently |
deny(reason?) |
Block the tool call |
next() |
No opinion — pass to next policy (or prompt user if none remain) |
Each policy handler receives a ToolCall with:
tool— tool name ("Bash","Read","Write","Edit", etc.)args— tool arguments (e.g.{ command: "git status" }for Bash)context.cwd— working directorycontext.projectRoot— git repository root (ornull)context.env— environment variables
When writing policies for Bash commands, don't parse raw strings with regex — use the AST-based utilities from policies/parse-bash-ast.ts instead. They use shfmt --tojson under the hood and reject unsafe patterns (substitution, chaining, background, unsafe redirects) at the AST level.
import { safeBashCommand } from "toolgate/policies/parse-bash-ast";
import { allow, next, type Policy } from "toolgate";
const allowMake: Policy = {
name: "Allow make",
description: "Permits simple make commands",
handler: async (call) => {
const tokens = await safeBashCommand(call);
if (!tokens) return next();
if (tokens[0] === "make") return allow();
return next();
},
};Parses a Bash tool call into a flat string[] of tokens. Returns null if the command contains pipes, shell operators (&&, ||, ;, &), command substitution, unsafe redirects, or multiple statements. Use this for simple, single-command policies.
Like safeBashCommand, but allows pipes to safe filters. Returns string[] — the tokens of the first command only (filter safety is validated automatically). Returns null for non-pipe operators or unsafe patterns. Use this when you need to allow commands like git log | head.
import { safeBashCommandOrPipeline } from "toolgate/policies/parse-bash-ast";
const tokens = await safeBashCommandOrPipeline(call);
if (!tokens) return next();
if (tokens[0] === "git") return allow();Returns true if a token array is a safe pipe filter — a command that only reads stdin and writes stdout. Safe filters: grep, egrep, fgrep, head, tail, wc, cat, tr, cut, sort (without -o), uniq.
Returns the git repository root for the given directory, or null if not in a repo. Exported from toolgate/utils.
See policies/allow-git-add.ts for a full hardened example.
# Dry-run a tool call against your policies
toolgate test Bash '{"command": "git add ."}'
# → ALLOW
# Show which policy matched and why
toolgate test --why Bash '{"command": "git add ."}'
# → ALLOW
# why: Allow git add (index 4)
# description: Permits git add commands, optionally piped through safe filters
# List all loaded policies
toolgate list
# Audit settings.local.json against policies
toolgate audit
toolgate audit --json
# Temporarily suspend all policies (Ctrl+C to resume)
toolgate suspendToolgate ships with 50 built-in policies organized in three tiers. Order matters — first non-next() verdict wins.
| Policy | Description |
|---|---|
deny-git-add-and-commit |
Blocks compound git add+commit, forcing separate steps |
deny-writes-outside-project |
Blocks writes, redirects, cp/mv/install targeting paths outside the project |
deny-git-dash-c |
Blocks git -C configuration injection |
deny-bash-grep |
Rejects grep/rg in Bash — use the built-in Grep tool instead |
deny-cd-chained |
Blocks cd chained with other commands |
deny-git-chained |
Blocks git commands chained with non-git commands |
deny-gh-heredoc |
Prevents heredoc/command substitution in gh/git commands |
| Policy | Description |
|---|---|
redirect-plans-to-project |
Blocks plan writes to ~/.claude/plans/ and suggests project docs/ instead |
Git & GitHub
| Policy | Description |
|---|---|
allow-git-add |
Permits git add with safe arguments |
allow-git-diff |
Permits git diff, optionally piped through safe filters |
allow-git-log |
Permits git log and git show, optionally piped |
allow-git-status |
Permits git status, optionally piped |
allow-git-branch |
Permits read-only git branch commands |
allow-git-checkout-b |
Permits git checkout -b / git switch -c |
allow-git-stash |
Permits safe git stash operations |
allow-git-worktree |
Permits git worktree add/list/move/remove/prune |
allow-git-check-ignore |
Permits git check-ignore |
allow-git-rev-parse |
Permits git rev-parse |
allow-git-local-repo |
Permits git commands in local repos |
allow-gh-read-only |
Permits read-only gh CLI commands (view, list, diff, checks, search) |
File Operations
| Policy | Description |
|---|---|
allow-read-in-project |
Permits Read tool for files within project root |
allow-edit-in-project |
Permits Edit, Write, Update for files in project (except sensitive files) |
allow-grep-in-project |
Permits Grep tool within project root |
allow-search-in-project |
Permits Search and Glob within project root |
allow-find-in-project |
Permits Find tool within project root |
allow-mkdir-in-project |
Permits mkdir within project root |
Bash & Shell
| Policy | Description |
|---|---|
allow-bun-test |
Permits bun test, optionally piped |
allow-bash-find-in-project |
Permits find commands within project root |
allow-ls-in-project |
Permits ls within project root |
allow-cd-in-project |
Permits cd within project root |
allow-safe-read-commands |
Permits read-only commands (cat, head, tail, wc, etc.) in project |
allow-pure-and-chains |
Auto-allows && chains where every segment is independently safe |
allow-rm-project-tmp |
Permits rm in project tmp/ directories |
allow-sleep |
Permits sleep with numeric duration |
allow-read-plugin-cache |
Permits reads from plugin cache directories |
Claude Code Tools
| Policy | Description |
|---|---|
allow-explore-in-project |
Permits Explore agent within project root |
allow-plan-in-project |
Permits Plan tool within project root |
allow-agent |
Permits Agent subagent invocations |
allow-task-crud |
Permits Task tool calls (create, update, list, get) |
allow-task-create |
Permits TaskCreate tool calls |
allow-cron-crud |
Permits CronCreate, CronDelete, CronList |
allow-ask-user |
Permits AskUserQuestion |
allow-plan-mode |
Permits EnterPlanMode and ExitPlanMode |
allow-tool-search |
Permits ToolSearch |
allow-superpowers-skills |
Permits superpowers skill invocations |
Web & MCP
| Policy | Description |
|---|---|
allow-web-fetch |
Permits all WebFetch tool calls |
allow-web-search |
Permits all WebSearch tool calls |
allow-webfetch-claude |
Permits WebFetch to claude.com and subdomains |
allow-mcp-context7 |
Permits Context7 documentation lookup calls |
allow-mcp-ide-diagnostics |
Permits IDE diagnostics tool calls |
MIT