Desktop app: settings.local.json Write/Edit/NotebookEdit permission deny rules not enforced
Environment
- Claude Code desktop app, Code tab (not the terminal CLI directly)
- Project has a committed
.claude/settings.jsonand a git-ignored.claude/settings.local.json, both withpermissions.denyarrays
Setup
.claude/settings.json (committed):
{
"permissions": {
"deny": [
"Read(**/.env)", "Read(**/.env.*)", "Read(**/*.pem)", "Read(**/*.key)",
"Read(~/.aws/credentials)", "Read(~/.ssh/id_*)",
"Bash(env)", "Bash(printenv)"
]
}
}
.claude/settings.local.json (git-ignored, project-local):
{
"permissions": {
"deny": [
"Edit(/absolute/path/to/some-other-repo/**)",
"Write(/absolute/path/to/some-other-repo/**)",
"NotebookEdit(/absolute/path/to/some-other-repo/**)"
]
}
}
Expected
Per the settings docs, .claude/settings.local.json (project-local, level 3) should override/merge with .claude/settings.json (level 4) with the same precedence everywhere Claude Code runs, including the desktop app. deny rules are documented to "apply right away." So a Write or Edit tool call targeting a path matched by a Write(...)/Edit(...) deny rule in settings.local.json should be blocked, the same way a Read call matched by a Read(...) deny rule in settings.json is blocked.
Actual
Readcalls matchingsettings.json'sRead(...)deny rules are blocked correctly, with an explicit "File is in a directory that is denied by your permission settings" error.Writecalls matchingsettings.local.json'sWrite(...)deny rule are not blocked:- In session permission mode
auto: theWritesilently succeeded — no denial, no prompt. - In session permission mode
default(switched mid-session via the app's own permission-mode control): the sameWriteattempt did not get an explicit rule-based denial either — it fell through to an ordinary interactive approval prompt, as if nodenyrule existed at all, and only got blocked because a human manually rejected the prompt. - Re-tested an
Editagainst a pre-existing tracked file with a matchingEdit(...)deny rule (present insettings.local.jsonbefore this test, not newly added) — same result: not blocked as a rule match, required manual rejection indefaultmode.
So there's a clear asymmetry: Read deny rules from the committed settings file enforce correctly; Write/Edit/NotebookEdit deny rules from the local settings file do not enforce as rule-based denials in either auto or default permission mode — in the desktop app specifically. I haven't tested the terminal CLI to see if it reproduces there too.
Impact
This defeats a guardrail pattern meant to keep an agent session from ever committing to or editing files in an unrelated, read-only reference repo path configured via settings.local.json — the rule is present, syntactically valid, and silently doesn't fire.
Happy to provide more repro detail or a minimal test repo if useful.