[DOCS] Clarify recursive vs. shallow globbing syntax for Read/Edit permission rules
Documentation Type
Missing documentation (feature not documented)
Documentation Location
- https://code.claude.com/docs/en/iam#tool-specific-permission-rules - https://code.claude.com/docs/en/settings#permission-rule-syntax - https://code.claude.com/docs/en/gitlab-ci-cd#quick-setup
Section/Topic
The "Permission rule syntax" and "Tool-specific permission rules" sections in IAM/Settings, specifically regarding how wildcard globs (* vs **) behave for File operations compared to Bash operations.
Current Documentation
In Identity and Access Management, the documentation states:
"Read & Edit rules both follow the gitignore specification with four distinct pattern types..."
In the GitLab CI/CD guide, the configuration example suggests:
--allowedTools "Bash(*) Read(*) Edit(*) Write(*) mcp__gitlab"
In Settings > Permission rule syntax, it clarifies regarding the whole tool:
"Bash(*)does not match all Bash commands. The*wildcard only matches within the specifier context. To allow or deny all uses of a tool, use just the tool name:Bash, notBash(*)."
What's Wrong or Missing?
There is an inconsistency that leads to security configuration errors.
- The documentation states file rules follow the
gitignorespecification. Ingitignoresyntax, a single asterisk*matches files in the current directory only—it does not match recursively into subdirectories. Recursive matching requires**. - Users seeing
Read(*)in the GitLab examples might assume this grants permission to read all files recursively. Ifgitignorerules are strictly followed,Read(*)would only allow reading files in the root directory, potentially breaking workflows that expect full access. - The distinction between using
Read(no parentheses, allows all) vsRead(*)(parentheses with glob, potentially shallow) vsRead(**)(recursive) is not explicitly defined for file tools, leading to confusion when users try to apply the logic described in the Bash section to File sections.
Suggested Improvement
- In the Settings > Permission rule syntax section, explicitly clarify that for file tools (
Read/Edit):
Tool(e.g.,Read) matches all uses.Tool(*)(e.g.,Read(*)) matches only files in the immediate directory (shallow), pergitignorespec.Tool(**)(e.g.,Read(**)) is required for recursive matching within a specific scope.
- Update the GitLab CI/CD and GitHub Actions examples. If the intention is to allow the bot to read/edit the whole repo, change
Read(*)andEdit(*)toReadandEdit(without parentheses) orRead(**)to ensure recursive access is actually granted.
Impact
High - Prevents users from using a feature
Additional Context
Users migrating from other tools often assume * is always recursive or behaves like a "match all" string. Since Claude Code enforces strict permission boundaries, a misunderstanding here results in the agent losing access to subdirectories or users unintentionally creating overly restrictive rules.
The specific confusion stems from:
- IAM Page:
Read(*.env)matches files in current dir. - IAM Page:
Read(src/**)matches recursively. - Implied:
Read(*)therefore likely does not matchsrc/file.txt.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗