{"slug": "3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none", "title": "3 permission presets for Claude Code (strict, balanced, autonomous) and the gap none of them close", "summary": "A developer published three permission presets for Claude Code's `.claude/settings.json` — strict, balanced and autonomous — that control which shell commands the agent may run without confirmation, and documented two gaps the presets cannot close: prefix matching lets `Bash(git:*)` permit `git push --force` and `git reset --hard`, and a `Read(./.env)` deny rule does not stop a `cat .env` run through Bash. The developer recommends `PreToolUse` hooks that inspect the full command and can block it with `exit 2`, and released two MIT-licensed hook scripts, one blocking destructive git commands and one preventing secrets from being written to files. The presets and hooks are also bundled with six skills and CLAUDE.md templates in a US$9 unofficial starter kit.", "body_md": "Every \"Allow this command?\" prompt in Claude Code is a small interruption. Click \"always allow\" enough times and you end up with a `settings.json` nobody has read. Here are three presets I keep in `.claude/settings.json`, from most to least careful, and the one thing none of them can do.\n\nRules are matched in this order: **deny** beats **ask**, and **ask** beats **allow**. Anything not listed falls back to `defaultMode`.\n\nRead-only git is free. Commits, pushes and installs need a confirmation, and network tools are off.\n\n```\n{\n  \"permissions\": {\n    \"defaultMode\": \"default\",\n    \"allow\": [\n      \"Bash(git status)\",\n      \"Bash(git diff:*)\",\n      \"Bash(git log:*)\"\n    ],\n    \"ask\": [\n      \"Bash(git commit:*)\",\n      \"Bash(git push:*)\",\n      \"Bash(npm install:*)\",\n      \"Bash(pnpm add:*)\",\n      \"Bash(yarn add:*)\"\n    ],\n    \"deny\": [\n      \"Read(./.env)\",\n      \"Read(./.env.*)\",\n      \"Read(./secrets/**)\",\n      \"Bash(curl:*)\",\n      \"Bash(wget:*)\",\n      \"WebFetch\"\n    ]\n  }\n}\n```\n\nEdits are accepted automatically (`acceptEdits`). Lint, tests and type checks run without asking, and anything that leaves your machine or changes dependencies still asks.\n\n```\n{\n  \"permissions\": {\n    \"defaultMode\": \"acceptEdits\",\n    \"allow\": [\n      \"Bash(git status)\",\n      \"Bash(git diff:*)\",\n      \"Bash(git log:*)\",\n      \"Bash(git add:*)\",\n      \"Bash(npm run lint:*)\",\n      \"Bash(npm run test:*)\",\n      \"Bash(npm test:*)\",\n      \"Bash(npx tsc --noEmit:*)\"\n    ],\n    \"ask\": [\n      \"Bash(git push:*)\",\n      \"Bash(npm install:*)\",\n      \"Bash(pnpm add:*)\",\n      \"Bash(yarn add:*)\"\n    ],\n    \"deny\": [\n      \"Read(./.env)\",\n      \"Read(./.env.*)\",\n      \"Read(./secrets/**)\"\n    ]\n  }\n}\n```\n\nAll of git and npm are allowed. Use it only where a bad command costs you a branch, not a production database.\n\n```\n{\n  \"permissions\": {\n    \"defaultMode\": \"acceptEdits\",\n    \"allow\": [\n      \"Bash(git:*)\",\n      \"Bash(npm:*)\",\n      \"Bash(npx:*)\",\n      \"Bash(pnpm:*)\",\n      \"Bash(node:*)\",\n      \"WebFetch\",\n      \"WebSearch\"\n    ],\n    \"deny\": [\n      \"Read(./.env)\",\n      \"Read(./.env.*)\",\n      \"Read(./secrets/**)\"\n    ]\n  }\n}\n```\n\nLook at the autonomous preset again: `Bash(git:*)` allows `git push --force` and `git reset --hard` too. Permission rules match a command by its prefix. They can't tell a safe `git push` from a destructive one.\n\nThere's a second gap. `Read(./.env)` blocks Claude's Read tool, but it isn't a rule about the shell. A `cat .env` through Bash is a different tool and needs its own handling.\n\nThat's what **hooks** are for. A `PreToolUse` hook is a script that sees the full command before it runs and can block it with `exit 2`, so it can reject `git push --force` while allowing a normal push, or refuse any command that touches `.env`. Two free ones (one blocks destructive commands, tested against bypasses like `git push origin +main`; one stops secrets from being written into files) are here: [https://github.com/kailucho/claude-code-hooks-seguridad](https://github.com/kailucho/claude-code-hooks-seguridad) (free, MIT).\n\nPresets for convenience, hooks for safety. You want both.\n\nThe three presets, the hooks, 6 skills (`/commit`, `/pr`, `/review`, `/tests`, `/plan`, `/debug`) and `CLAUDE.md` templates for React, Node and GraphQL come together in the **Starter Kit for Claude Code** (US$9, unofficial): [https://luijhy.gumroad.com/l/starter-kit-for-claude-code](https://luijhy.gumroad.com/l/starter-kit-for-claude-code)", "url": "https://wpnews.pro/news/3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none", "canonical_source": "https://dev.to/luijhy_michaelguerraflo/3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none-of-them-close-4pn8", "published_at": "2026-10-28 19:31:26+00:00", "updated_at": "2026-10-28 19:41:34.902826+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-safety"], "entities": ["Claude Code", "Anthropic", "GitHub", "npm", "Gumroad"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none", "markdown": "https://wpnews.pro/news/3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none.md", "text": "https://wpnews.pro/news/3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none.txt", "jsonld": "https://wpnews.pro/news/3-permission-presets-for-claude-code-strict-balanced-autonomous-and-the-gap-none.jsonld"}}