Configuring Claude Code with settings.json

6 min·Jul 18, 2026
AI Summary

.claude/settings.json governs Claude Code in a repo. permissions has allow/deny/ask arrays of tool-pattern rules, and deny always wins. hooks run shell commands on events like PostToolUse. env injects variables; model overrides the model. Allow only narrow safe patterns, deny secret paths, and use ask for irreversible actions like git push.

Claude Code settings.json
A .claude/settings.json for Claude Code — permission allow/deny/ask rules, a PostToolUse hook, environment variables and a model override — the file that governs how the agent behaves in a repo.
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm run test:*)",
      "Bash(npm run lint:*)",
      "Read(./src/**)"
    ],
    "ask": [
      "Bash(git push:*)"
    ],
    "deny": [
      "Read(./.env)",
      "Bash(rm -rf:*)"
    ]
  },
  "env": {
    "NODE_ENV": "development"
  },
  "model": "claude-sonnet-4-5",
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATHS\""
          }
        ]
      }
    ]
  }
}

.claude/settings.json decides how Claude Code behaves in a project — what runs without asking, what is always blocked, and what happens automatically around each action.

permissions: allow, deny, ask

Three arrays of tool-pattern rules:

"permissions": { "allow": ["Bash(npm run test:*)", "Read(./src/**)"], "ask": ["Bash(git push:*)"], "deny": ["Read(./.env)", "Bash(rm -rf:*)"] }
  • allow — run without prompting. Keep patterns narrow.
  • ask — prompt every time. Right for irreversible actions.
  • deny — never allowed. deny always wins over allow.

Put secret paths and destructive commands in deny and you have a hard floor no allow rule can override.

hooks: run commands on events

Hooks fire shell commands on lifecycle events. A PostToolUse hook that formats after every edit:

"hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "npx prettier --write \"$CLAUDE_FILE_PATHS\"" } ] } ] }

env and model

env injects environment variables into the session; model overrides which model this project uses. Both are optional — an empty {} is a valid settings file.

Where it lives

Shared project rules go in .claude/settings.json; personal overrides in .claude/settings.local.json (git-ignored); global defaults in ~/.claude/settings.json.

Security notes

  • deny beats allow — lean on it for secrets and destructive commands.
  • Do not store API keys here; reference them via env or a separate secrets file.
  • Hook commands run automatically with your privileges — read them before trusting a shared config.

Open the Claude Code settings template and ask the workspace to "deny access to the .env file" or "add a hook that runs prettier after edits", then diff the result.

FAQ

Where do settings files live and which wins?

Project settings are in .claude/settings.json (shared) and .claude/settings.local.json (personal, git-ignored); user settings are in ~/.claude/settings.json. More specific scopes and deny rules take precedence.

What can a hook do?

A hook runs a shell command on an event — e.g. PostToolUse after an edit to auto-format, or Stop when the agent finishes. Hooks run with your shell privileges, so review them.

Related templates