Skip to content

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

Description

@usorama

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

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

Activity

  1. github-actions commented on Mar 21, 2026

    @github-actions

    Found 3 possible duplicate issues:

    1. .claude/skills/ edits prompt for permission despite being documented as exempt (regression in 2.1.79) #36497
    2. Regression: .claude/skills/ writes prompt for confirmation in bypassPermissions mode since 2.1.78 #36396
    3. Bug: SKILL.md creation prompts for permission even in bypass mode #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

  2. yurukusa commented on Mar 22, 2026

    @yurukusa

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

  3. IMBurbank commented on Mar 22, 2026

    @IMBurbank

    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 segment → safe: 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)

  4. itspers commented on Mar 25, 2026

    @itspers

    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.

  5. adelfino69 commented on Mar 25, 2026

    @adelfino69

    .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.

  6. AlexanderNaumovets commented on Mar 25, 2026

    @AlexanderNaumovets

    Plugins can store their working data under the recommended path ~/.claude/plugins/data//. it should be also exempt alongside .claude/commands, .claude/agents, and .claude/skills.

  7. tz5514 commented on Mar 28, 2026

    @tz5514

    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.

  8. bkerf commented on Apr 20, 2026

    @bkerf

    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//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

  9. bkerf commented on Apr 20, 2026

    @bkerf

    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.

  10. claude commented on Apr 29, 2026

    @claude
    Contributor

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

  11. github-actions commented on May 7, 2026

    @github-actions

    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.

  12. locked as resolved and limited conversation to collaborators on May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions