Chapter 23: settings.json Overview
Learning Objectives
Understand the priority and purpose of the four types of settings files, and know where to place settings for teams, individuals, and experiments.
Four Types of Settings
flowchart TB
Final["Final Effective Settings"] --> Override["Override from High to Low"]
Override --> CMD["1. Command-line Flag
(Highest Priority)"]
Override --> Local["2. .claude/settings.local.json
(Project Local, gitignore)"]
Override --> Project["3. .claude/settings.json
(Project Shared, in git)"]
Override --> User["4. ~/.claude/settings.json
(User-level)"]
Override --> Default["5. Claude Code Default
(Lowest)"]
style Local fill:#fff9c4
style Project fill:#c8e6c9→ Higher priority overrides lower priority. In case of conflict, local wins.
Role of Each File
| File | Who Writes/Reads | Example Content |
|---|---|---|
~/.claude/settings.json |
You (configure once, effective everywhere) | Default model, theme, global hooks |
<project>/.claude/settings.json |
Team Shared (committed to git) | Project-level permissions, shared hooks, agent defaults |
<project>/.claude/settings.local.json |
Personal within Project (not committed to git) | Personal credentials, local paths, experimental settings |
| Command-line flag | Temporary (one-time) | claude --model haiku for a quick task |
gitignore Strategy
.claude/
├── agents/ ← in git (team shared agents)
├── commands/ ← in git
├── hooks/ ← in git
├── settings.json ← in git
├── settings.local.json ← .gitignore (personalization)
├── telegram-notify.json ← .gitignore (credentials)
└── .notify-sent ← .gitignore (runtime state)
Our project's .claude/.gitignore:
.notify-sent
telegram-notify.json
settings.local.json
Quick Reference for Common Fields
{
"model": "claude-opus-4-7",
"permissions": {
"defaultMode": "bypassPermissions",
"allow": ["Bash(npm:*)"],
"deny": ["Bash(sudo:*)"]
},
"hooks": {
"PreToolUse": [...],
"Stop": [...]
},
"env": {
"PYTHONPATH": "src/"
},
"includeCoAuthoredBy": false
}
| Field | Purpose |
|---|---|
model |
Default model (used by main Claude) |
permissions |
Detailed in Chapter 24 |
hooks |
Detailed in Ch 25/26 |
env |
Environment variables injected into all Bash subprocesses |
includeCoAuthoredBy |
Whether to add Co-Authored-By: Claude to commits |
Personal vs. Team Examples
// ~/.claude/settings.json (Your personal preferences, cross-project)
{
"model": "claude-opus-4-7",
"includeCoAuthoredBy": false
}
// <project>/.claude/settings.json (Team shared)
{
"permissions": {
"defaultMode": "bypassPermissions",
"deny": ["Bash(sudo:*)", ...]
},
"hooks": { ... }
}
// <project>/.claude/settings.local.json (Your personal settings for this project)
{
"env": {
"TELEGRAM_BOT_TOKEN": "xxx",
"TELEGRAM_CHAT_ID": "yyy"
}
}
Verifying Settings Take Effect
After starting Claude Code, run:
/help view active settings
/permissions view parsed permission rules
Or:
# See which settings files are loaded
ls -la ~/.claude/settings.json
ls -la <project>/.claude/settings.json
ls -la <project>/.claude/settings.local.json
Anti-patterns
❌ Writing credentials into project shared settings.json (will be pushed to GitHub)
❌ Putting team consensus into settings.local (others won't see it)
❌ Setting overly strict deny rules at the user level (affects all projects)
❌ Incorrect JSON (missing commas, single quotes) (settings silently fail to apply)
What You Can Do Now
- Place each setting in the correct location
- Use .gitignore to prevent credentials from being exposed
- Verify that settings have taken effect
The next chapter will formally discuss the permissions field—the security guardrail for multi-agent systems.