раздел 06 · подстраница 2

Структура settings.json

Hooks живут в settings.json - один JSON-файл, три уровня (глобально / проект / локально). Знание иерархии решает 90% проблем "почему мой hook не срабатывает".

Зачем

Без чёткого понимания, где какой файл и какой приоритетнее, легко настроить hook, который никогда не вызовется (или вызовется не там). А ещё .local иногда коммитится по ошибке - и приватные настройки уезжают в git.

Три файла, три уровня

| Файл | Зона действия | Коммитим в git? | | ------------------------------------- | ----------------------------------- | --------------- | | ~/.claude/settings.json | Глобально, для всех проектов | Нет (домашний) | | <project>/.claude/settings.json | Конкретный проект, для всей команды | Да | | <project>/.claude/settings.local.json | Только ваша машина в этом проекте | Нет (gitignore) |

Иерархия применения

Hooks из всех трёх файлов складываются, не перекрывают друг друга. Сработают и глобальный, и проектный, и локальный - в порядке: project → user → local (зависит от события и от настроек, обычно все три по очереди).

Permissions и общие настройки - наоборот, локальный перекрывает проектный, проектный перекрывает глобальный.

Структура JSON

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "scripts/format.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"done\" with title \"Claude\"'"
          }
        ]
      }
    ]
  }
}

Ключевые поля

  • hooks - корневой объект, ключи = имена событий (см. предыдущую страницу).
  • matcher - паттерн для фильтрации. Для PreToolUse/PostToolUse - имена инструментов через |. Для UserPromptSubmit - regex по тексту промпта. "*" или пусто - срабатывает всегда.
  • hooks[] - массив команд. Каждая - объект { "type": "command", "command": "..." }.
  • command - shell-команда. Может быть путь к скрипту или однострочник. Запускается в bash -c.

matcher: примеры

"matcher": "Edit|Write|MultiEdit"   // только при правке файлов
"matcher": "Bash"                    // только bash-вызовы
"matcher": "*"                       // любой инструмент
"matcher": ""                        // тоже любой

Для UserPromptSubmit - regex по тексту:

"matcher": "deploy|выкат|пуш на прод"

Полный пример settings.json

{
  "model": "claude-opus-4-7",
  "theme": "dark",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read",
        "hooks": [
          {
            "type": "command",
            "command": "[[ \"$CLAUDE_FILE_PATHS\" == *\".env\"* ]] && echo 'blocked .env' >&2 && exit 1; exit 0"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/format.sh"
          },
          {
            "type": "command",
            "command": ".claude/hooks/run-tests.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude finished\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  },
  "permissions": {
    "allow": ["Bash(npm test:*)", "Bash(git status)"]
  }
}

Безопасные правки: команда /update-config

JSON ломается легко: лишняя запятая, незакрытая скобка - и Claude вообще перестаёт стартовать. Чтобы не править руками, используйте встроенный skill:

> /update-config
> /update-config добавь hook PostToolUse: автоформат .py через black
> /update-config разреши Bash(npm test:*) глобально

Skill сам найдёт нужный уровень файла, провалидирует JSON и применит правку.

Где живут вспомогательные скрипты

Удобный паттерн - класть hook-скрипты в .claude/hooks/<name>.sh рядом с settings:

project/
├── .claude/
│   ├── settings.json
│   ├── settings.local.json   ← в .gitignore
│   └── hooks/
│       ├── format.sh
│       └── run-tests.sh

Не забудьте chmod +x .claude/hooks/*.sh.

Антипаттерны

  • Хардкод абсолютных путей в проектном settings.json - сломаете коллегам.
  • Команды в command с двойными кавычками без экранирования - JSON порвётся.
  • Положить settings.local.json под git - утекут локальные настройки и токены.
  • Hooks без таймаута - заблокируют Claude навсегда при зависании.

Полезные ссылки