Scan your transcripts for common read-only Bash and MCP tool calls, then add a prioritized allowlist to project .claude/settings.json to reduce permission prompts.
Scan your transcripts for common read-only Bash and MCP tool calls, then add a prioritized allowlist to project .claude/settings.json to reduce permission prompts.
Fewer Permission Prompts
Look through my transcripts' MCP and bash tool calls, and based on those, make a prioritized list of patterns that I should add to my permission allowlist to reduce permission prompts. Focus on read-only commands.
The format for permissions is: Bash(foo*), Bash(foo), Bash(foo bar *), mcp__slack__slack_read_thread, etc.
Then, add these to the project .claude/settings.json under permissions.allow.
Steps
Locate transcripts. Session transcripts live at ~/.claude/projects/<sanitized-cwd>/*.jsonl. Each line is a JSON object. Tool calls appear as assistant messages with message.content[] entries of type: "tool_use". The name field identifies the tool (e.g. "Bash", "mcp__slack__slack_read_thread"); for Bash, input.command is the shell string.
Scan the recent transcripts across the user's projects dir — not just the current project — so the allowlist reflects their actual usage. Cap the scan at a reasonable number of recent sessions (e.g. 50 most-recently-modified JSONL files) so this stays fast.
Extract tool-call frequencies.
For Bash calls: parse input.command, take the leading command token (handling sudo, timeout, pipes, &&, env-var prefixes). Record the command + first subcommand pair (e.g. git status, gh pr view, ls, cat).
For MCP calls: record the full tool name (e.g. mcp__slack__slack_read_thread).
Count occurrences across the scanned transcripts.
Filter to read-only. Keep only commands that don't mutate state. Examples of read-only: ls, cat, pwd, git status, git log, git diff, git show, git branch, rg, grep, find, head, tail, wc, file, which, echo, date, gh pr view, gh pr list, gh pr diff, gh issue view, gh issue list, gh run list, gh run view, gh api (GET), bun run typecheck, bun run lint, bun run test (for tests that don't mutate), docker ps, docker logs, kubectl get, kubectl describe, ps, top, df, du, env, printenv, any MCP tool with read/get/list/search/view in its name.
Drop anything that writes, deletes, renames, pushes, merges, installs, or runs a build/test that has side effects. When in doubt, leave it out.
Never allowlist a pattern that grants arbitrary code execution. A wildcard rule for any of these (e.g. Bash(python3:*)) is equivalent to allowing arbitrary code execution. This list is not exhaustive — apply the same rule to anything in the same category:
Interpreters: python/python3, node, bun, deno, ruby, perl, php, lua, etc.
Shells: bash, sh, zsh, , , , , etc.
Drop commands Claude Code already auto-allows. These don't need an allowlist entry — they never prompt. If you see any of these in the transcripts, skip them; don't suggest them to the user.
Pick the pattern form. Use the narrowest pattern that still covers the observed usage:
If the user runs many variants (git log, git log --oneline, git log main..HEAD): use Bash(git log *) — note the space before *, which is required for prefix matching to work correctly.
If a single exact invocation is common: use Bash(foo) with no wildcard.
For MCP: use the full tool name verbatim (no wildcard needed; they're already specific).
Never widen a pattern to the point that it conflicts with the rules above (no arbitrary code execution, no mutation/side effects).
Prioritize. Rank by count descending. Drop anything that appeared fewer than ~3 times — not worth the allowlist entry. Cap the list at the top ~20 so the user can skim it.
Present the prioritized list to the user as a markdown table with columns: rank, pattern, count, one-line description. Example:
#
Pattern
Count
Notes
1
Bash(git status *)
142
repo status checks
2
Bash(gh pr view *)
87
PR inspection
3
mcp__slack__slack_read_thread
54
Slack thread reads
Merge into .claude/settings.json in the current project (not ~/.claude/settings.json, not .claude/settings.local.json). Create the file if it doesn't exist. Preserve existing keys and existing entries in permissions.allow; de-duplicate against what's already there; don't remove anything; don't reorder unrelated fields.
Report back. Tell the user what you added (count + a few examples), what was already in the allowlist, and what you skipped and why (e.g. "dropped rm and git push — not read-only; dropped cat/ls/git status — already auto-allowed, no rule needed").
Do not add anything to permissions.deny or permissions.ask. Do not touch any other settings field.
同仓库更多 Skills
fish
eval
exec
ssh
Package runners: npx, bunx, uvx, uv run, etc.
Task-runner wildcards: npm run *, yarn run *, pnpm run *, bun run *, make *, just *, cargo run *, go run *, etc. — an exact Bash(bun run typecheck) is fine, Bash(bun run *) is not
gh api *, docker run/exec, kubectl exec, sudo, and similar
Source of truth: src/tools/BashTool/readOnlyValidation.ts (READONLY_COMMANDS, READONLY_NOARGS, READONLY_EXACT, COMMAND_ALLOWLIST) and src/utils/shell/readOnlyCommandValidation.ts (GIT_READ_ONLY_COMMANDS, GH_READ_ONLY_COMMANDS, DOCKER_READ_ONLY_COMMANDS, RIPGREP_READ_ONLY_COMMANDS, PYRIGHT_READ_ONLY_COMMANDS). If the user is in this repo and you're unsure whether a command is covered, grep these files rather than guessing.