[Bug] Allow rules under `~/.claude/` show as loaded per /permissions but don't match at runtime

Open 💬 10 comments Opened May 8, 2026 by hwaterer

Summary

Allow rules in ~/.claude/settings.json that target paths under ~/.claude/
itself appear in /permissions as loaded but never match at runtime. Edits
to files in any subdirectory under ~/.claude/ prompt for permission
despite a matching rule being present and active.

Tested all four combinations of {tilde, absolute path} × {**/*.md glob,
literal path} for both Edit(...) and Update(...) scope-name forms —
none matched.

Reproducer

  1. Create a markdown file at ~/.claude/rules/test-rule.md (the rules/

subdirectory is the documented standard location for user rule files).

  1. Add to ~/.claude/settings.json:

``json
{
"permissions": {
"allow": [
"Edit(~/.claude/**/*.md)"
]
}
}
``

  1. Restart Claude Code, or run /hooks to force-reload settings.
  1. Verify with /permissions that the rule appears in the loaded allow list.
  1. Ask Claude Code to edit ~/.claude/rules/test-rule.md.

Expected (per docs): the Edit operation proceeds without a permission
prompt. The rule's gitignore-style ** matches the subdirectory, and the
docs explicitly state *"Edit rules apply to all built-in tools that edit
files."*

Actual: a permission prompt fires titled
Update(~/.claude/rules/test-rule.md). The rule is bypassed.

What was tested

Each rule below was added to ~/.claude/settings.json, settings reloaded
via /hooks, and /permissions confirmed each rule was loaded. None
matched the runtime edit attempt.

| Rule | Match? |
| ---------------------------------------------------------- | ------ |
| Edit(~/.claude/**/*.md) | No |
| Edit(//<absolute home>/.claude/**/*.md) | No |
| Update(~/.claude/**/*.md) | No |
| Update(//<absolute home>/.claude/**/*.md) | No |
| Update(~/.claude/rules/test-rule.md) (literal path) | No |
| Update(//<absolute home>/.claude/rules/test-rule.md) | No |

Notes

  • Auto-memory edits (under ~/.claude/projects/<encoded-slug>/memory/*.md)

are silent — they appear to have implicit allowlisting independent of the
~/.claude/** allow rules.

is documented as supported ("Path from home directory") and ** is
documented as recursive across directories.

  • The runtime prompt label uses Update(~/...) form, but /permissions

lists rules with whatever scope name (Edit or Update) was put in
settings.json. Update(...) rules with the same path patterns also
fail to match.

  • Whether project-level .claude/settings.local.json (e.g. with

defaultMode: "acceptEdits" and project-relative Edit(.claude/**))
interacts with user-global lookup is untested.

Environment

  • Claude Code: 2.1.133
  • OS: Linux x86_64

Impact

Users who store global rules, scripts, or skills under ~/.claude/ (a
documented and encouraged location) cannot allowlist edits to those files
without a permission prompt every time, despite writing rules that match
both the documented syntax and the gitignore-style spec.

View original on GitHub ↗

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