permission-check skill
Diagnose why Claude Code is (or isn't) prompting for permission. By default reads only repo-local layers (CLI project, CLI project-local, VSCode workspace). Host-global layers (CLI user `~/.claude/`, VSCode user settings) are read ONLY when the user explicitly confirms — those files may contain unrelated paths or secrets. Use when user says "why is it asking me to approve?", "permission check", "why am I getting prompts?", "bypass isn't working", "check my permissions". Read-only diagnostic.
Is the permission-check skill safe?
Clean: nothing in its files matched our rules. We read 1 file in the folder on 2026-09-28.
No findings.
Install the permission-check skill
A skill is a folder. Copy it into your agent's skills folder and the agent loads it when the task matches its description.
git clone --depth 1 https://github.com/pedrohcgs/claude-code-my-workflow.git /tmp/claude-code-my-workflow mkdir -p ~/.claude/skills cp -r /tmp/claude-code-my-workflow/.claude/skills/permission-check ~/.claude/skills/permission-check
In the Claude apps, zip the folder and upload it from the Skills settings. The folder on GitHub
The instructions your agent would load
SKILL.md as published, without the frontmatter. Read it on GitHub
Permission Check
Purpose
Surface the full permission-mode picture across every layer Claude Code honors, so the user can see at a glance why prompts are (or aren't) firing. Claude Code resolves permission mode from a 6-tier stack; a single misconfigured layer produces silent overrides that are hard to debug by eye.
The 6 layers (precedence: bottom wins)
- VSCode user settings — ~/Library/Application Support/Code/User/settings.json (macOS), %APPDATA%/Code/User/settings.json (Windows), ~/.config/Code/User/settings.json (Linux). Key: claudeCode.initialPermissionMode.
- VSCode workspace settings — /.vscode/settings.json. Same key. Wins over user.
- CLI user settings — ~/.claude/settings.json. Key: permissions.defaultMode.
- CLI project settings — /.claude/settings.json. Same key. Wins over user.
- CLI project-local settings — /.claude/settings.local.json. Same key. Wins over project.
- In-session mode — set at session start from layers 1-5, then mutable via Shift+Tab (CLI) or the mode indicator (VS Code / Desktop); /permissions manages allow/deny rules, not the mode. Authoritative until session ends.
Two rules that override the stack (Anthropic's permission-modes docs, re-verified 2026-09-26):
- Layers 4 and 5 do not honor auto or bypassPermissions as a starting mode. A bypassPermissions there is ignored and the terminal session starts in Manual (default); an auto there is ignored in favour of the built-in default. Every other mode value applies from any layer.
- The VS Code extension does not read layers 4–5 for its starting mode; it uses claudeCode.initialPermissionMode (which does not accept auto), and a bypass value needs the extension's Allow dangerously skip permissions toggle. With no override, Claude Code ≥ 2.1.283 starts in auto mode.
So check first for "bypass set in the project settings, where it cannot take effect" — then for the mid-session override below.
Key insight: initialPermissionMode only fires at session start. If you toggled mid-session (or the session started before a settings change), the file-level settings are correct but the runtime mode differs. That, and a bypass set only in project settings, are the two usual sources of "bypass isn't working" confusion.
Privacy contract
Host-global settings files (~/.claude/settings.json, VSCode user settings) may contain:
- Paths to unrelated projects and secrets
- API keys, tokens, or provider credentials added outside this repo
- Permission policies set by the user's org or employer
This skill is designed for defense-in-depth: Phase A runs automatically and reads only repo-local files. Phase B reads host-global files only after the user explicitly confirms — never silently. When reporting host-global layers, redact any key that is not directly relevant to permissions., claudeCode., or allowDangerouslySkipPermissions.
Protocol
Phase A: Repo-local layers (auto-runs)
Read these immediately — they are checked into (or gitignored inside) the repo and do not cross the trust boundary:
VSCODE_WS="${CLAUDE_PROJECT_DIR}/.vscode/settings.json"
CLI_PROJECT="${CLAUDE_PROJECT_DIR}/.claude/settings.json"
CLI_LOCAL="${CLAUDE_PROJECT_DIR}/.claude/settings.local.json"For each file that exists, extract:
- VSCode workspace: claudeCode.initialPermissionMode and allowDangerouslySkipPermissions (no claudeCode. prefix — flag the prefixed claudeCode.allowDangerouslySkipPermissions as a silently-ignored typo if you see it)
- CLI project / project-local: permissions.defaultMode, permissions.allow, permissions.deny
Missing files are fine — report "not present" rather than erroring.
Print the resolved defaultMode from these three layers alone, applying the two override rules above — a bypassPermissions or auto found only in layer 4 or 5 is reported as ignored, not as the resolved mode. If that already explains the prompt behavior (e.g. bypass set only in .claude/settings.json), stop here and surface the diagnosis with the fix: move it to ~/.claude/settings.json, pass --permission-mode bypassPermissions, or use auto mode.
Phase B: Host-global layers (requires explicit user confirmation)
If Phase A is inconclusive — e.g., all repo-local layers agree on bypass but the user is still being prompted — ask the user:
"To complete the diagnosis, I need to read two files outside this repo:
- ~/.claude/settings.json (CLI user-level)
- your VSCode user settings (~/Library/Application Support/Code/User/settings.json on macOS; Linux/Windows vary)
These may contain unrelated paths or secrets. I will redact any key that isn't in permissions., claudeCode., or allowDangerouslySkipPermissions. Proceed?"
Only after the user confirms, read:
# VSCode user (platform-dependent path; try all three)
case "$(uname -s)" in
Darwin) VSCODE_USER="${HOME}/Library/Application Support/Code/User/settings.json" ;;
Linux) VSCODE_USER="${HOME}/.config/Code/User/settings.json" ;;
MINGW*|MSYS*|CYGWIN*) VSCODE_USER="${APPDATA}/Code/User/settings.json" ;;
*) VSCODE_USER="" ;;
esac
CLI_USER="${HOME}/.claude/settings.json"When reporting their contents, extract only the relevant keys:
- CLI user: permissions.defaultMode, permissions.allow, permissions.deny
- VSCode user: any key starting with claudeCode.
Never print the full file. Redact everything else to (other keys redacted).
Step 2: Compute resolved state
The resolved defaultMode is the value from the highest-precedence layer that sets it. Report:
- Which layer won the defaultMode contest.
- Merged allow list (union across CLI tiers).
- Merged deny list (union; any deny blocks the action even if allowed elsewhere).
- Whether VSCode says bypass but CLI says otherwise (or vice versa) — this is a legitimate conflict to flag.
Step 3: Report runtime mode
The live in-session mode is exposed via the status line (see .claude/scripts/statusline.sh). Tell the user:
"If your status line shows a mode badge ([AUTO], [BYPASS], [PLAN], [AUTO-EDIT], [PROMPT]), that is the live in-session mode. If it disagrees with the resolved defaultMode above, either a mid-session toggle (Shift+Tab) changed it, or the resolution above already explains it — e.g. [PROMPT] from a bypass set only in project settings. No badge means Claude Code did not report the mode; the mode indicator in the Claude Code panel shows it."
If the status line isn't configured, emit a warning and point at .claude/scripts/statusline.sh.
Step 4: Flag common failure modes
Check for and explicitly call out:
- Bypass or auto set only in project settings: layers 4–5 cannot set these starting modes. A bypass there starts the session in Manual; an auto there falls back to the built-in default (auto on ≥ 2.1.283). Fix: remove it from the project files and set bypass in user settings or with the CLI flag — or rely on the built-in auto default.
- Layer drift: CLI user says bypass but CLI project-local says default → the project-local default wins (it is an honoured value), which explains the prompts.
- VSCode-only bypass: VSCode layers say bypass but no CLI layer does → terminal Claude Code will still prompt; the extension honours it only with Allow dangerously skip permissions on.
- Empty allowlist + default mode: defaultMode: "default" with empty allow → every tool prompts, as designed.
- Stale session: settings are correct but user reports prompts → almost always a session that pre-dates the fix. Advise "Cmd+Shift+P → Developer: Reload Window, then new Claude Code session."
- deny wins: any match in a deny list blocks the tool regardless of allow, in every mode including bypass — which is exactly why restricted-data projects use deny rules.
Output format
=== PERMISSION STATE ===
Layer 1 — VSCode user: bypassPermissions (allowDangerouslySkipPermissions: true)
Layer 2 — VSCode workspace: (not set)
Layer 3 — CLI user: bypassPermissions (allow: ["*"])
Layer 4 — CLI project: (not set) (allow: ["Edit(**)", "Bash(*)", ...])
Layer 5 — CLI project-local: bypassPermissions NOT HONOURED — a project-layer bypass starts the session in Manual
Resolved defaultMode: default (Manual) — Layer 5's bypass overrides Layer 3 and is not honoured
Merged allow: Edit(**), Write(**), Bash(*), ...
Merged deny: (none)
=== RUNTIME ===
Check the status line (or the mode indicator). Expected here: [PROMPT] — the ignored Layer 5 bypass explains it.
Remove the bypass from Layer 5 and keep it in Layer 3 (or rely on auto mode) to get [BYPASS] / [AUTO].
Any other mismatch with the resolved mode is an in-session override — Shift+Tab cycles modes.
=== DIAGNOSIS ===
No layer drift detected. If you are still seeing prompts:
1. Session is stale (started before settings were applied) — reload window + new session.
2. VSCode extension bug — check extension version and file an issue.
3. Tool was prIf any layer disagrees, replace the "No layer drift detected" line with a specific flagged issue.
Notes
- This skill is read-only. It never modifies settings.
- If $CLAUDEPROJECTDIR is unset, fall back to git rev-parse --show-toplevel.
- Platform-aware: detect macOS vs Linux vs Windows for the VSCode user path.
More skills from pedrohcgs/claude-code-my-workflow
- Aadjudicate-reviewTurn an incoming set of findings — from an AI reviewer, a referee report, a code review, a linter, or a second model — into verified fixes, without letting a confident misread damage correct work. Every finding is a CANDIDATE until checked against the actual source. Use whenever you receive review comments, audit findings, or a critique you did not write yourself, especially when the reviewer is a model or when the volume is too large to check by feel.
- Aaudit-reproducibilityEnforce the replication-protocol.md rule by cross-checking numeric claims in a manuscript against the actual R / Stata / Python outputs. Report PASS/FAIL per claim against tolerance thresholds. Use before submission and before releasing a replication package.
- Ablast-radiusBefore and after changing anything shared — a function's return value, a signature, a schema, a label set, a config default, a constant, a file format — find every consumer and actually run them. Catches the change that looks purely additive but silently breaks a contract in a file you never opened. Use when editing shared code, adding a field/column/return element, renaming, changing units or defaults, or touching a pipeline that produces reported numbers.
- Acapture-environmentSnapshot the computational environment for a replication package — detects the analysis stack (R / Stata / Python) and emits the right lockfiles (renv.lock + sessionInfo.txt, requirements.txt / environment.yml / uv.lock, Stata version + ado package list), records seeds and RNG kind, optionally writes a pinning Dockerfile, and produces a paste-ready "Computational requirements" block. Use when user says "capture the environment", "snapshot my dependencies", "pin the versions", "make a renv.lock / requirements.txt", "make this byte-reproducible", or before releasing a replication package to openICPSR / the AEA Data Editor.
- AchallengeStress-test a finding against the choices you did not make. Enumerates the discrete forks a competent analyst could have taken (measure definition, sample filter, control set, clustering level, weighting, functional form), runs the specification grid, and reports the distribution rather than a point estimate — then attacks the identifying assumption with named, computable sensitivity statistics. Use when the user says "is this robust", "challenge this result", "specification curve", "multiverse", "how sensitive is this", "what if I'd used a different measure", "stress-test my estimate", or before a result becomes a headline claim. NOT a reviewer of prose or code — it challenges the CLAIM.
- AcheckpointSave a structured state snapshot before stopping or handing off. Captures the active plan, recent decisions, file pointers (with line numbers), open questions, and the next 1–3 actions into a checkpoint file under `quality_reports/checkpoints/`. Optionally proposes `[LEARN]` entries to add to MEMORY.md. Use when user says "checkpoint", "save state", "snapshot before I stop", "where am I", "wrap up the session for handoff", or before a long break / model switch / collaborator handoff. Companion to (NOT replacement for) the narrative session-log workflow.
- Acoauthor-briefGenerate a co-author / collaborator handoff brief for a multi-author, multi-machine project — summarizing what changed since the last brief (git delta), the current state of each artifact (manuscript, analysis, slides), open questions, how to reproduce locally, and any restricted-data access steps. Use when user says "coauthor brief", "handoff brief", "bring my coauthor up to speed", "what changed since last week", "onboard a collaborator", "write a handoff for [name]", or before sending a co-author the repo. NOT a commit or a checkpoint — it is the cross-machine, cross-person summary `meta-governance.md` only partially covers.
- AcommitCommit the current work — runs the quality, consistency and passport gates, branches off main if needed, stages specific files, and writes a commit whose subject states what is now true. Pushes and opens a pull request only with --pr or when the user asks; never merges — a merge happens only when the user explicitly says to merge. Use ONLY on explicit commit intent — user says "commit", "let's commit this", "open a PR", or prefixes with `/commit`. Do NOT auto-invoke on vague end-of-task phrases ("we're done", "wrap up") — those require explicit confirmation first. Never force-pushes or skips hooks.
- Acompile-latexCompile a Beamer LaTeX slide deck with XeLaTeX (3 passes + bibtex). Use when user says "compile", "build the slides", "rebuild the PDF", "run latex", "render the tex", or asks why a `.tex` file isn't producing a PDF. Operates on `Slides/*.tex`.
- Acompress-sessionDistill the current conversation into a structured note (decisions made, open questions, file pointers with line numbers, next 1–3 actions) and save to `quality_reports/session_logs/` before auto-compression. Differs from `/checkpoint` (explicit stop-point snapshot) and from auto-compaction (which truncates rather than distills). Use when context is approaching auto-compact threshold, when a long pipeline has accumulated many decisions, or when the user says "compress", "distil this session", "before we hit auto-compact", "structured handoff before context resets".
- Acontext-statusShow current context status and session health. Use to check how much context has been used, whether auto-compact is approaching, and what state will be preserved.
- Acreate-lectureCreate a new Beamer lecture `.tex` from source papers and materials, with notation consistency checks and the project's preamble wired in. Use when user says "create a lecture on X", "new lecture from these papers", "start a deck on topic Y", "scaffold a new Beamer file", "build me a lecture from these PDFs". Scaffolds the full deck — NOT for compiling existing `.tex` (use `/compile-latex`).