Bash wildcards — runtime test
Hands-on runtime battle-test of Bash wildcards. Result: PASS.
Wildcard pattern matching for Bash tool permissions allows commands to be allowed or blocked using * at any position in the rule, reducing permission fatigue without sacrificing control.
How It Works
The Bash tool permission system evaluates commands against patterns. A rule like Bash(npm *) matches the full command string with spaces significant. The wildcard can appear at three positions: as a prefix (* install), suffix (npm *), or in the middle (git * main), matching zero or more characters at that position.
What the Test Found
Three pattern types were tested on 7 January 2026:
- Prefix wildcard
Bash(npm *)allowednpm --versionwhile blockingpnpm --version. Pass. - Suffix wildcard
Bash(* install)allowedecho install. Pass. - Middle wildcard
Bash(git * main)permittedgit log main(permission validated; the command failed for unrelated reasons). Pass.
All tests passed. Wildcards work at any position. Patterns are applied to the complete command string, and spaces between tokens are significant. Commands with default permissions (like pwd, ls, echo) keep those defaults; wildcards add to the allowed list rather than replacing it.
Why It Matters
Without wildcards, a developer using npm install, npm run, npm test, and npm audit needed four separate permission entries or one per-command prompt. A single rule Bash(npm *) covers all of them, reducing prompt fatigue in interactive sessions. The rule remains explicit (patterns must be declared), so the security model is not weakened. Teams can express intent more directly: Bash(git *) for all git commands, Bash(docker-compose *) for orchestration, or Bash(* --help) for any help flag.
Mechanics
When a Bash command is submitted for execution, Claude Code compares it against the allowlist. If a rule matches the command string—either exactly or via wildcard—the command proceeds without prompting. Matching is positional: the wildcard matches the substring at that location. Commands like npm install --save-dev are matched by the pattern npm * because the leading substring npm is fixed and the * absorbs everything after. The pattern git * main requires git and main to be present with at least one token between them.
Test Results: Bash Wildcard Permissions
Feature: Added wildcard pattern matching for Bash tool permissions using * at any position in rules
Tested: 2026-01-07
Pattern Types Tested
1. Prefix Wildcard: Bash(npm *)
Test: Allow npm commands, block pnpm
claude -p "run both: 'npm --version' and 'pnpm --version'" --allowedTools "Bash(npm *)"
Result: PASS
npm --version→ ran successfully (10.9.3)pnpm --version→ needs approval (blocked)
2. Suffix Wildcard: Bash(* install)
Test: Allow any command ending with "install"
claude -p "run: echo install" --allowedTools "Bash(* install)"
Result: PASS
echo install→ ran successfully
3. Middle Wildcard: Bash(git * main)
Test: Allow git commands targeting main branch
claude -p "run: git log main" --allowedTools "Bash(git * main)"
Result: PASS
- Command was allowed (failed because no main branch, but permission worked)
Key Findings
Wildcards work at any position:
Bash(npm *)- prefix matchingBash(* install)- suffix matchingBash(git * main)- middle matching
Pattern is command-based:
- Matches the full command string
- Spaces are significant
npm *matchesnpm install,npm run, etc.
Combining with defaults:
- Some commands (pwd, ls, echo) may have default permissions
- Wildcards add to allowed list, don't replace it entirely
Use Cases
{
"permissions": {
"allow": [
"Bash(npm *)", // All npm commands
"Bash(git *)", // All git commands
"Bash(docker-compose *)", // All docker-compose
"Bash(* --help)", // Any help command
"Bash(* --version)" // Any version check
]
}
}
Implications
- Easier permission management - one rule covers many commands
- Less permission fatigue - fewer prompts for related commands
- Still secure - wildcards are explicit, not implicit
Status: PASS
Wildcard patterns work at prefix, suffix, and middle positions.
test_27d233e1ff71d893ee3d8bc2ed255199b87705613b1e2fd064d57fa75a6b679d2856ceafad6b1daa8f982493871b6dd4aefa4d4d7836de66cc11c9aaf1f522114005e37da4298cb7b541b2c0d5e8d9a97baa4175f8f757393e890c7faa2a9974984846a8b06836b23ee74c572614302Signed with an ed25519 key held off the repo. Anyone can verify against the published public key; nobody without the secret key can forge it. Click verify: it recomputes the signature in your browser. The signature proves integrity and authorship of this exact content — not a third-party timestamp or that the underlying claim is objectively true. signedAt is when the @f3/attest pipeline ran, not when the work happened; the evidence refs carry the source dates.
- verifies Bash wildcards Primitive