Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Pattern Grammar

A pattern is the pattern field in a [[permissions.rules]] entry (or the argument to --allow/--deny/--ask on the CLI). It encodes the tool name and an optional argument specifier separated by a colon.

Forms at a glance

FormDescription
ToolMatch any invocation of Tool, regardless of arguments.
Tool:<glob>Match Tool when its first argument matches <glob>.
Bash:~<glob>Match Bash when <glob> appears anywhere in the command string.
Tool:key=<glob>Match Tool when the named input field matches <glob> (dotted keys supported).
Tool:k1=<g1>,k2=<g2>Multiple key=glob pairs, AND-combined.
*Catch-all — matches every tool.

Glob characters

The argument-side glob uses globset semantics:

CharacterMeaning
*Zero or more characters (does not cross / in path patterns).
**Zero or more path segments (crosses /; use in file-edit patterns).
?Exactly one character.

Non-path patterns (Bash command strings, URLs, MCP string fields) use literal_separator = false, so * matches slashes too.

Tool:<glob> — first-argument matching

The "first arg" is a per-tool field extracted from the JSON input:

ToolFirst-arg field
Bashcommand
Read, Write, Edit, MultiEdit, NotebookEditpath
WebFetchurl
MCP tools with no known accessor(no first arg; pattern can't match)

If the tool has no known accessor, only the bare Tool form can match; Tool:<glob> never fires for that tool.

Bash:~<glob> — anywhere-in-command match

Prefix the argument glob with ~ to perform a sliding-window search over the full command string rather than matching from the start. This catches commands invoked via wrappers or subshells:

# Deny any use of rm, even via sudo or bash -c "rm …"
[[permissions.rules]]
pattern = "Bash:~rm *"
action  = "deny"
reason  = "no rm — use git revert or Write"

The ~ prefix is only meaningful for Bash. On other tools it does not match.

Tool:key=<glob> — structured (dotted-key) matching

For MCP tools or built-ins whose input has named fields, use key=glob to match a specific field. Dots traverse nested objects:

# Allow creating GitHub issues only in the anthropic org
[[permissions.rules]]
pattern = "mcp__github__create_issue:repo=anthropic/*"
action  = "allow"

# AND-combined: repo must match AND title must start with "feat"
[[permissions.rules]]
pattern = "mcp__github__create_issue:repo=anthropic/*,title=feat*"
action  = "allow"

File-edit path normalization

For Read, Write, Edit, MultiEdit, and NotebookEdit, the file path in the tool call is workspace-normalized before pattern matching:

  • Absolute paths are used as-is.
  • Relative paths are resolved against the workspace root (the git rev-parse --show-toplevel result, or the current working directory when outside a repo).
  • A relative pattern like src/**/*.rs is automatically anchored with **/ so it matches at any depth under the repo.
# Allow editing any Markdown file anywhere in the repo
[[permissions.rules]]
pattern = "Edit:**/*.md"
action  = "allow"

# Allow editing files only in a specific directory (absolute path)
[[permissions.rules]]
pattern = "Write:/tmp/*"
action  = "allow"

Examples table

PatternMatchesDoes not match
BashAny Bash call
Bash:git *git push, git commit -m "…"gitk, sudo git push
Bash:~git *sudo git push, bash -c "git fetch"commands with no git substring
Bash:rm *rm -rf /tmpsudo rm -rf /tmp (use ~rm * for that)
Edit:**/*.rs/repo/src/main.rs, /repo/crates/x/lib.rs/tmp/scratch.py
Write:/tmp/*/tmp/out.txt/home/user/file.txt
WebFetch:https://docs.*https://docs.rs/…, https://docs.anthropic.com/…https://api.example.com/…
mcp__gh__create_issue:repo=acme/*{"repo":"acme/frontend"}{"repo":"other/repo"}
*Every tool

Unknown MCP tools

MCP tools that declare no known first-arg accessor can only be matched by their full name (mcp__server__tool_name) or the * catch-all. A pattern like mcp__server__tool_name:<glob> will never fire for such tools because there is no field to extract.