settings.json is where Claude Code stops being "the agent" and starts being "your harness." Permission allowlists. Environment variables. Hook wiring. The default model and effort tier. Project-scoped overrides that pin team behavior. If CLAUDE.md is what the agent reads, settings.json is what shapes how the agent runs.

This is a practical reference -- the keys that pay off, where to put them, and the project-vs-user split that keeps team and personal preferences from contaminating each other. Chapter 3 of Claude Code in Production is the long version.

Where settings live

Settings layer: local overrides project overrides user. The most specific scope wins on conflicts. The model/effort floor pattern uses this -- project pins the floor, user can raise but not lower.

Permission allowlists

The single most useful key. Every tool call (Bash command, file write, MCP call) is gated by default; an allowlist entry pre-approves the matching shape so the agent does not prompt you every time. Add the shapes you trust:

{ "permissions": { "allow": [ "Bash(npm test:*)", "Bash(npm run lint:fix)", "Bash(git status)", "Bash(git diff:*)", "Bash(git log:*)", "Read", "Grep", "Glob" ], "deny": [ "Bash(rm -rf /:*)" ] } }

Pre-approving read-only and obviously-safe shapes (the test command, common git read ops, the read/grep/glob built-ins) eliminates the prompt-storm without giving up safety on the writes that matter. The /fewer-permission-prompts skill in Yaw Mode generates an allowlist from your recent transcripts -- a good way to seed the file.

Hook wiring

Hooks attach to events (PreToolUse, PostToolUse, UserPromptSubmit, Stop) with optional matchers. See the hooks guide for the full pattern; the settings shape is:

{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [{"type": "command", "command": "~/.claude/hooks/gh-pr-merge-admin-gate.sh"}] }, { "matcher": "Edit|Write", "hooks": [{"type": "command", "command": "~/.claude/hooks/canonical-source-gate.sh"}] } ] } }

Model and effort defaults

Pin the model and effort tier so the team gets consistent output regardless of who's running. Project-scoped, checked into git:

{ "model": "claude-opus-4-7", "effort": "xhigh" }

This is what the "default to flagship at the backend's recommended effort" discipline looks like in writing. Per-user overrides can raise (someone debugging a hard problem bumps to max) but should not lower below the project floor on shared work.

Environment variables

Variables Claude Code passes into every tool call. Useful for surfacing project state to scripts and hooks without per-call wiring:

{ "env": { "PROJECT_ROOT": "/Users/jeff/yaw/yaw.sh", "DEPLOY_ENV": "staging" } }

Project vs user: what goes where

Common mistakes

Want the full reference?

Claude Code in Production Chapter 3 covers every key in the file, the project-as-tooling-contract pattern from Chapter 11, the migration story when settings.json shape evolves, and the worked examples of each pattern in production.

Claude Code in Production

The Claude Code book and practitioner's guide. Twelve chapters. PDF + EPUB. Free updates. $39 one-time, secure checkout.

Read more & buy $39

Published by Yaw Labs.

Related