Claude Code settings.json: the one config file most developers ignore
When people talk about customizing Claude Code, they jump straight to CLAUDE.md. But there's another config file that deserves equal attention: .claude/settings.json.
This file controls what Claude Code is actually allowed to do on your machine. Get it right and your agent works safely and predictably. Ignore it and you're running with default permissions that might surprise you.
Here's a complete breakdown of what it does and my recommended setup.
Where it lives
your-project/
├── .claude/
│ └── settings.json ← project-level (commit this)
├── ~/.claude/
│ └── settings.json ← user-level (applies everywhere)
Project-level overrides user-level. Both are JSON.
The structure
{
"permissions": {
"allow": [],
"deny": []
},
"env": {},
"includeCoAuthoredBy": true
}
Simple — but the permissions section is where the real power is.
Permissions: allow and deny
Permissions use a tool-name format: Bash, Read, Write, Edit, WebFetch, WebSearch, TodoWrite, etc.
You can be granular with Bash:
{
"permissions": {
"allow": [
"Bash(git:*)",
"Bash(npm run:*)",
"Bash(ls:*)",
"Bash(cat:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(ssh:*)",
"Bash(sudo:*)"
]
}
}
This gives Claude Code git operations and npm scripts, but blocks destructive commands and network calls from bash.
My recommended project-level settings.json
Here's the config I copy into every new project:
{
"permissions": {
"allow": [
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(npm run test:*)",
"Bash(npm run lint:*)",
"Bash(npm run build:*)",
"Bash(ls:*)",
"Bash(find:*)",
"Bash(cat:*)",
"Bash(echo:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push:*)",
"Bash(git reset --hard:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(ssh:*)",
"Bash(scp:*)",
"Bash(sudo:*)",
"Bash(chmod 777:*)",
"Bash(npm publish:*)",
"Bash(npm install -g:*)"
]
},
"env": {},
"includeCoAuthoredBy": false
}
What this does:
- ✅ Allows: reading files, git status/diff/log/add/commit, running tests/lint/build
- 🚫 Blocks: destructive deletes, force pushes, hard resets, network downloads, global installs, publishing
Why block git push? I want to review before anything leaves my machine. Claude can stage and commit, but I push manually.
Why block git reset --hard? This is the command from the infamous Claude Code git reset incident. One wrong reset and you lose uncommitted work.
The env field
This lets you inject environment variables into every Claude Code session without polluting your .env file:
{
"env": {
"NODE_ENV": "development",
"LOG_LEVEL": "debug"
}
}
Useful for dev/test mode flags you always want active during Claude sessions.
The includeCoAuthoredBy field
When true (default), Claude adds Co-Authored-By: Claude to your git commits. Set to false if:
- Your employer doesn't allow AI attribution in commits
- You're contributing to open source projects with attribution policies
- You just prefer cleaner commit messages
{
"includeCoAuthoredBy": false
}
User-level settings: the global baseline
Your ~/.claude/settings.json applies to every project. Good place for global rules:
{
"permissions": {
"deny": [
"Bash(sudo:*)",
"Bash(rm -rf /home:*)",
"Bash(rm -rf /*:*)"
]
},
"includeCoAuthoredBy": false
}
Project settings layer on top of this.
Quick reference: all permission tokens
| Token | What it controls |
|---|---|
Bash(cmd:*) |
Shell command execution |
Read |
File reading |
Write |
File writing |
Edit |
In-place file editing |
MultiEdit |
Multi-file editing |
WebFetch |
HTTP requests from tools |
WebSearch |
Web search tool |
TodoWrite |
Task list management |
Glob |
File pattern matching |
Grep |
File content search |
LS |
Directory listing |
Pro tip: start restrictive, expand as needed
The temptation is to allow everything and deny the obviously bad stuff. Flip this:
- Start with empty
allowand deny your biggest concerns - When Claude says it can't do something useful, add it to
allow - You'll end up with a minimal-permissions config that actually reflects how you work
Bonus: combine with CLAUDE.md
Use settings.json for what Claude can do. Use CLAUDE.md for how Claude should do it.
settings.json:
{
"permissions": {
"allow": ["Bash(npm run test:*)"],
"deny": ["Bash(npm publish:*)"],
}
}
CLAUDE.md:
## Testing
Always run tests before committing. Use `npm run test` not `node test.js`.
Never skip failing tests — fix them first.
The config controls the guard rails. The CLAUDE.md controls the behavior within those rails.
One more thing: if you're doing heavier API work with Claude (not just Claude Code), I use SimplyLouie as my ANTHROPIC_BASE_URL drop-in — flat $2/month vs paying per token. Set it once in .env, swap back anytime.
What's in your settings.json? Drop it in the comments — curious what restrictions people are actually running with.
Top comments (0)