Review commands that were blocked by the permission system and decide which to allowlist. Reads the denial ledger written by the PermissionDenied hook and deny-check.sh, groups the blocks, and proposes concrete settings.json edits for approval. Use when (1) user says '/permission-review', 'review blocks', 'what got blocked', 'tune permissions', (2) a /x-wt-teams or /x-as-pr run has just finished and blocked commands should be triaged, (3) the user is moving to auto mode and wants to reduce pr...
Scanned 9/8/2026
Install to Claude Code
npx -y skills add Takazudo/claude-resources --skill permission-review --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Permission Review?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/takazudo-permission-review)More formats (shields.io, HTML) on the badges page.
---
name: permission-review
description: "Review commands that were blocked by the permission system and decide which to allowlist. Reads the denial ledger written by the PermissionDenied hook and deny-check.sh, groups the blocks, and proposes concrete settings.json edits for approval. Use when (1) user says '/permission-review', 'review blocks', 'what got blocked', 'tune permissions', (2) a /x-wt-teams or /x-as-pr run has just finished and blocked commands should be triaged, (3) the user is moving to auto mode and wants to reduce prompts. Also runs a static scan of skill commands not covered by the allowlist."
---
# Permission review
Turn blocked commands into deliberate allowlist decisions. Two inputs:
- **Runtime ledger** — `$HOME/.claude/logs/permission-denials.jsonl`, appended by
the `PermissionDenied` hook and by `scripts/security/deny-check.sh`. Captures
what actually got blocked, **including inside subagents and worktree children**.
- **Static scan** — `node $HOME/.claude/scripts/scan-skill-commands.js`, which
reports commands skills *could* run that no allow rule covers.
## Steps
### 1. Read the ledger
```bash
LEDGER="$HOME/.claude/logs/permission-denials.jsonl"
[ -s "$LEDGER" ] || echo "ledger empty — nothing blocked since last clear"
jq -s 'group_by(.command | split(" ")[0:3] | join(" "))
| map({sig: .[0].command, n: length, source: .[0].source, reason: .[0].reason, cwds: (map(.cwd) | unique)})
| sort_by(-.n)' "$LEDGER"
```
Scope to a single run when reviewing right after a workflow:
```bash
# blocks from the last 2 hours only
jq -c --arg since "$(date -u -v-2H '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \
|| date -u -d '2 hours ago' '+%Y-%m-%dT%H:%M:%SZ')" \
'select(.ts >= $since)' "$LEDGER"
```
### 2. Classify every distinct block
This is the judgment step. Do not batch-approve.
| Class | Signal | Action |
|---|---|---|
| **Hard deny** | `source: "deny-check"` | **Never propose allowlisting.** These are the user's deliberate guardrails (force-push, repo delete, `git config`). Report that it was hit and what the agent did instead. A repeat hit means a skill needs fixing, not the deny list. |
| **Pure friction** | read-only or clearly reversible, recurs across runs | Propose a narrow `permissions.allow` prefix rule. |
| **Category friction** | mutating or outward-facing, and no prefix rule can express it (compound commands, redirects) | Propose an `autoMode.allow` sentence describing the *category*. |
| **Correctly blocked** | irreversible, or dual-use binary (`gh api`, `bash -c`, `sed -i`) | Leave uncovered. Say so explicitly and why. |
### 3. Run the static scan for what has not been hit yet
```bash
node "$HOME/.claude/scripts/scan-skill-commands.js" --min 2
```
Treat the output as candidates only. A signature appearing here has not
necessarily caused a prompt.
### 4. Present decisions, then apply
Show a table of proposed changes — rule, class, why, how often hit. Use
`AskUserQuestion` when more than two items need a call, one question per
non-obvious rule. Never widen the deny list without an explicit request.
Apply approved edits via the `/update-config` skill so array merge semantics
are respected. Preserve the literal `"$defaults"` as the first element of
`autoMode.allow` — dropping it silently discards every built-in allow rule.
### 5. Verify and clear
```bash
jq -e . "$HOME/.claude/settings.json" >/dev/null && echo "settings.json valid"
bash "$HOME/.claude/scripts/security/deny-check-test.sh" # if present
: > "$HOME/.claude/logs/permission-denials.jsonl" # only after applying
```
Clear the ledger **only** once decisions are applied, so an interrupted review
does not lose the evidence.
## Reporting
Per global instructions, headings state the verdict:
- `## 3 rules added, 1 left blocked on purpose`
- `## Nothing blocked this run`
- `## Hard deny hit twice: /x-wt-teams tried force-push`
Do not write a "nothing notable" section. If a class is empty, omit it.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!