[DOCS] Clarify recursive vs. shallow globbing syntax for Read/Edit permission rules

Resolved 💬 3 comments Opened Jan 22, 2026 by coygeek Closed Jan 23, 2026

Documentation Type

Missing documentation (feature not documented)

Documentation Location

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, not Bash(*)."

What's Wrong or Missing?

There is an inconsistency that leads to security configuration errors.

  1. The documentation states file rules follow the gitignore specification. In gitignore syntax, a single asterisk * matches files in the current directory only—it does not match recursively into subdirectories. Recursive matching requires **.
  2. Users seeing Read(*) in the GitLab examples might assume this grants permission to read all files recursively. If gitignore rules are strictly followed, Read(*) would only allow reading files in the root directory, potentially breaking workflows that expect full access.
  3. The distinction between using Read (no parentheses, allows all) vs Read(*) (parentheses with glob, potentially shallow) vs Read(**) (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

  1. 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), per gitignore spec.
  • Tool(**) (e.g., Read(**)) is required for recursive matching within a specific scope.
  1. 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(*) and Edit(*) to Read and Edit (without parentheses) or Read(**) 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 match src/file.txt.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗