[BUG] bypassPermissions v2.1.81: .claude/skills/ not exempt from protected directory prompt despite documentation

Status Closed — duplicate
Reported on v2.1.81
Maintainer reply ✓ Yes — claude[bot]
Activity 11 comments · opened Mar 21, 2026 · closed Apr 29, 2026
💡 Likely answer: A maintainer (claude[bot], contributor) responded on this thread — see the highlighted reply below.

Description

The permissions documentation states:

Writes to .claude/commands, .claude/agents, and .claude/skills are 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

  1. Set "defaultMode": "bypassPermissions" in settings
  2. Have a skill with scripts under .claude/skills/<name>/scripts/
  3. Ask Claude to edit any file under .claude/skills/
  4. Actual: Permission prompt appears
  5. 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/skills exemption 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"]
}

View original on GitHub ↗

11 Comments

github-actions[bot] · 5 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/36497
  2. https://github.com/anthropics/claude-code/issues/36396
  3. https://github.com/anthropics/claude-code/issues/36923

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

yurukusa · 5 months ago

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" }]
}]
}
}
\
\\

IMBurbank · 5 months ago

Confirming this also affects Agent SDK query() — with source-level root cause and working binary patch

Tested exhaustively in v2.1.81 (Linux/Docker, @anthropic-ai/claude-agent-sdk npm package). The missing .claude/skills exemption blocks Edit/Write in SDK subprocess mode. Two separate checks in cli.js need the exemption.

History: v2.1.78 added protected-directory checks for all .claude/ writes (#35646). A follow-up fix added exemptions for .claude/commands and .claude/agents but missed .claude/skills. The uHY function's existing worktrees exemption 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 — sXT in the OP maps to LP8 in my build; the checks below are additional to that exemption function)

dN1 (the write-safety check called from Yw6) runs three checks sequentially. A .claude/skills/ path fails at both step 2 and step 3:

  1. rEq — Windows path patterns → passes
  2. IHY — checks if path is a .claude/ protected path → returns true for skills/safe: false
  3. uHY — checks path segments against hHY = [".git", ".vscode", ".idea", ".claude"]returns true for .claude segmentsafe: false

IHY already has .claude/skills in its check list alongside commands and agents — but it flags all three as protected rather than exempt. uHY has 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/skills to LP8 alone does not fix the edit block — both IHY and uHY in dN1 need to be patched.

Working binary patch (two changes in cli.js):

Patch 1 — IHY: Settings files remain protected via WU1; commands/agents/skills no longer flagged:

Find:    return wk(A,q)||wk(A,K)||wk(A,_)}
Replace: return!1}

Patch 2 — uHY: Add skills/agents/commands to the existing worktrees exemption:

Find:    if(O===".claude"){let $=K[Y+1];if($&&yZ($)==="worktrees")break}
Replace: if(O===".claude"){let $=K[Y+1];if($&&(yZ($)==="worktrees"||yZ($)==="skills"||yZ($)==="agents"||yZ($)==="commands"))break}

What remains protected after patch:

  • .claude/settings.json, .claude/settings.local.json — protected (WU1 + uHY)
  • .claude/rules/, .claude/hooks/ — protected (uHY catches .claude without exemption)
  • .claude/skills/, .claude/agents/, .claude/commands/ — exempt (matching docs and pre-v2.1.78 behavior)

Apply with Python:

with open('node_modules/@anthropic-ai/claude-agent-sdk/cli.js', 'r') as f:
    content = f.read()
content = content.replace(
    'return wk(A,q)||wk(A,K)||wk(A,_)}',
    'return!1}', 1)
content = content.replace(
    'if(O===".claude"){let $=K[Y+1];if($&&yZ($)==="worktrees")break}',
    'if(O===".claude"){let $=K[Y+1];if($&&(yZ($)==="worktrees"||yZ($)==="skills"||yZ($)==="agents"||yZ($)==="commands"))break}',
    1)
with open('node_modules/@anthropic-ai/claude-agent-sdk/cli.js', 'w') as f:
    f.write(content)

Verified: Edit tool works with 0 denials in SDK query() mode after patch. Both bypassPermissions and acceptEdits modes work correctly. Settings files remain protected.

Note on hook workarounds: PreToolUse with permissionDecision: "allow" fires but doesn't override (runs before dN1). PermissionRequest hooks never fire in SDK subprocess mode — dN1 returns {behavior: "ask"} before the PermissionRequest dispatch 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)

itspers · 5 months ago

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/skills to the exemption list alongside .claude/commands and .claude/agents would fix this completely.

adelfino69 · 5 months ago

.claude/plans/ should also be added to the exemption list.

Currently only commands and agents are exempted in the code (with skills documented but missing). But plans/ 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:

function sXT() {
    return [...nCK.filter(d => d !== ".git"), ".claude/commands", ".claude/agents", ".claude/skills", ".claude/plans"]
}

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.

AlexanderNaumovets · 5 months ago

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.

tz5514 · 5 months ago

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: true
  • Explicit Edit(/.claude/skills/**) and Write(/.claude/skills/**) in allow rules
  • .claude/skills in additionalDirectories

None 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 PreToolUse hook workaround (returning permissionDecision: "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.

bkerf · 4 months ago

Still reproducible on Windows as of 2026-04-20.

This matches the existing .claude/skills exemption bug, but I'm adding a Windows repro because the behavior is still inconsistent with the docs.

Environment

  • OS: Windows
  • Shell: PowerShell
  • Permission mode: bypassPermissions

Docs say .claude/skills should 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:

Claude requested permissions to write to .../.claude/skills/<skill-name>/scripts, but you haven't granted it yet.

The prompt includes choices such as:

  • Yes
  • Yes, and always allow access ...
  • No

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

  • #39523
bkerf · 4 months ago

Additional version detail for tracking:

Reproduced on:

  • Claude Code 2.1.114
  • Windows
  • PowerShell
  • bypassPermissions

So this is still present well past the earlier reports around v2.1.78-v2.1.84.

claude[bot] contributor · 4 months ago

This is a duplicate of #37765, which was fixed as of version 2.1.121.

github-actions[bot] · 3 months ago

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.