claude-code - 💡(How to fix) Fix v2.1.123: --dangerously-skip-permissions still denies .claude/skills/ writes in stream-json mode (regression of v2.1.122 fix) [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#54850Fetched 2026-04-30 06:34:10
View on GitHub
Comments
1
Participants
2
Timeline
9
Reactions
1
Timeline (top)
labeled ×7commented ×1subscribed ×1

In Claude Code 2.1.123, writing to .claude/skills/, .claude/agents/, or .claude/commands/ is silently denied even with --dangerously-skip-permissions and permissionMode: "bypassPermissions". This contradicts the v2.1.122 changelog entry:

--dangerously-skip-permissions no longer prompts for writes to .claude/skills/, .claude/agents/, and .claude/commands/

The denial is recorded in the final result event's permission_denials array, with no inbound control_request / can_use_tool for the host to surface to the user. In headless / SDK / stream-json contexts (no TTY), this manifests as an agent that emits {"is_error": true, "content": "Claude requested permissions to write to <path>, but you haven't granted it yet."} and stalls — there is no surface where the user can grant permission.

Root Cause

In Claude Code 2.1.123, writing to .claude/skills/, .claude/agents/, or .claude/commands/ is silently denied even with --dangerously-skip-permissions and permissionMode: "bypassPermissions". This contradicts the v2.1.122 changelog entry:

--dangerously-skip-permissions no longer prompts for writes to .claude/skills/, .claude/agents/, and .claude/commands/

The denial is recorded in the final result event's permission_denials array, with no inbound control_request / can_use_tool for the host to surface to the user. In headless / SDK / stream-json contexts (no TTY), this manifests as an agent that emits {"is_error": true, "content": "Claude requested permissions to write to <path>, but you haven't granted it yet."} and stalls — there is no surface where the user can grant permission.

Fix Action

Fix / Workaround

Workaround (for other host implementers)

Code Example

mkdir -p /tmp/cm-skills-test/.claude/skills
cd /tmp/cm-skills-test

echo '{"type":"user","message":{"role":"user","content":"Use the Write tool to create .claude/skills/diag/SKILL.md with content: # diag"}}' \
  | claude \
      --input-format stream-json \
      --output-format stream-json \
      --include-partial-messages \
      --verbose \
      --dangerously-skip-permissions \
  2>&1 | tee /tmp/repro.jsonl \
  | grep -E '"type":"result"|permission_denials|"is_error":true'

---

{
  "type":"user","message":{...,"content":[{
    "type":"tool_result",
    "content":"Claude requested permissions to write to /private/tmp/cm-skills-test/.claude/skills/diag/SKILL.md, but you haven't granted it yet.",
    "is_error":true,
    "tool_use_id":"toolu_01QsYwXfg13ZjFQN2YBGnsMy"
  }]}
}

---

{
  "type":"result","subtype":"success","is_error":false,...,
  "permission_denials":[{
    "tool_name":"Write",
    "tool_use_id":"toolu_01QsYwXfg13ZjFQN2YBGnsMy",
    "tool_input":{
      "file_path":"/private/tmp/cm-skills-test/.claude/skills/diag/SKILL.md",
      "content":"# diag"
    }
  }],
  "terminal_reason":"completed"
}
RAW_BUFFERClick to expand / collapse

Summary

In Claude Code 2.1.123, writing to .claude/skills/, .claude/agents/, or .claude/commands/ is silently denied even with --dangerously-skip-permissions and permissionMode: "bypassPermissions". This contradicts the v2.1.122 changelog entry:

--dangerously-skip-permissions no longer prompts for writes to .claude/skills/, .claude/agents/, and .claude/commands/

The denial is recorded in the final result event's permission_denials array, with no inbound control_request / can_use_tool for the host to surface to the user. In headless / SDK / stream-json contexts (no TTY), this manifests as an agent that emits {"is_error": true, "content": "Claude requested permissions to write to <path>, but you haven't granted it yet."} and stalls — there is no surface where the user can grant permission.

Environment

  • Claude CLI version: 2.1.123
  • Platform: macOS 25.3.0 (Darwin)
  • Shell: zsh
  • Reproducer: vanilla CLI invocation, no PreToolUse hooks, no project settings, fresh /tmp cwd, no plugin / MCP interference (also reproduces with user ~/.claude/settings.json removed)

Reproducer

mkdir -p /tmp/cm-skills-test/.claude/skills
cd /tmp/cm-skills-test

echo '{"type":"user","message":{"role":"user","content":"Use the Write tool to create .claude/skills/diag/SKILL.md with content: # diag"}}' \
  | claude \
      --input-format stream-json \
      --output-format stream-json \
      --include-partial-messages \
      --verbose \
      --dangerously-skip-permissions \
  2>&1 | tee /tmp/repro.jsonl \
  | grep -E '"type":"result"|permission_denials|"is_error":true'

Expected (per v2.1.122 changelog)

The Write succeeds. .claude/skills/diag/SKILL.md is created. The result event has an empty or absent permission_denials.

Actual

The Write is silently blocked. Output:

{
  "type":"user","message":{...,"content":[{
    "type":"tool_result",
    "content":"Claude requested permissions to write to /private/tmp/cm-skills-test/.claude/skills/diag/SKILL.md, but you haven't granted it yet.",
    "is_error":true,
    "tool_use_id":"toolu_01QsYwXfg13ZjFQN2YBGnsMy"
  }]}
}
{
  "type":"result","subtype":"success","is_error":false,...,
  "permission_denials":[{
    "tool_name":"Write",
    "tool_use_id":"toolu_01QsYwXfg13ZjFQN2YBGnsMy",
    "tool_input":{
      "file_path":"/private/tmp/cm-skills-test/.claude/skills/diag/SKILL.md",
      "content":"# diag"
    }
  }],
  "terminal_reason":"completed"
}

The system / init event for the same session reports "permissionMode":"bypassPermissions" — so the flag is being honored at the mode level, but the .claude/skills/ relaxation from v2.1.122 is not taking effect.

What we ruled out

I'm building a stream-json host (Tauri app wrapping the CLI) and chased this through several wrong hypotheses. For the next person debugging the same thing — these are NOT the cause:

HypothesisDisproven by
Inbound control_request / can_use_tool not handled by the hostRaw stdout tap shows zero control_request events for the failing turn
PreToolUse hook returning the wrong response shapeReproduces with no hooks at all (vanilla CLI)
User-level ~/.claude/settings.json (permissions.defaultMode: "auto", plugins) overriding the flagReproduces with ~/.claude/settings.json temporarily moved aside
bypassPermissions mode not being appliedInit event explicitly reports permissionMode: "bypassPermissions"
Project-level .claude/settings*.json deny rulesFresh /tmp cwd, no .claude/settings*.json exists

Suggested fix direction

If the v2.1.122 relaxation is intentionally limited to TTY contexts, the changelog should say so, and stream-json mode should at minimum emit a control_request (or some addressable event) so SDK hosts can prompt the user instead of seeing a silent permission_denials and a stalled agent. Today there is no documented escape hatch for stream-json hosts that legitimately need to write skills/agents/commands.

Workaround (for other host implementers)

Bash heredoc writes to .claude/... are not subject to this guardrail and go through normal hook/approval paths. We're shipping a host-side detection of permission_denials in the result event with a user-facing toast that suggests asking the agent to retry via Bash, but that's a band-aid — the protocol gap remains.

extent analysis

TL;DR

The issue can be worked around by using Bash heredoc writes to .claude/... which are not subject to the same guardrail.

Guidance

  • The --dangerously-skip-permissions flag and permissionMode: "bypassPermissions" are not taking effect for stream-json contexts, causing writes to .claude/skills/, .claude/agents/, and .claude/commands/ to be silently denied.
  • The denial is recorded in the permission_denials array of the final result event, but there is no inbound control_request or can_use_tool event to prompt the user for permission.
  • To verify the issue, run the provided reproducer script and check the output for the permission_denials array and the error message.
  • To mitigate the issue, use Bash heredoc writes to .claude/... which are not subject to the same guardrail.

Example

echo "# diag" > .claude/skills/diag/SKILL.md

This Bash command writes to .claude/skills/diag/SKILL.md without being subject to the guardrail.

Notes

The issue seems to be specific to stream-json contexts and the --dangerously-skip-permissions flag. The workaround using Bash heredoc writes may not be suitable for all use cases.

Recommendation

Apply the workaround using Bash heredoc writes, as the protocol gap remains and there is no documented escape hatch for stream-json hosts.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix v2.1.123: --dangerously-skip-permissions still denies .claude/skills/ writes in stream-json mode (regression of v2.1.122 fix) [1 comments, 2 participants]