Agent Skills: Claude Code Settings

Claude Code settings files — which config lives where (user / project / project-local / managed, and their precedence) plus a runnable convention-validator hook recipe that blocks actions violating repo rules. Use when editing settings.json or .claude config, deciding which scope a key belongs in, or building a hook that enforces a convention (commit/branch/file rules). For hooks internals see smith-ctx-claude; for permissions/auto-mode see smith-auto_mode.

UncategorizedID: tianjianjiang/smith/smith-settings

Install this agent skill to your local

pnpm dlx add-skill https://github.com/tianjianjiang/smith/tree/HEAD/smith-settings

Skill Files

Browse the full folder contents for smith-settings.

Download Skill

Loading file tree…

smith-settings/SKILL.md

Skill Metadata

Name
smith-settings
Description
Claude Code settings files

Claude Code Settings

Scope: Settings file layout + scope precedence, and a convention-validator hook recipe. NOT a hooks or permissions deep-dive — those live elsewhere. Load if: Editing settings.json / .claude config, choosing which scope a key belongs in, OR building a hook that enforces a repo convention. Prerequisites: @smith-ctx-claude/SKILL.md (hooks + permission-mode deep-dive), @smith-ctx-claude-mode-auto/SKILL.md (permissions, $defaults, classifier) Authoritative source: Claude Code settings, hooks (verified 2026-06-25)

CRITICAL: One Key, One Scope

  • Put a key in the RIGHT file: shared team config → committed .claude/settings.json; personal/secret/machine-specific → gitignored .claude/settings.local.json; cross-project defaults → ~/.claude/settings.json.
  • A key set in a higher-precedence scope overrides the same key lower down; omitting it leaves the lower value in place (keys merge, they don't wipe).
  • permissions.defaultMode: "auto" is honored ONLY in ~/.claude/settings.json — it is ignored in project/local settings, so a repo can't grant itself auto.
  • Cross-reference @smith-ctx-claude/SKILL.md and @smith-ctx-claude-mode-auto/SKILL.md for hook events/handlers or permission rules instead of re-documenting them here (DRY).
  • Keep secrets and personal defaultMode overrides in .local.json — .claude/settings.json ships to every teammate.

Settings files & precedence

Four scopes, highest precedence first (a managed policy can't be overridden):

  • Managed policy settings — org/MDM deployed; absolute.
  • .claude/settings.local.json — your personal, gitignored project overrides.
  • .claude/settings.json — committed, shared project config.
  • ~/.claude/settings.json — your cross-project user defaults.

Command-line --settings <file-or-json> merges as a temporary top layer. The same scope names appear as ConfigChange hook matchers (user_settings, project_settings, local_settings, policy_settings, skills) — use that event to audit or block settings changes.

Convention-validator hook recipe

A PreToolUse hook can ENFORCE a repo convention by rejecting the offending tool call (exit 2 blocks it and shows stderr to Claude). The if field narrows the handler to just the calls you care about, using permission-rule syntax. Example: block any git commit made on a protected branch — enforcing the smith "never commit to main/master/develop" rule mechanically.

In committed .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-protected-commit.sh",
            "args": [],
            "if": "Bash(git commit *)"
          }
        ]
      }
    ]
  }
}

args is set (to []) because command uses the ${CLAUDE_PROJECT_DIR} path placeholder — that selects exec form, where the placeholder is substituted and no shell re-tokenizes the path.

In .claude/hooks/block-protected-commit.sh (chmod +x):

#!/usr/bin/env bash
set -euo pipefail
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
case "$branch" in
  main|master|develop)
    echo "Blocked: commit on protected branch '$branch'. Use a feature branch." >&2
    exit 2
    ;;
esac
exit 0

Generalize the same shape: swap the if pattern and script to validate branch names (Bash(git checkout -b *)), file paths (Edit(*)), or a commit-message format. For richer control than exit 2, a PreToolUse hook can return hookSpecificOutput.permissionDecision: "deny" with a reason — see @smith-ctx-claude/SKILL.md.

Related

  • @smith-ctx-claude/SKILL.md - Hook events/handlers, permission modes (deep-dive)
  • @smith-ctx-claude-mode-auto/SKILL.md - Permissions rules, $defaults, classifier lists
  • @smith-dev/SKILL.md - Pre-commit checks this hook can enforce
  • @smith-git/SKILL.md - The protected-branch rule the recipe enforces

Before You Finish

Placing a key:

  1. Shared team behavior → committed .claude/settings.json
  2. Personal/secret/machine-specific → gitignored .claude/settings.local.json
  3. Cross-project default → ~/.claude/settings.json (only home for auto)

Building a convention validator:

  1. PreToolUse + matcher: "Bash" + an if permission-rule to scope it
  2. Script exits 2 to block (stderr is shown to Claude); use exec form (args) when command references a ${CLAUDE_PROJECT_DIR} path placeholder