Glob reference

Capability rule patterns are globs, not regular expressions. Content guardrails take RE2; these do not.

The whole syntax

* matches any run of characters, including none. Every other character matches itself. The pattern is anchored at both ends.

PatternMatchesDoes not match
BashBashBashful, bash, BashOutput, run_Bash
mcp__github__*mcp__github__create_pull_request, mcp__github__mcp__githubx__y, mcp__gitlab__x
*__delete_*mcp__jira__delete_issuemcp__jira__create_issue
*everything in that family
a.ca.cabc
^Bash$a tool literally named ^Bash$Bash

Matching is case-sensitive for tools, MCP servers and skills, because wire names are: Bash and bash are two different tools to a provider, and folding them would let a rule written for one silently govern the other. Client names are already canonical lowercase, so the question does not arise.

Why not a regex

Content rules and capability rules are asking different questions, and the answer is different because of it.

A content rule matches against prose an attacker chose. You need alternation, character classes, quantifiers — the full engine, because the thing you are looking for has no fixed form.

A capability rule matches against a name from a fixed list. Someone typing Bash means exactly Bash. Under a regex:

  • Bash is unanchored, so it would also match Bashful and run_Bash_now.
  • . typed out of habit in mcp.github matches any character.
  • mcp__github__* is a valid regex meaning “mcp__github_ followed by any number of _”, which is neither what it says nor what anyone intended.

The last one is the dangerous case, because it compiles. A rule that stores cleanly, shows as enabled, and quietly matches nothing is the worst failure this product has, and the glob syntax removes that whole class of it for name lists.

An empty pattern is rejected at write time for the same reason: it would name nothing, and there is no reading of it that does something useful.

Porting from a regex

RegexGlob
^Bash$Bash
^mcp__github__mcp__github__*
delete*delete*
`^(BashRead)$`

There is no alternation. Write one rule per alternative — they cost nothing, and the resulting policy reads as a list of decisions rather than as one expression somebody has to parse.