# Fewer permission prompts: 15 sessions, one allowlist line

> Scanned 15 Claude Code session transcripts for prompts to allowlist. ~50 commands extracted, one strict survivor. The auto-allow list is broader than expected.

**Canonical URL**: https://agentcookbooks.com/blog/fewer-permission-prompts-scanned-15-sessions-one-allowlist-line/

**Published**: 2026-05-21

**Tags**: claude-code, harness

---

The pitch on `fewer-permission-prompts` is straightforward: scan your session transcripts, find the high-frequency Bash commands that keep prompting you, and add them to `.claude/settings.json` so they stop prompting. After eleven days of active work on this project, I expected to find maybe a dozen patterns worth allowlisting. The scan returned **one strict survivor**. Everything else was either already auto-allowed by Claude Code, or explicitly forbidden by the skill's safety rules. The takeaway isn't "this skill didn't help" — it's that Claude Code's built-in auto-allow list is much broader than the skill's setup docs suggest, and a fresh scan tells you exactly where the edges are.

## What I ran

Invoked via `/fewer-permission-prompts` as step four of a broader harness audit. Going into the run I had zero project-scoped permissions configured. Recurring commands that I knew were prompting me: `git status`, `git diff`, `npm run build`, `npm run dev`, `gh api repos/.../contents/...`, `node scripts/*`, `python scripts/*`.

The skill's behavior: read every `.jsonl` transcript under `~/.claude/projects/<project-id>/`, extract Bash command frequencies, filter the results against Claude Code's auto-allow list and against an explicit deny-list (mutating commands like `git push`, `git add`; arbitrary-code-execution like `gh api`; anything that takes a subcommand argument that could be anything).

## What happened

Fifteen `.jsonl` transcripts in the project's session folder. The skill extracted roughly fifty distinct command patterns. After filtering:

- **One pattern survived the strict threshold**: `Bash(npm run build)` at 14 hits. Everything else that hit the 3-occurrence floor was either already auto-allowed by the harness, mutating-by-nature (so blocked from quiet allowlisting), or arbitrary-code-execution.
- **Two patterns added proactively** below the threshold: `Bash(npm run dev)` and `Bash(npm run preview)`. Both are documented `npm` scripts in `package.json` and would hit the floor the second active local dev work resumed.

Final write to `.claude/settings.local.json`:

```json
{
  "permissions": {
    "allow": [
      "Bash(npm run build)",
      "Bash(npm run dev)",
      "Bash(npm run preview)"
    ]
  }
}
```

Three lines. That's the entire deliverable on an eleven-day-old project with fifteen active sessions of history.

## Where it drifted

Three friction points, in order of significance.

**The skill's "write to `.claude/settings.json`" default conflicts with how I actually want to scope permissions.** Project-committed `settings.json` versus operator-local `settings.local.json` is a real distinction: anything in `settings.json` ships to anyone who clones the repo, anything in `settings.local.json` stays personal. The skill wrote to the committed file by default. I wanted the local file. Easy override on user instruction, but the skill itself didn't catch that `settings.local.json` wasn't in `.gitignore` at all yet — had to add a line manually before saving. The skill's default path is reasonable for shared-team contexts; not reasonable for personal harness tuning.

**`gh api` is the prompts you can't silence.** Twenty-four `gh api repos/.../contents/...` prompts across the fifteen transcripts. All GET reads of public-ish repo content. I'd expected those to be auto-allowed since `git status` and `git diff` are. But the skill explicitly forbids `Bash(gh api *)` because `gh api` accepts arbitrary HTTP methods (`POST`, `DELETE`, etc.) and the wildcard would silently allow mutations. Correct call from the skill — but no narrow pattern fits, so this friction stays. Twenty-four prompts per session-equivalent of work remain prompts.

**The surprise was the lower bound, not the upper bound.** I went in expecting to add maybe ten lines. I added three (one strict, two proactive). The skill's report told me, in effect: the harness already handles most of what I thought I needed. The honest deliverable on a healthy active project is "you're already covered; here's the one thing to add."

## What I'd change

**Run the scan once at project setup, then again at the 30-session mark.** A single run on a one-week-old project surfaces almost nothing because the auto-allow list dominates. The patterns that bleed through accumulate slowly — a recurring `gh issue view`, a `python scripts/<script>.py` that becomes habit. The next useful run is once a project has thirty-plus sessions of friction-pattern data, not on day eleven.

**Treat the skill's "one survivor" output as a signal, not a failure.** If the scan returns one allowlist line, the harness is mostly doing its job. If it returns twenty, something's been disabled or the project is doing something unusual. The number itself is the diagnostic.

**Default to `settings.local.json`, not `settings.json`, unless the operator explicitly wants the rules shared.** Personal harness tuning is private. Team-shared permission policies are a separate concern that deserves its own intentional flow.