[BUG] bypassPermissions v2.1.81: .claude/skills/ not exempt from protected directory prompt despite documentation
Description
The permissions documentation states:
Writes to.claude/commands,.claude/agents, and.claude/skillsare exempt and do not prompt, because Claude routinely writes there when creating skills, subagents, and commands.
However, in v2.1.81, .claude/skills/ is not exempt from the protected directory prompt. Edits to files under .claude/skills/** trigger the "Do you want to make this edit?" prompt with the "Yes, and allow Claude to edit its own settings for this session" option — even with bypassPermissions mode active.
Root Cause (from source analysis)
The exemption function in the bundled binary only includes two of the three documented paths:
// Actual code in v2.1.81 binary (decompiled):
function sXT() {
return [...nCK.filter(d => d !== ".git"), ".claude/commands", ".claude/agents"]
}
// Returns: [".vscode", ".idea", ".claude/commands", ".claude/agents"]
// MISSING: ".claude/skills"
The docs promise .claude/skills is exempt, but the code doesn't include it.
Steps to Reproduce
- Set
"defaultMode": "bypassPermissions"in settings - Have a skill with scripts under
.claude/skills/<name>/scripts/ - Ask Claude to edit any file under
.claude/skills/ - Actual: Permission prompt appears
- Expected: No prompt (skills are documented as exempt)
Impact
This is particularly disruptive for projects that use .claude/skills/ extensively for automation, agent workflows, and domain-specific tooling. Every new session requires manual approval for the first .claude/skills/** edit, breaking autonomous claude -p --dangerously-skip-permissions workflows.
Related Issues
- #35646 (closed as fixed, but
.claude/skillsexemption was not included in the fix) - #35718 (duplicate of #35646, extensive user testing confirms the issue persists in v2.1.81)
Environment
- Claude Code version: 2.1.81
- OS: macOS (Darwin 25.3.0, arm64)
- Shell: zsh
- Settings:
bypassPermissions+skipDangerousModePermissionPrompt: true
Suggested Fix
Add .claude/skills to the sXT() exemption function to match the documented behavior:
function sXT() {
return [...nCK.filter(d => d !== ".git"), ".claude/commands", ".claude/agents", ".claude/skills"]
}
11 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Same pattern as #37253 — \
~/.claude/\is a protected directory that even \bypassPermissions\doesn't bypass. The docs say \skills/\should be exempt, but the implementation doesn't match.Until the exemption is fixed, you can auto-approve with a PreToolUse hook:
\
\\bash\INPUT=\$(cat)
TOOL=\$(echo "\$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
FILE=\$(echo "\$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
[[ "\$TOOL" != "Edit" && "\$TOOL" != "Write" ]] && exit 0
case "\$FILE" in
*/\.claude/skills/*|*/\.claude/commands/*|*/\.claude/agents/*)
jq -n '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"skills/commands/agents auto-approved per docs"}}'
exit 0
;;
esac
exit 0
\
\Settings:
\
\\json\{
"hooks": {
"PreToolUse": [{
"matcher": "",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/approve-claude-dirs.sh" }]
}]
}
}
\
\Confirming this also affects Agent SDK
query()— with source-level root cause and working binary patchTested exhaustively in v2.1.81 (Linux/Docker,
@anthropic-ai/claude-agent-sdknpm package). The missing.claude/skillsexemption blocks Edit/Write in SDK subprocess mode. Two separate checks incli.jsneed the exemption.History: v2.1.78 added protected-directory checks for all
.claude/writes (#35646). A follow-up fix added exemptions for.claude/commandsand.claude/agentsbut missed.claude/skills. TheuHYfunction's existingworktreesexemption pattern was not extended to cover skills/agents/commands either. This patch completes both exemptions.Root cause: two functions in
dN1's safety cascade (function names from our build's minification —sXTin the OP maps toLP8in my build; the checks below are additional to that exemption function)dN1(the write-safety check called fromYw6) runs three checks sequentially. A.claude/skills/path fails at both step 2 and step 3:rEq— Windows path patterns → passesIHY— checks if path is a.claude/protected path → returns true for skills/ →safe: falseuHY— checks path segments againsthHY = [".git", ".vscode", ".idea", ".claude"]→ returns true for.claudesegment →safe: falseIHYalready has.claude/skillsin its check list alongside commands and agents — but it flags all three as protected rather than exempt.uHYhas an existing exemption for.claude/worktrees(breaks out of the check) but not for skills/agents/commands.Note:
LP8/sXT(the exemption function identified in the OP) is used for file search/ripgrep scoping, not the permission cascade. Adding.claude/skillstoLP8alone does not fix the edit block — bothIHYanduHYindN1need to be patched.Working binary patch (two changes in
cli.js):Patch 1 —
IHY: Settings files remain protected viaWU1; commands/agents/skills no longer flagged:Patch 2 —
uHY: Add skills/agents/commands to the existing worktrees exemption:What remains protected after patch:
.claude/settings.json,.claude/settings.local.json— protected (WU1+uHY).claude/rules/,.claude/hooks/— protected (uHYcatches.claudewithout exemption).claude/skills/,.claude/agents/,.claude/commands/— exempt (matching docs and pre-v2.1.78 behavior)Apply with Python:
Verified: Edit tool works with 0 denials in SDK
query()mode after patch. BothbypassPermissionsandacceptEditsmodes work correctly. Settings files remain protected.Note on hook workarounds:
PreToolUsewithpermissionDecision: "allow"fires but doesn't override (runs beforedN1).PermissionRequesthooks never fire in SDK subprocess mode —dN1returns{behavior: "ask"}before thePermissionRequestdispatch path is reached, and the SDK subprocess treats the unresolved ask as a denial.Environment: Claude Code 2.1.81,
@anthropic-ai/claude-agent-sdk(npm), Node 20.20.0, Linux (Docker)Same issue here. Running two autonomous Claude Code agents 24/7 on a VPS via
--channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions. Both agents constantly get blocked on the "modify config files" prompt when writing to.claude/skills/.Since these are headless agents communicating only via Telegram, there's no one watching the terminal to approve. The permission relay (
claude/channel/permission) doesn't cover this prompt category either, so it doesn't appear in Telegram — it just silently blocks.Current workaround: telling agents to use
cat >via Bash instead of Write/Edit for.claude/paths, but they forget and get stuck regularly. Need manual intervention via tmux to unblock.Setup: Claude Code v2.1.81, Claude Max, Ubuntu 24.04, two agents running in tmux with
--dangerously-skip-permissions --channels.Adding
.claude/skillsto the exemption list alongside.claude/commandsand.claude/agentswould fix this completely..claude/plans/should also be added to the exemption list.Currently only
commandsandagentsare exempted in the code (withskillsdocumented but missing). Butplans/is equally non-dangerous — it's where Claude stores implementation plans for multi-session work. These are markdown files with no executable content, no hooks, no settings.In my setup (fully permissive: unrestricted
Edit/Write+bypassPermissions+skipDangerousModePermissionPrompt), the self-edit prompt only triggers for plans — memory writes to~/.claude/projects/*/memory/go through without prompting, but any write to<project>/.claude/plans/triggers the prompt every session.Suggested fix for the exemption function:
All four subdirectories (
commands,agents,skills,plans) contain user-facing content that Claude routinely creates/updates — none of them are settings, hooks, or anything security-sensitive.Plugins can store their working data under the recommended path ~/.claude/plugins/data/<plugin-name>/. it should be also exempt alongside .claude/commands, .claude/agents, and .claude/skills.
I've been hitting this since v2.1.78 dropped. Now on v2.1.83 — still broken.
My workflow relies heavily on editing
.claude/skills/files for context archiving and knowledge persistence across sessions. Every single Edit/Write to a skill file triggers a permission prompt, even with:defaultMode: "bypassPermissions"skipDangerousModePermissionPrompt: trueEdit(/.claude/skills/**)andWrite(/.claude/skills/**)in allow rules.claude/skillsinadditionalDirectoriesNone of these have any effect. The hardcoded safety check overrides everything.
What makes this even worse: approving "allow all edits during this session" doesn't persist. The next edit to a
.claude/skills/file prompts again. So it's not even a once-per-session annoyance — it's every single time.I've also tried the
PreToolUsehook workaround (returningpermissionDecision: "allow") — the hook fires but the safety check runs as a separate gate after it and prompts anyway.The documentation explicitly says
.claude/skills/should be exempt. The binary patch in @IMBurbank's comment above shows exactly what needs to change — it's literally adding"skills"to the existing"worktrees"exemption. This is a one-line fix that's been sitting here for weeks.Five versions without a fix or even an acknowledgment. Please prioritize this.
Still reproducible on Windows as of 2026-04-20.
This matches the existing
.claude/skillsexemption bug, but I'm adding a Windows repro because the behavior is still inconsistent with the docs.Environment
bypassPermissionsDocs say
.claude/skillsshould be exempt from protected-directory prompts:https://code.claude.com/docs/en/permissions
Actual behavior
When Claude tries to create or edit files under:
.claude/skills/<skill-name>/scripts/it still shows a permission prompt like:
The prompt includes choices such as:
Expected behavior
No prompt at all for writes under
.claude/skills/**, since the docs explicitly list that path as exempt.Impact
This breaks deterministic skill-authoring workflows on Windows even with
bypassPermissions, because skill creation and editing still requires interactive confirmation.Related
Additional version detail for tracking:
Reproduced on:
bypassPermissionsSo this is still present well past the earlier reports around v2.1.78-v2.1.84.
This is a duplicate of #37765, which was fixed as of version 2.1.121.
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.