← Alle Recipes
Phase 3 · Basic Workflows·8 min·5 steps

Permissions reloaded — building a tight allow-list

Beyond the safe defaults from Recipe 1.4: a project-scoped allow-list that pre-clears 90% of routine prompts without giving up the dangerous-command guardrails.

5 steps0%
Du liest ohne Account. Mit Login speichern wir Step-Fortschritt + Notes.

Permissions reloaded

Recipe 1.4 set up the safe defaults — Bash blocked, file edits scoped, network calls reviewed. That keeps you out of trouble. But after a few weeks of real use you start clicking "allow" on the same five commands every session: npm test, git status, git diff, ls, cat package.json. Each click costs three seconds and your concentration.

This recipe builds a tight allow-list that pre-clears those routines without re-opening the gates the safe defaults closed.

Step 1: Spot the prompts you keep approving

Open ~/.claude/transcripts/ (or use the /fewer-permission-prompts skill if you have it installed) and skim the last week. You're looking for tool calls you approved more than three times. Those are candidates for an allow-rule.

The skill is the lazy path:

/fewer-permission-prompts

It scans your transcripts, ranks the most-clicked commands, and produces a JSON snippet ready to paste. If you don't have it, do it manually — grep "Allow this" ~/.claude/transcripts/*.jsonl | head -50 is enough.

Step 2: Add a project-scoped allow-list

Project-scoped lives in <repo>/.claude/settings.local.json. Things in here only apply when Claude is launched from that directory:

{
  "permissions": {
    "allow": [
      "Bash(npm test)",
      "Bash(npm run build)",
      "Bash(git status)",
      "Bash(git diff)",
      "Bash(git log:*)",
      "Read(./*)",
      "Edit(./src/**)",
      "Glob(./*)",
      "Grep(./*)"
    ]
  }
}

Two things to note:

  • Bash(git log:*) — the :* suffix lets any flag through (--oneline, -10, --graph). Without it only the bare git log is allowed.
  • Edit(./src/**) — scopes edits to your source tree. ./node_modules/** won't auto-approve.

Step 3: Deny rules for hard limits

Allow-list is offense. Deny-list is defense. Even when an allow-rule technically matches, a deny-rule can override:

{
  "permissions": {
    "allow": [
      "Bash(*)"
    ],
    "deny": [
      "Bash(rm -rf*)",
      "Bash(git push --force*)",
      "Bash(git reset --hard*)",
      "Bash(prisma migrate reset*)",
      "Bash(docker system prune --volumes*)"
    ]
  }
}

The point is not to stop a malicious agent (the model is on your side). The point is to add friction in front of the few commands that destroy hours of work in one keystroke.

Step 4: Verify settings parse

The validator on this step parses ~/.claude/settings.json (the global file). For project-scoped checks Claude reads .claude/settings.local.json automatically the next time you launch it from that directory.

Run aiguide_validate_step. If it fails, fix the JSON — a stray comma is the usual cause.

Client check · run on your machine
python3 -m json.tool ~/.claude/settings.json > /dev/null && echo "valid" || echo "invalid or missing"
Expect: Prints "valid".
If stuck: Fix the JSON syntax — settings.json must parse, even if it is just `{}`.

Step 5: Reload and watch

In an open Claude session, type /permissions to see the merged allow-list (global + project + session-level). The project rules should appear when you launch from that repo.

Test by running npm test once. No "Allow this?" prompt → you saved a click forever.

Re-audit every two months. Three signals that you need to revisit:

  • A new command shows up in the top-five "Allow this" list. Add it.
  • A command in the allow-list hasn't been used in a month. Remove it.
  • You added a deny rule because something scared you. Keep that. Promote it to global if it would scare you in any project.
Slash commands and built-in shSubagents 101 — when to delega