[BUG] settings.local.json allow not working - keeps asking and wanting to add existing items again

Open 💬 42 comments Opened Aug 30, 2025 by tonydehnke
💡 Likely answer: A maintainer (bogini, collaborator) responded on this thread — see the highlighted reply below.

Environment

  • Platform (select one):
  • [ ] Anthropic API
  • [ ] AWS Bedrock
  • [ ] Google Vertex AI
  • [x] Other: Claude Code on MacOS in VS Code
  • Claude CLI version: 1.0.98 (Claude Code)
  • Operating System: MacOS 15.6.1 (24G90)
  • Terminal: Apple Terminal

Bug Description

Claude Code keeps asking permission to run commands already saved in the settings.local.json file, even suggesting to add allow again with the exact same format. Have rebooted etc, same result. Happen across multiple commands.

Steps to Reproduce

Get Claude Code to do an action, it will ask permission to do things that are in the allow section already.

Expected Behavior

Don't ask to do things that are covered in the settings allow section

Actual Behavior

Keeps asking for permission, despite it being pre-approved

Additional Context

!Image

This was reported before, but closed without resolution:
ttps://github.com/anthropics/claude-code/issues/2560

View original on GitHub ↗

42 Comments

github-actions[bot] · 10 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/819
  2. https://github.com/anthropics/claude-code/issues/2560
  3. https://github.com/anthropics/claude-code/issues/5140

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

luck02 · 10 months ago

Looks like a widespread issue, having the same thing on Fedora Linux 42 / vscode, after asking me for the same read permission on the same directory 4x I had this in my settings.json

{
  "permissions": {
    "allow": [
      "Read(/home/garylucas/.local/share/Steam/steamapps/common/Avorion/Documentation/**)",
      "Read(/home/garylucas/.local/share/Steam/steamapps/common/Avorion/Documentation/**)",
      "Read(/home/garylucas/.local/share/Steam/steamapps/common/Avorion/Documentation/**)",
      "Read(/home/garylucas/.local/share/Steam/steamapps/common/Avorion/Documentation/**)"
    ],
    "deny": [],
    "ask": []
  }
}
ZivBA · 10 months ago

Not sure in which of the many identical issues to put this, so I'm hoping someone catches it here:
I believe the issue stems from inconsistent expansion of the ~ sign (home folder).
Sometimes Claude will try to read from the relative path (~/someFolder), and when you approve the action, the actual permission written to the settings will be "Read(/home/<username>/someFolder/**)"
But when Claude tries again to read from ~/someFolder, it will not match the rule in the settings JSON.
Manually adding the relative path (as ~/someFolder) to permissions (from Claude /permissions or directly to settings json) will resolve the issue.

I believe a proper solution would be for claude to identify home-folder paths, and add both the relative and absolute paths to the 'allowed' list, so both versions will work (or for Claude to always expand homefolder paths behind the scenes?)

bogini collaborator · 10 months ago

Hey @tonydehnke! I think you're encountering this because of wrong path format in your permissions. See https://docs.anthropic.com/en/docs/claude-code/iam#tool-specific-permission-rules.

The fix: Use // for absolute paths on macOS:

// Instead of this:
"Read (/Users/tdehnke/.agent-os/**)",

// Use this:
"Read (//Users/tdehnke/.agent-os/**)",

Quick cheat sheet:

  • //path → absolute path (use for /Users/...)
  • ~/path → from home directory
  • /path → relative to settings file (this is what's tripping you up)

Update your settings.local.json with the double slashes and the repeated prompts should stop immediately.

ryan-williams · 10 months ago

Thanks @bogini, but claude itself is adding these incorrect lines (see more examples in #7015).

Update: I'm also not seeing the manual fix (two leading slashes) have any effect, I'm still getting prompted for reads that should be covered by them.

trungkien2003ntk · 10 months ago

I don't know if anyone met this, auto accept edit also not working with Claude Code version 1.0.103 this morning

zipyo · 10 months ago

I have a same problem too.

An-u-rag · 10 months ago

I have randomly started experiencing this today too. If you are running CC on windows, you can try referencing your path for the permission this way:

"Read(RelativePath/to/someFolder/)",
"Edit(RelativePath/to/someFolder/
)",

However, I think this underlines a bigger issue with the CC startup. It seems to somehow lose the linkage when restarted even within the same home directory of the codebase. Not sure why.

Edit: Obviously downgrading will fix the issue, but my answer is for people who want to have access to the latest CC version and new features.

liuzhenjluccst · 10 months ago
Hey @tonydehnke! I think you're encountering this because of wrong path format in your permissions. See https://docs.anthropic.com/en/docs/claude-code/iam#tool-specific-permission-rules. The fix: Use // for absolute paths on macOS: // Instead of this: "Read (/Users/tdehnke/.agent-os/)", // Use this: "Read (//Users/tdehnke/.agent-os/)", Quick cheat sheet: //path → absolute path (use for /Users/...) ~/path → from home directory * /path → relative to settings file (this is what's tripping you up) Update your settings.local.json with the double slashes and the repeated prompts should stop immediately.

worked for me thks very much!

And anyone can try this:
Read(**)

danilo-01 · 10 months ago
Not sure in which of the many identical issues to put this, so I'm hoping someone catches it here: I believe the issue stems from inconsistent expansion of the ~ sign (home folder). Sometimes Claude will try to read from the relative path (~/someFolder), and when you approve the action, the actual permission written to the settings will be "Read(/home//someFolder/**)" But when Claude tries again to read from ~/someFolder, it will not match the rule in the settings JSON. Manually adding the relative path (as ~/someFolder) to permissions (from Claude /permissions or directly to settings json) will resolve the issue. I believe a proper solution would be for claude to identify home-folder paths, and add both the relative and absolute paths to the 'allowed' list, so both versions will work (or for Claude to _always_ expand homefolder paths behind the scenes?)

Yes this worked!

I put this in my workspaces .claude folder

.claude/settings.local.json

{
  "permissions": {
    "allow": [
      "Read(./**)"
    ]
  }
}
janosmathe · 10 months ago

Non of the recommended workaround work for me on Windows. I tried

  • "Read(**)"
  • "Read(~/**)"
  • "Read(./**)"
  • "Read(/../**)"
  • "Read(/.\\../**)"
trungkien2003ntk · 10 months ago
Non of the recommended workaround work for me on Windows. I tried "Read(*)" "Read(~/*)" "Read(./*)" "Read(/../*)" "Read(/.\../*)"

Have you updated your Claude Code yet? the issue was already resolved in newest version.

roverby-inmar · 10 months ago
Have you updated your Claude Code yet? the issue was already resolved in newest version.

I'm on the latest version and still have these problems. #7207

vhardy · 9 months ago

For what it is worth, I was not able to get the simpler permissions matching to work with the prefix matching either, i.e., the issue discussed here. However, I was able to use a hook to filter my 'grunt test:*' content.

If that helps, here is the configuration I used:

settings.json

Added the following:

"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/grunt_test_hook.sh",
"timeout": 30
}
]
}
]
}

and my script:

#!/usr/bin/env bash
set -euo pipefail

Read JSON from stdin

input="$(cat)"

tool_name="$(jq -r '.tool_name // ""' <<<"$input")"
cmd="$(jq -r '.tool_input.command // ""' <<<"$input")"

Only handle Bash tool

if [[ "$tool_name" == "Bash" && "$cmd" == grunt\ test* ]]; then
cat <<'JSON'
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "Auto-allowing grunt test*"
}
}
JSON
else
# Do nothing; normal permission system applies
echo "{}"
fi

The relevant documentation: https://docs.claude.com/en/docs/claude-code/hooks and https://docs.claude.com/en/docs/claude-code/hooks-guide.

keithdan · 9 months ago

I'm experiencing what appears to be a related issue with permissions being overridden. I have explicit "ask" permissions configured in my .claude/settings.local.json for git operations:
"ask": [
"Bash(git add*)",
"Bash(git commit*)",
"Bash(git push*)"
]
However, Claude is executing git add and git commit commands without requesting approval. When I asked Claude what permissions it sees in its system instructions, it reported having Bash(git add:) (with a colon) in the allow list, despite this not being present in my settings file. This suggests either: 1) a pattern-matching issue where git add in my "ask" list doesn't match git add:* that the system is checking against, or 2) permissions are being cached/inherited from a previous session. This occurred in a "continued conversation" (a session resumed after a previous conversation ran out of context). It's possible that continued conversations are inheriting old permissions from prior sessions rather than reloading the current settings file. This is a critical issue since it allows Claude to modify git repository state without user consent, completely bypassing explicitly configured permission guards. The expected behavior is that any "ask" permission should always require user approval, regardless of pattern variations or session continuation.

vhardy · 9 months ago

@keithdan it may be a typo in your message, but it reads "Bash(git add)",and it should be "Bash(git add:)", with the semicolon. I noticed that typos in the config file make the whole config be silently ignored.

ytzhakov · 8 months ago

any update on this issue?
calude 2.0.27 STILL ignores settings.local.json allow permissions. it keeps asking and (sometimes) adding the commands to the list (when I hit "2") but completely ignores them

vhardy · 8 months ago

@ytzhakov Not sure if this helps, but it took me a while to realize that errors in settings files do not cause errors on claude start up, but if you invoke the /status command, you will see if there is an error in the file. For example, you'll see something like:

System Diagnostics
⚠ Found invalid settings files: <your-code-repo-directory>/.claude/settings.json. They will be ignored.

This can give the sense that settings are ignored, where in fact, it may be due to a typo. I have found these hard to debug because the error message is not specific about the error, but I was able to fix the issue.

ytzhakov · 8 months ago

@vhardy this is what status shows at the bottom:
System Diagnostics
⚠ Found invalid settings files: . They will be ignored.

im not sure what it means because there is no file name. Additionaly, calude itself adds the "allow" permissions to settings.local.json when I hit "2" (always allow....).
I've tried removing all permissions and let calude add them on its own again - same issue.
it just wouldnt honor these settings. I tried using wildcards as well, for example:
"Bash(MSYS_NO_PATHCONV=1 \"C:/Program Files/Microsoft Visual Studio/2022/Enterprise/MSBuild/Current/Bin/MSBuild.exe\":*)",
"Bash(MSYS_NO_PATHCONV=1 \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\MSBuild\\Current\\Bin\\MSBuild.exe\":*)",

nothing seems to work. it just keeps asking me every time it wants to build the project

arnonmoscona · 8 months ago

Detailed Investigation Report: Permissions Ignored Despite Explicit Configuration

### Environment

  • Claude Code Version: 2.0.34
  • Platform: macOS (Darwin 22.6.0)
  • Project: Local project with .claude/settings.local.json

### Problem Statement
Claude Code repeatedly requests permissions for actions explicitly allowed in .claude/settings.local.json, including:

  • Bash commands: uv run ruff check, uv run ruff format, uv run python -m py_compile
  • MCP tools: mcp__basic-memory__edit_note, mcp__basic-memory__write_note, etc.

All of these permissions were explicitly listed in the permissions.allow array.

### Investigation Steps

#### Theory 1: Path Format Issue (Single vs Double Slash)
Based on issue #6850 and #6881, we hypothesized that absolute paths needed double slashes (//) on macOS.

Changes Made:
```
// Before
"Read(/Users/arnon/projects/**)"
"Bash(/Users/arnon/bin/send_text:*)"

// After
"Read(//Users/arnon/projects/**)"
"Bash(//Users/arnon/bin/send_text:*)"

Result: ❌ Failed - Still requested permissions

Test Method: Fresh Claude instance, asked to run uv run ruff check on a file
Outcome: Permission prompt appeared despite pattern being in allow list

Theory 2: Wildcard Syntax Issue (Colon vs Space)

Based on issue #819, we hypothesized that command:* syntax doesn't match space-separated arguments.

Changes Made:
// Before
"Bash(uv run ruff check:*)"
"Bash(uv run ruff format:*)"

// After
"Bash(uv run ruff *)"

Result: ❌ Failed - Still requested permissions

Test Method: New Claude instance after configuration change
Outcome: Still prompted for permission to run uv run ruff check bin/checked_bash.py

Theory 3: Configuration File Corruption

Rolled back .claude/settings.local.json to a known-good version from Oct 27 (commit a079a14) using git.

Result: ❌ Failed - Still requested permissions with old configuration

Test Method: Fresh Claude instance with rolled-back configuration
Outcome: Permissions still requested, ruling out configuration file as the cause

Evidence of Core Bug

  1. MCP Tool Permissions Ignored:
  • Tool mcp__basic-memory__edit_note explicitly listed on line 40 of settings
  • Claude still prompted: "Do you want to proceed? ... for basic-memory - edit_note commands"
  • No wildcards, no paths, exact string match - still failed
  1. Fresh Instance Behavior:
  • Problem occurs in brand new Claude instances running for <10 seconds
  • Rules out issues from #10028 about periodic clearing after hours of use
  • Indicates permission matching is broken at initialization
  1. Pattern Independence:
  • Failed with single slash paths
  • Failed with double slash paths
  • Failed with colon wildcards
  • Failed with space wildcards
  • Failed with exact MCP tool names (no wildcards at all)

Verification Steps Taken

# Verified settings file exists and contains permissions
$ grep -n "edit_note" .claude/settings.local.json
39: "mcp__basic-memory__edit_note",

# Verified only one settings file in project
$ ls -la .claude/settings*.json
-rw-r--r--@ 1 arnon staff 2845 Nov 6 12:09 .claude/settings.local.json

# Tested with git history
$ git log --oneline -- .claude/settings.local.json
ffe4d62 FLO-72: Add customers table page with sortable columns
99fa209 FLO-72: Implement users table page infrastructure
a079a14 FLO-72: prep for implementing table pages

# Rolled back and tested
$ git checkout a079a14 -- .claude/settings.local.json
# Result: Still prompted for permissions

Screenshot Evidence

Permission prompt appeared for uv run ruff check bin/checked_bash.py despite:

  • Settings containing "Bash(uv run ruff check:)" (later changed to "Bash(uv run ruff )")
  • Fresh Claude instance
  • File explicitly shown in working directory

Conclusion

The permission system in Claude Code 2.0.34 does not read or respect .claude/settings.local.json at all, or the pattern matching is completely broken for all pattern types.

This is not caused by:

  • Path format (single vs double slash)
  • Wildcard syntax (colon vs space)
  • Configuration file corruption
  • Duplicate entries
  • Periodic clearing (happens immediately)

This appears to be a fundamental bug in the permission system initialization or matching logic affecting:

  • All Bash command patterns
  • All MCP tool permissions
  • Both wildcard and exact-match patterns

The system prompts for permissions on every fresh instance regardless of configuration, making the settings file effectively non-functional.

Reproducibility

100% reproducible on every fresh Claude Code instance with any configuration pattern tested.
```

arnonmoscona · 8 months ago

This critical security bug has been open for 3 months with no progress. Permission system is completely non-functional in v2.0.34. Escalating to
security@anthropic.com and support@anthropic.com

amcdavid · 8 months ago
@vhardy this is what status shows at the bottom: System Diagnostics ⚠ Found invalid settings files: . They will be ignored.

I just encountered this -- I had an old-style hook in settings.json, which was deprecated (without any warning 😧 ) in 2.0.32. This caused the entire settings.json to be ignored-- I guess not technically "silently" since there is a brief message on startup. But that's a pretty dangerous failure mechanism, since it means that upon an upgrade, suddenly project-wide guardrails will be dropped.

pzgz · 7 months ago
This critical security bug has been open for 3 months with no progress. Permission system is completely non-functional in v2.0.34. Escalating to [security@anthropic.com](mailto:security@anthropic.com) and [support@anthropic.com](mailto:support@anthropic.com)

Now with v2.0.50, the issue is still there, cannot believe that, the issue was there since day one of v2, it just cannot be fixed?

andmanea · 7 months ago

Still an issue. I feel like this should be THE top priority issue. The permission system basically does not work for me. I can't leave it unattended for more than 15 seconds...

tonydehnke · 7 months ago

One thing I'm finding is if there is an error in setting.local.json, claude keeps trying and asking permission. It would be much better if it said "There is an error in the permissions file, would you like me to fix it, fix it yourself, or fix later".

rupurt · 6 months ago

Also running into this on Linux

lucamarchionna · 6 months ago

Three months and still the same problem? That's weird!

lucamarchionna · 6 months ago

Workaround: use PermissionRequest hook
I had problems with the Read operation on some files.
Since Read permissions in settings.json are ignored despite correct configuration, I used a PermissionRequest hook to auto-approve Read operations.

For VS Code

  1. Create _~/.claude/hooks/allow-read.sh_
#!/bin/bash
printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
  1. and add to _.claude/settings.local.json_ or _claude/settings.json_

```
"hooks": {
"PreToolUse": [
{
"matcher": "Read",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/allow-read.sh"
}
]
}
]
}



3. Make executable: `chmod +x ~/.claude/hooks/allow-read.sh`


### For CLI
1. Create _~/.claude/hooks/allow-read.sh_ 

#!/bin/bash
echo '{"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}}'
exit 0



2. and add to _.claude/settings.local.json_ or _claude/settings.json_ 

"hooks": {
"PermissionRequest": [
{
"matcher": "Read",
"hooks": [
{"type": "command", "command": "~/.claude/hooks/allow-read.sh"}
]
}
]
}


3. Make executable: `chmod +x ~/.claude/hooks/allow-read.sh
`





You can also use the CLI to configure hooks. This bypasses the broken permissions system.

Hope this helps the community,
Luca
maxres-ch · 6 months ago

This is driving me crazy. I'm having issues w/ it on linux and macos.

sumit-kumar2002 · 6 months ago

The disconnect between documented behavior and actual behavior suggests the permission system wasn't tested against the documented spec. A TDD approach where tests validate the documented patterns would catch these gaps.

Specific issues encountered:

  • Read(), Read(~/), Read(/home/**) in both ~/.claude/settings.json and ~/.claude/settings.local.json - still prompts
  • Same files correctly apply sandbox.enabled: false
  • No managed-settings.json overriding

This inconsistency makes it nearly impossible to configure Claude Code reliably without --dangerously-skip-permissions.

flaxinger · 6 months ago

It's 2026 and we're still having issue.
If this is the quality of the AI product that writes code for me, I don't know how you expect us to trust the code it's writing. (not that I trust it at all in the first place)

jwhartley · 6 months ago

Confirming Solution from #6881

After extensive debugging, I can confirm @bogini's solution works:

The Fix

Use double-slash // for absolute paths in settings.json or settings.local.json:

{
  "permissions": {
    "allow": [
      "Read(//Users/username/**)",
      "Write(//Users/username/projects/**)",
      "Edit(//Users/username/projects/**)"
    ],
    "deny": [
      "Edit(//Users/username/.ssh/**)"
    ]
  }
}

Why Single-Slash Fails

| Format | Interpretation |
|--------|----------------|
| /Users/james/** | Relative to settings file (WRONG) |
| //Users/james/** | Absolute filesystem path (CORRECT) |
| ~/projects/** | Home directory expansion (CORRECT) |

Additional Finding

Path-restricted Bash commands also fail: Bash(rm:/tmp/**) doesn't match rm /tmp/file.txt. Use wildcards instead: Bash(rm:*) with appropriate deny rules.

Recommendation

Claude Code should either:

  1. Auto-generate the correct // format when users accept permission prompts, OR
  2. Document this prominently in error messages

Currently Claude generates single-slash paths which perpetuates the problem.

brian-compass · 6 months ago

This is still not working, especially with Tasks. Asking Claude to fix the permissions issue, or even simply add * under alwaysApproveToolUsePatterns permissions and normal permissions, does not help.

arnonmoscona · 5 months ago

Got tired of waiting for fixes. Created https://github.com/arnonmoscona/toolguard as an enhanced drop-in replacement to the native permissions system using hooks. As far as I can tell it is syntax-compatible, but it has more features and allows also new matching patterns. The simplest setup is just to setup the hook as documented, but you can go far beyond if you want. I will add a new feature soon to overcome some of the annoying behaviors I find around permissions.

I'd welcome any feedback, comments, PRs. This is new, to treat it carefully. "works on my machine" is not really good enough, but I am one guy with one machine. So there's that...

donny-virgo · 5 months ago

Why is this bug still open and having duplicates filed? There are two issues:

  1. Claude Code does not understand its own config file, and this breaks users' expectations (no judgement here)
  2. Unix users consistently do not read the documentation regarding rooted path syntax (no judgement here either)

1 cannot be fixed as the input requires natural language processing and there is no way to ensure users don't want the edits made since it is valid syntax
2 can only be fixed by a specification change - for example, switching from "Read(customgitignoreglob)" syntax to "Read[gitignoreglob]" or Read.unix(unixglob) etc.

1 will receive new duplicate bugs and should be closed with WONTFIX and a friendly reminder to read the opening claude disclaimer "Claude can make mistakes" before using the tool or expect consequences.
2 may depend on an analysis of how many bug reports/upvotes this problem receives

Jensimogit · 4 months ago

Additional reproduction: Linux CLI, Glob + Read affected, symlink paths

Environment: Claude Code CLI v2.1.50, Debian Linux, working directory /opt/projects/

Allow rules on both global and project level:

"Read(/opt/projects/**)",
"Glob(/opt/projects/**)",
"Read(/export/data/docs/**)",
"Glob(/export/data/docs/**)",
"Glob(/export/data/docs/*)",
"Glob(/export/data/docs/**/*)"

Affected tools:

  • Glob(pattern: "INDEX.md", path: "/export/data/docs")prompts for permission
  • Read("/home/jens/.claude/CLAUDE.md")prompts for permission
  • Bash(git -C /export/data/docs status) → works fine ✅

Notes:

  • /opt/projects/docs is a symlink → /export/data/docs, rules exist for both paths
  • The issue is not symlink-specific: Read on /home/jens/.claude/CLAUDE.md also prompts despite matching rules (no symlink involved)
  • Inconsistent: in the same session, some tools are auto-approved while others with identical path patterns are not
  • Closed #27614 as duplicate of this issue
arcivanov · 4 months ago

This is very annoying and still present even in 2.1.71

Simplereally · 4 months ago

How is this still an issue? Vibe coded slop

yurukusa · 3 months ago

The allow list in settings.local.json has known pattern-matching limitations (see #30519 for the full catalogue). The most reliable workaround is a PreToolUse hook that implements your own allow logic:

INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$COMMAND" ] && exit 0
CLEAN=$(echo "$COMMAND" | sed 's/#.*$//' | tr '\n' ' ' | sed 's/  */ /g')
PARTS=$(echo "$CLEAN" | sed 's/\s*&&\s*/\n/g; s/\s*||\s*/\n/g; s/\s*;\s*/\n/g; s/\s*|\s*/\n/g')
ALL_SAFE=true
while IFS= read -r part; do
    part=$(echo "$part" | sed 's/^\s*//;s/\s*$//')
    [ -z "$part" ] && continue
    BASE=$(echo "$part" | awk '{print $1}')
    case "$BASE" in
        cd|ls|cat|head|tail|grep|rg|find|which|stat|wc|echo|printf|date|env) ;;
        git|npm|node|python|python3|pip|make|cargo) ;;
        sort|uniq|cut|tr|awk|sed|jq|yq|tee|xargs) ;;
        mkdir|touch|tree|du|df|file|realpath) ;;
        *) ALL_SAFE=false; break ;;
    esac
done <<< "$PARTS"
if [ "$ALL_SAFE" = true ]; then
    jq -n '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",permissionDecisionReason:"Command allowed by hook"}}'
fi
exit 0
// ~/.claude/settings.json (or settings.local.json)
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/auto-allow.sh" }]
    }]
  }
}

This bypasses all the pattern-matching bugs:

  • Works with compound commands (&&, |, ;)
  • Works regardless of colon/space syntax confusion
  • Works at both user and project level
  • Never saves dead exact-string rules
  • You control the logic directly in bash

Add or remove commands from the case statement to match your needs.

altonplace · 3 months ago

Possible 2.1.87 regression: tool permission "Always allow" accepted but never written to disk

Adding a data point that may help narrow this down — specifically around settings.local.json not being written at all, rather than pattern-matching issues.

Environment

  • Claude Code 2.1.87 (CLI, macOS Sequoia 25.3.0 arm64)
  • CWD: ~/.claude (via alias — creates project-scoped config at ~/.claude/.claude/settings.local.json, which is expected behavior)
  • Issue is with tool permission rules (Bash, Write, MCP tools etc.) — not the additionalDirectories prompt covered in #7472

Observation

settings.local.json has not been modified since before the 2.1.87 upgrade, despite multiple "Always allow" clicks across sessions:

File last modified:  Mar 28 08:00  ← before upgrade
2.1.87 installed:    Mar 28 22:25
Checked:             Mar 30        ← no writes in 2 days of use

lsof shows the file is only ever opened read-only — never for writing:

$ lsof +D ~/.claude/.claude/
2.1.87  PID1  46r  REG  settings.local.json
2.1.87  PID1  57r  DIR  .claude/
2.1.87  PID2  35r  REG  settings.local.json
2.1.87  PID2  37r  DIR  .claude/

Both running 2.1.87 processes hold r (read-only) file descriptors on settings.local.json. No rw or w fd is observed at any point — including immediately after clicking "Always allow." The rule is accepted in-memory for the session but the write to disk never happens.

What was ruled out

  • settings.json ask/deny rules don't match settings.local.json path — no config blocking the write
  • No special CLI flags passed that would disable session persistence
  • File and directory permissions are correct (owner has write access)
  • No lock files present
  • SecurityValidator PreToolUse hook only intercepts the Write tool — not internal fs.writeFileSync calls made by Claude Code itself

Prior version behavior
The file was being written normally under 2.1.86. The last entry in settings.local.json dates to Mar 28 08:00, under 2.1.86 (installed Mar 27 18:04). Nothing has been written since the 2.1.87 upgrade later that day.

This suggests the issue may not be pattern-matching (the existing focus of this thread) but rather the write to settings.local.json never being triggered at all in 2.1.87. Happy to provide any additional diagnostic info.

bcherny collaborator · 3 months ago

Thanks for the report. This is a duplicate of #6881 — consolidating tracking there.

arnonmoscona · 2 months ago

[FYI toolguard is now at 0.3.0 - while takeover mode is nominally in alpha state, it's been working perfectly for me for a while. So this issue does not really affect me any more and I have a much more flexible permissions configuration.

https://github.com/arnonmoscona/toolguard](https://github.com/arnonmoscona/toolguard)