This skill should be used when the user asks to "review permissions", "update allowlist", "check unapproved commands", "what's getting prompted", "audit bash permissions", "reduce prompts", "permission audit", or wants to review and update Claude Code's auto-approved command allowlist based on recent usage.
From mxnpx claudepluginhub maxwolf-01/agents --plugin mxThis skill uses the workspace's default tool permissions.
scripts/scan_unapproved.pyDesigns and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Scan recent sessions for Bash commands that triggered permission prompts, then recommend additions to the allowlist. The goal is to reduce friction for read-only / benign operations while keeping write operations and state-modifying commands gated.
Two permission paradigms exist:
--dangerously-skip-permissions, making PRs. No allowlist needed.This skill is for paradigm 1. The allowlist safety bar:
git add/commit/push/reset/restore, docker exec/stop/rm/run, rm/mv/cp, ssh * docker exec/stop/restart, file writes, database mutations, npm install, pip install. Anything that modifies state, even benignly.Global settings (always applies):
~/.claude/settings.json
If this is a symlink (common with dotfiles), note the canonical path for editing.
Project-level settings (applies to current project only):
<project-root>/.claude/settings.json
Read both to understand what's already allowed.
uv run <skill-dir>/scripts/scan_unapproved.py \
<sessions_dir> \
<global_settings_path> [<project_settings_path>] \
--days <N>
<sessions_dir>: ~/.claude/projects/<project-path-encoded>/ (path encoding: replace / with -, strip leading slash)--days N: how far back to scan (default 30, user may request 60+)--help for full usageThe script reads the actual allowlist from the settings files, so it stays in sync. Output is JSON: [{signature, count, example}, ...] sorted by frequency.
Present results in a table, grouped by safety:
Safe to allowlist — pure RO, zero side effects:
df, free, uptime, dig, ps, id, wc, stat, fileuv run, uvx, ty, npx tsc, npm view, make test-*, make checkgit fetch, git worktree list, git cherrydocker ps, docker logs, docker inspect, docker imagesssh * <any-of-the-above>Never allowlist — state modifications:
git add, git commit, git push, git reset, git checkout, git stashdocker exec, docker stop, docker rm, docker run, docker buildrm, mv, cp, mkdir, chmod, sed -inpm install, uv add, uv sync, pip install&&, ||, ;) — these bypass pattern matching anywayJudgment calls — discuss with user:
duckdb — can write, but often used for analytics reads only. Project-local if allowed.sqlite3 — same as duckdb.curl — can POST/DELETE, but locally already allowed. SSH-tunneled version is consistent.bash <script> — depends entirely on script content. Usually skip.make targets — safe if RO, but varies. Always project-local.Split additions:
~/.dotfiles/claude/settings.json or wherever the canonical source is): universal RO commands useful across all projects.<project>/.claude/settings.json): project-specific make targets, domain tools.Insert new entries in the appropriate section of the JSON, maintaining the existing grouping style (basic commands, search tools, nix, system, dev tooling, git, gh, ssh, docker).
Format: "Bash(<command_pattern> *)" — the * at end matches any trailing arguments.
Gotcha — trailing * requires at least one argument. "Bash(git status *)" matches git status -s but NOT bare git status. For commands that are commonly called without arguments, add BOTH the bare and * variants:
"Bash(git status)",
"Bash(git status *)",
For SSH remote commands: "Bash(ssh * <command> *)" — the first * matches the hostname. Same trailing-* caveat applies: "Bash(ssh * nvidia-smi)" is needed alongside the * variant for bare invocations.
Gotcha — SSH glob patterns are inherently over-broad. ssh * docker ps * matches ANY SSH command containing "docker ps" anywhere in the string, including ssh host docker exec $(docker ps -q) evil-cmd. The * wildcards match across the full command, not just individual arguments. This means "read-only" SSH docker patterns can be exploited to run docker exec/run/stop/rm over SSH without approval.
Mitigation: the mx plugin includes a PreToolUse hook (hooks/ssh-docker-guard.sh) that acts as a deny-list — it blocks SSH commands containing dangerous docker subcommands (exec, run, stop, rm, kill, build, push, pull, restart, update, create) regardless of what the glob allowlist permits. If reviewing SSH docker patterns, verify this hook is active rather than trying to fix it at the glob level.
Commit each settings file to its respective repo with a descriptive message.