DEV Community

brian austin
brian austin

Posted on

Claude Code settings.json: the one config file most developers ignore

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)
Enter fullscreen mode Exit fullscreen mode

Project-level overrides user-level. Both are JSON.

The structure

{
  "permissions": {
    "allow": [],
    "deny": []
  },
  "env": {},
  "includeCoAuthoredBy": true
}
Enter fullscreen mode Exit fullscreen mode

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:*)"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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:

  1. Start with empty allow and deny your biggest concerns
  2. When Claude says it can't do something useful, add it to allow
  3. 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:*)"],
  }
}
Enter fullscreen mode Exit fullscreen mode

CLAUDE.md:

## Testing
Always run tests before committing. Use `npm run test` not `node test.js`.
Never skip failing tests — fix them first.
Enter fullscreen mode Exit fullscreen mode

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)