Every time you click "approve" on ls, cat, or git status, you're paying a 3-second tax. Multiply by 50 prompts a day. The fix is a one-shot scan: LingCode reads your past transcripts, finds the safe commands you keep approving, and builds you a personalized allowlist.
LingCode prompts before every Bash command for one good reason: it can't tell ls from rm -rf ahead of time without asking. The default has to be paranoid or someone, somewhere, loses their work.
But after a week of real use, the prompts you've actually answered yes to are a small, repetitive set:
ls, cat, head, tail, file, stat.git status, git diff, git log, git show, git branch.npm test, npm run lint, cargo check, swift build.which, node --version, echo $PATH.None of those mutate state. None of them deserve a prompt. The discipline of writing them all out by hand is what nobody does — so this tutorial replaces the discipline with a scan.
LingCode stores conversation transcripts locally on disk — each session is a JSON file under ~/.claude/projects/, namespaced by working directory. Inside each transcript, every tool call is recorded with its exact arguments and whether the user approved it.
The scan looks at:
list, get, read, describe — are typical safe candidates).It does not touch your code or any sensitive content — only the metadata of tool calls and their approvals.
In the chat panel, ask LingCode:
Scan my recent transcripts for repeated safe Bash and MCP tool
calls. Build me a prioritized allowlist for this project's
.claude/settings.json. Show me the proposed diff before applying.
LingCode walks the transcripts in ~/.claude/projects/, counts approvals per command, classifies each into a safe category (read-only, build-check, env-inspection) or a "needs human judgment" category (anything that writes to disk, network, or system state), and proposes additions to permissions.allow.
The output looks roughly like this:
Found 47 unique approved Bash patterns across 23 sessions.
Categorizing:
- read-only: 19 patterns, 312 total approvals
- build/test: 8 patterns, 94 approvals
- env inspection: 6 patterns, 41 approvals
- judgment call: 14 patterns (NOT proposing)
Top 12 by frequency:
Bash(ls:*) ........ 87 approvals
Bash(git status:*) ........ 54 approvals
Bash(cat:*) ........ 41 approvals
Bash(git diff:*) ........ 38 approvals
Bash(npm test:*) ........ 22 approvals
...
Proposed diff for <repo>/.claude/settings.json:
+ "Bash(ls:*)",
+ "Bash(cat:*)",
+ "Bash(head:*)",
...
Don't blindly accept the diff. Read it as a code review. Three checks:
Bash(git:*) matches git status but also git push --force. Prefer the narrower form, e.g. Bash(git status:*), Bash(git diff:*), Bash(git log:*) as separate entries.curl, wget, npm install, git push, or anything with redirects, strip it. Approve those manually so you keep noticing them.Bash(ls:*) belongs in the user file (~/.claude/settings.json) so every project benefits. Bash(./scripts/build.sh:*) belongs in the project file. The scan defaults to the project file — move entries up as you go.curl https://example.com can be weaponized if the URL was assembled at runtime. The scan filters these by default; if you see one in the proposed list, it's because LingCode wasn't sure — err on the side of "leave it prompting."
Once the proposal looks right, tell LingCode:
Apply the cleaned-up allowlist to .claude/settings.json. Show the
final file when done.
LingCode writes the file with the new entries appended (it does not remove existing entries) and prints the result. The file hot-reloads — your next session benefits immediately.
If you don't already have .claude/settings.json at the project root, LingCode creates it with the standard skeleton. If you want the rules to live in your user-wide file instead, say so explicitly: "apply to ~/.claude/settings.json instead of the project file."
The honest test isn't "did the file save" — it's "do I get fewer prompts in the next session." Open a new chat in the same repo and ask LingCode to do something that would have prompted before:
Show me the most recently modified files in src/ and tell me
what they likely do.
If your allowlist took effect, LingCode runs ls, stat, cat, and friends without any approval dialogs. If a prompt still appears, the most common cause is a pattern mismatch between what's in the allowlist and what LingCode wants to run — see Customize permissions and env vars for the glob syntax in detail.
Your workflow drifts. New tools enter rotation, old ones fall away. Re-running the scan every couple of weeks keeps the allowlist matching reality:
Re-scan transcripts since <date of last scan> and propose
additions to .claude/settings.json. Don't touch existing entries.
The scan is incremental-friendly — give it a date floor and it only counts approvals after that point. This is how you avoid the allowlist quietly accumulating a year of stale entries.
rm, mv, dd, shutdown, kill -9 (even if you've approved them before).sudo or doas.npm install, pip install, brew install, cargo install. These mutate global state and pull arbitrary code.git push, scp, rsync to remotes, curl -X POST.curl ... | sh patterns. These should be approved by hand every single time.The scan errs on the side of leaving these prompting. If you want one of them in the allowlist anyway, add it manually — but write the glob narrowly.
The whole workflow — scan, classify, propose, review, apply, re-run — is packaged as a skill. Drop it into your skills folder and ask LingCode for "reduce my permission prompts" or "build me an allowlist" to invoke it:
---
name: fewer-permission-prompts
description: Use to reduce permission-prompt fatigue. Scans Claude Code session transcripts for common read-only Bash and MCP tool calls (ls, cat, grep, git status, find, etc.), then adds a prioritized allowlist to project .claude/settings.json. Triggers: 'too many permission prompts', 'allowlist commands', 'stop asking permission', 'auto-approve safe commands', 'reduce prompts', 'allow X command'. Actions: scan transcripts, classify SAFE-READ vs JUDGMENT, append to permissions.allow, save the 3-second tax on every ls. Hard exclude: rm, sudo, package installs, network writes.
---
Reduce LingCode permission prompts by analyzing past transcripts and
proposing a personalized allowlist.
Steps:
1. Walk ~/.claude/projects/<cwd>/ JSON transcripts (or the
user-specified directory if asked). Count approved Bash and MCP
tool calls per pattern. If a date floor was given, only count
approvals after it.
2. Classify each pattern:
- SAFE-READ: inspection-only verbs (ls, cat, head, tail, file,
stat, pwd, which, git status, git diff, git log, git show, git
branch, cargo check, swift build, npm test, npm run lint, npx
tsc --noEmit, node --version, env, echo).
- JUDGMENT: anything writing to disk, network, or system state.
Do NOT propose these — leave them prompting.
3. Sort SAFE-READ by frequency. Drop one-offs (≤2 approvals).
Convert exact commands to prefix-glob "Bash(<verb>:*)" only
when the verb is universally safe; otherwise keep the literal.
4. Default target is <repo>/.claude/settings.json. Universal
patterns (ls, cat, git status, git diff) can be hoisted to
~/.claude/settings.json — note this as an option in the diff.
5. Show the diff first. Never modify settings.json until the user
approves. Preserve existing entries; only append.
6. After applying, suggest re-running the scan in 2 weeks with a
date floor of today.
Hard exclusions — never propose: rm, mv, dd, shutdown, kill, sudo,
doas, npm install, pip install, brew install, cargo install, git
push, scp, rsync to remotes, curl -X POST, curl|sh patterns.
Save as ~/.lingcode/skills/fewer-permission-prompts/SKILL.md — see Install a skill for the exact location and how skills get discovered.