[Feature Request] Add setting to skip protected directory prompts when bypassPermissions is enabled
Problem
v2.1.78 introduced prompts for writes to protected directories (.git/, .claude/, .vscode/, .idea/) even when bypassPermissions mode is enabled. While this is a reasonable security default, users who have explicitly opted into bypassPermissions mode have already accepted full trust — prompting them for every edit to these directories adds friction without security benefit.
This is especially painful in VS Code where each prompt requires a mouse click on a dialog, and typical sessions involve many edits to .claude/settings.json, .claude/rules/, .vscode/settings.json, and occasionally .git/config.
Attempted Workarounds (all failed)
permissions.allowpatterns (e.g.Edit(.claude/**)) — do not override the protected directory promptPermissionRequesthook returning{"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}}— does not fire in VS Code extension (see #13203, #12176)PreToolUsehook returningpermissionDecision: "allow"— does not override protected directory checks (v2.1.77 change)- No CLI flag or env var exists for this
Proposed Solution
Add a skipProtectedDirectoryPrompts setting (boolean, default false) that, only when bypassPermissions is already enabled, skips the protected directory write prompt:
{
"permissions": {
"defaultMode": "bypassPermissions"
},
"skipProtectedDirectoryPrompts": true
}
This preserves the security improvement for users in default or acceptEdits modes while respecting the explicit trust decision of bypassPermissions users.
Additional Context
- The
PermissionRequesthook not firing in VS Code (#13203) means there is currently no workaround for VS Code users skipDangerousModePermissionPromptalready exists as precedent for skipping prompts that bypass-mode users find redundantpermissions.denyrules would still block even with this setting (deny always wins), so users retain granular control
Environment
- Claude Code v2.1.78
- VS Code extension
- Windows 11
bypassPermissionsmode enabled via~/.claude/settings.json
11 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Update: Working Workaround Found (VS Code Extension Patch)
While a proper setting is still the ideal solution, I found a working workaround by patching the VS Code extension directly.
What we tried (all failed)
As documented in the issue body, plus one additional finding:
PermissionRequesthook: Actually does fire in VS Code now (issue #13203 was fixed around v2.1.30), but protected directory prompts use a separate code path that doesn't go through thePermissionRequesthook event. So this approach fails silently.What works: Patching
extension.jsThe protected directory check originates in the native CLI binary (
claude.exe), which sendscan_use_toolrequests to the VS Code extension. The extension'srequestToolPermissionmethod forwards these to a webview dialog. The patch intercepts atrequestToolPermissionbefore the dialog is created.The extension already has an auto-approve pattern for Chrome MCP tools. The patch adds an identical check for protected directory paths right after it:
Full patch script (~130 lines) with
--check,--revert, and backup support: auto-detects the extension directory, finds the anchor point in minified code, creates a backup, and applies the patch.Results
permissions.denyrules still block as expected (the check never reaches the patch for denied tools)Why a proper setting is still needed
Not a duplicate
The suggested duplicates (#35646, #35718, #35626) report the same problem but none have a workaround. This issue specifically requests a
skipProtectedDirectoryPromptssetting, which remains the right long-term fix. The working patch demonstrates that the feature is technically simple to implement at the extension level.Thanks @voyagi — your workaround saved my day. I independently hit the same wall
(v2.1.78 broke our DevContainer workflow where Claude edits
.claude/files constantly)and went through the exact same failed attempts:
permissions.allowpatterns,PermissionRequesthook,PreToolUsehook — nothing worked.Found your issue and applied the
extension.jspatch. Works perfectly.Additional notes from my setup (VS Code DevContainer, Linux, v2.1.79):
return{behavior:"allow",updatedInput:j};let N=await this.sendRequestexists in both versions unchanged.
postStartCommandindevcontainer.jsonso the patchre-applies on every container rebuild. Script exits gracefully (exit 0) if
extension isn't installed yet or anchor string changed.
.claude/skills/exemption bug: docs say.claude/commands/,.claude/agents/,.claude/skills/should be exempt from protected dir prompts,but they all prompt in v2.1.79. Filed separately as a bug observation but
your patch covers it anyway.
inspect()bug:getInitialPermissionMode()usesvscode.workspace.getConfiguration("claudeCode").inspect("initialPermissionMode")which only checks
workspaceFolderValue,workspaceValue, andglobalValue.Machine-level settings (set via VS Code Settings UI or
devcontainer.jsoncustomizations.vscode.settings) are NOT in any of those scopes — they're indefaultValue. Workaround: use.vscode/settings.json(workspace level)instead of
devcontainer.jsonsettings.+1 for
skipProtectedDirectoryPromptsas a proper setting.+1 — this is a real problem for anyone with hook-based enforcement infrastructure.
I have ~36 hooks that fire on Write|Edit (format validation, integrity checks, quality gates). The protected directory prompt pushes toward using Bash writes as a workaround — which silently bypasses the entire PostToolUse hook layer. The "fix" is worse than the problem.
A
skipProtectedDirectoryPromptssetting (gated onbypassPermissionsalready being enabled) would be the clean solution. The user has already opted into full trust by enabling bypass mode.Update: v2.1.81 broke the patch — fixed with dynamic anchor detection
The anchor string changed in v2.1.81:
let N=awaitbecamelet U=await. The patch script silently skipped with "Anchor pattern not found" — so we were back to permission prompts.Fix: replaced the hardcoded variable name with dynamic extraction via regex:
The variable name (
N,U, or whatever comes next) is captured and passed to the Python patcher as a parameter. Everything else stays the same.Anchor stability across versions:
| Version | Variable | Surrounding pattern |
|---------|----------|-------------------|
| 2.1.78 |
N|return{behavior:"allow",updatedInput:j};let N=await this.sendRequest|| 2.1.79 |
N| same || 2.1.81 |
U| same (only variable name changed) |The surrounding pattern (
return{behavior:"allow",updatedInput:j};let ...=await this.sendRequest) has been stable across all three versions so far. The dynamic approach should survive future updates as long as this pattern holds.Still running via
postStartCommandin DevContainer — re-applies automatically on every rebuild.this seems to also affect
~/.claudedirectory as well. I store certain things in there that are updated headless by agents and this no longer works, had to downgrade to v2.1.77 and disable auto updates for now. Symlinking could be another alternative, but askipProtectedDirectoryPromptsoption would be welcomedUpdate: Patch v2 — Bash tool coverage (v2.1.83)
The original patch only checks
j?.file_path, which covers Write/Edit tools. Bash tool commands (mkdir,touch) in protected directories also prompt — but Bash usesj?.command, notj?.file_path, so the patch missed them.Testing matrix (v2.1.83, bypassPermissions, VS Code DevContainer):
| Command | Type | Prompts? |
|---------|------|:--------:|
|
ls .claude/| read | No ||
cat .claude/...| read | No ||
find .claude/| read | No ||
stat .claude/...| read | No ||
mkdir -p .claude/...| write | Yes ||
touch .claude/...| write | Yes ||
cp ... .claude/...| write | Yes ||
echo > .claude/...| write | Yes ||
rm -rf .claude/...| write | Yes |Read-only commands pass silently. All write commands prompt.
Patch v2 adds a second check for safe Bash commands:
Destructive commands (
cp,rm,mv,sed -i,echo >) still prompt — by design.Anchor stability update: pattern
return{behavior:"allow",updatedInput:j};let <VAR>=await this.sendRequestholds in v2.1.83 (var=v). Dynamic extraction continues to work.| Version | Variable |
|---------|----------|
| 2.1.78 |
N|| 2.1.79 |
N|| 2.1.81 |
U|| 2.1.83 |
v|v2.1.84 update: Minifier renamed variables —
j→BforupdatedInput, let variable also changed. Fixed the patch script to dynamically grep both variable names from the anchor pattern instead of hardcoding them. Re-tested, works on 2.1.84.You can auto-approve protected directory writes with a hook, giving you fine-grained control over which directories are exempt:
Same hook for Edit:
This lets you selectively exempt directories from the protected-directory prompt while keeping
.git/and other sensitive directories gated. Adjust thecasepatterns to match your workflow.Closing for now — inactive for too long. Please open a new issue if this is still relevant.
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.