Edit permission glob ** pattern does not recursively match nested directories

Status Fixed / completed
Reported on v2.1.133
Maintainer reply None cached
Activity 6 comments · opened May 10, 2026 · closed May 10, 2026

Description

The ** glob pattern in Edit() permission rules (settings.json allow list) does not recursively match files in deeply nested subdirectories. This appears to be a regression -- the same configuration worked in earlier versions.

Reproduction

settings.json allow rule:

"Edit(/Users/me/.config/myproject/**)"

File being edited:

/Users/me/.config/myproject/worktrees/my-branch/scripts/db.py

Expected: Auto-approved (path is under the allowed ** pattern)
Actual: Prompts for user approval

Root cause hypothesis

Python's pathlib.PurePath.match() does not support ** for recursive directory matching the way POSIX glob or fnmatch do:

from pathlib import PurePath

path = PurePath('/Users/me/.config/myproject/worktrees/branch/scripts/file.py')

path.match('/Users/me/.config/myproject/**')        # False (unexpected)
path.match('/Users/me/.config/myproject/*/*/*/*')    # True

If Claude Code uses PurePath.match() to evaluate permission patterns, ** will silently fail to match files more than one level deep. fnmatch.fnmatch() handles ** correctly for this case.

Environment

  • Claude Code version: 2.1.133
  • OS: macOS (Darwin 25.4.0)
  • The pattern matches files directly in the allowed directory (1 level deep) but fails for 2+ levels of nesting.

Impact

Users with Edit(/path/**) allow rules get unexpected approval prompts for nested file edits. This affects git worktree workflows where files are several directories deep under the allowed root.

View original on GitHub ↗

6 Comments

github-actions[bot] · 3 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/6881
  2. https://github.com/anthropics/claude-code/issues/17213
  3. https://github.com/anthropics/claude-code/issues/43667

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

OliPetry · 3 months ago

Additional finding: The "Yes, allow all edits during this session" option (option 2 at the approval prompt) also does not suppress subsequent Edit prompts. Each new file edit in the same session still triggers an approval prompt, even after selecting the session-wide allow option.

This suggests the session-level allowance may be stored using the same pattern-matching logic that fails for deeply nested paths, or it's scoped per-file rather than globally.

Workaround status: No effective client-side workaround exists. Adding more ** segments to the pattern (e.g., Edit(/path/**/**/**)) does not help -- PurePath.match treats each ** as matching exactly one directory level, so no single pattern covers all depths.

OliPetry · 3 months ago

Escalation: deny rules for Edit/Write paths are also not enforced.

Test: added Edit(/Users/opetry/.ssh/*) to the deny list, then spawned claude -p --permission-mode dontAsk which successfully edited a file in ~/.ssh/. The deny rule was ignored.

This means:

  1. ** glob patterns don't work in allow/deny for Edit/Write (original report)
  2. Even single-level * patterns in deny rules for Edit/Write are not enforced

The only safe workaround is explicit * patterns at each depth level in the allow list (positive allowlist, not deny). Deny rules for Edit/Write appear to be completely non-functional for path-scoped patterns.

Current workaround: Replaced Edit(/path/**) with 6 explicit depth-level rules using * in the allow list:

Edit(/path/*)
Edit(/path/*/*)
Edit(/path/*/*/*)
Edit(/path/*/*/*/*)
Edit(/path/*/*/*/*/*)
Edit(/path/*/*/*/*/*/*)

This works but is fragile and verbose.

OliPetry · 3 months ago

Correction on deny rule finding: My earlier test claiming deny rules are broken was invalid. The spawned agent likely used a relative path for the Edit call, so the absolute-path deny pattern was never evaluated. After reverting to path-scoped allow rules, a second test showed the edit blocked, but that was the allow list doing its job (no matching allow rule), not a deny rule.

Net: we have no evidence that deny rules for Edit/Write are broken. The confirmed issue is still the original: ** glob patterns don't recursively match in allow (and presumably deny) rules. Single-level * patterns work when the path format (relative vs absolute) matches.

A second contributing factor: agents sometimes pass relative paths to Edit/Write despite the tool spec requiring absolute paths. When this happens, absolute-path permission patterns (allow or deny) don't match.

OliPetry · 3 months ago

Closing as duplicate of #6881.

github-actions[bot] · 2 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.