headroom.walls.sh · settings

Claude Code settings.json

Complete reference for ~/.claude/settings.json — every field, with examples and the statusLineHook that powers live usage display.

File locations

Claude Code reads settings from two places, merging them (project wins over user):

FileScope
~/.claude/settings.jsonUser-level — applies to every project
.claude/settings.jsonProject-level — applies only in this repo

Create either with claude config or edit directly. Both are plain JSON with no schema validation — typos fail silently, so double-check key names.

Top-level fields

model

Set the default model for all sessions.

{
  "model": "claude-sonnet-4-6"
}

Overridden by --model on the CLI or /model inside a session. Valid values: any Claude model ID (e.g. claude-opus-4-8, claude-haiku-4-5-20251001).

permissions

Control which tools Claude Code can use without asking for confirmation. Structure:

{
  "permissions": {
    "allow": [
      "Bash(git:*)",
      "Bash(npm run *)",
      "Read(**)",
      "Edit(**)"
    ],
    "deny": [
      "Bash(rm -rf *)"
    ]
  }
}

Each entry is ToolName(pattern). The pattern is matched against the tool's input. allow entries skip the confirmation prompt; deny entries block without prompting. Deny takes precedence over allow.

Common patterns:

PatternWhat it allows
Bash(*)All shell commands without prompting
Bash(git:*)Any git command
Bash(npm run *)npm run scripts only
Read(**)Reading any file
Edit(**)Editing any file
WebFetch(*)Fetching any URL

env

Environment variables injected into every Claude Code session and all hooks.

{
  "env": {
    "ANTHROPIC_SMALL_FAST_MODEL": "claude-haiku-4-5-20251001",
    "NODE_ENV": "development"
  }
}

includeCoAuthoredBy

Whether to append the Co-Authored-By: Claude trailer to commits Claude Code creates. Defaults to true.

{
  "includeCoAuthoredBy": false
}

cleanupPeriodDays

How many days before Claude Code prunes old conversation transcripts. Defaults to 30.

{
  "cleanupPeriodDays": 7
}

hooks

Hooks are shell commands Claude Code runs at specific lifecycle events. Each hook receives structured JSON on stdin and can write structured JSON to stdout to influence Claude Code's behavior.

{
  "hooks": {
    "PreToolUse": [...],
    "PostToolUse": [...],
    "Stop": [...],
    "Notification": [...],
    "SubagentStop": [...],
    "PreCompact": [...]
  }
}

Each hook is an array of hook objects:

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Claude stopped'"
          }
        ]
      }
    ]
  }
}

statusLineHook — the most useful hook

The statusLineHook field (a sibling of hooks, not inside it) runs a command every time Claude Code refreshes its status line. The command's stdout becomes the text shown. It also writes usage data to ~/.claude/headroom-usage.json, which is how Headroom reads your live session and weekly percentages.

{
  "statusLineHook": "cat ~/.claude/headroom-usage.json 2>/dev/null | jq -r '"CC \(.sessionUsagePct|floor)%·\(.weeklyUsagePct|floor)%"' 2>/dev/null || echo 'CC --%'"
}

This is the complete setup for Headroom. Once this line is in your ~/.claude/settings.json, Headroom reads the file and shows your real usage. No other configuration needed.

The file ~/.claude/headroom-usage.json is written by Claude Code, not by Headroom. Headroom only reads it. This is why Headroom makes zero network calls — the data is already local.

Full JSON written by the hook:

{
  "sessionUsagePct": 34.2,
  "weeklyUsagePct": 61.8,
  "sessionCost": 0.42,
  "modelName": "claude-sonnet-4-6",
  "sessionResetSec": 9847,
  "weeklyResetSec": 198432
}

Full statusLineHook docs and examples · All status line fields explained

Complete example

A typical power-user ~/.claude/settings.json:

{
  "model": "claude-sonnet-4-6",
  "statusLineHook": "cat ~/.claude/headroom-usage.json 2>/dev/null | jq -r '"CC \(.sessionUsagePct|floor)%·\(.weeklyUsagePct|floor)%"' 2>/dev/null || echo 'CC --%'",
  "permissions": {
    "allow": [
      "Bash(git *)",
      "Bash(npm run *)",
      "Bash(make *)",
      "Read(**)",
      "Edit(**)"
    ]
  },
  "env": {
    "ANTHROPIC_SMALL_FAST_MODEL": "claude-haiku-4-5-20251001"
  },
  "includeCoAuthoredBy": true,
  "cleanupPeriodDays": 30
}

Project-level settings

Project-level settings at .claude/settings.json override user-level settings for the same keys. Useful for per-project model overrides or additional permissions for a specific codebase.

{
  "model": "claude-opus-4-8",
  "permissions": {
    "allow": [
      "Bash(docker *)",
      "Bash(kubectl *)"
    ]
  }
}

The statusLineHook should usually live in your user-level ~/.claude/settings.json, not project-level — you want usage visible everywhere, not just in one repo.

Applying changes

Changes to settings.json take effect the next time Claude Code starts or when you run /reload inside an active session. There's no watch mode — edits to the file mid-session require a reload.


Once the statusLineHook is set, Headroom shows your Claude Code session (5h) and weekly (7d) usage as a live % in the menu bar — color-coded before a limit stops you mid-task. Free, MIT, ~267 KB.

brew install --cask patwalls/tap/headroom

Hook setup docs
Rate limits explained
Claude Code tips and tricks
FAQ