settings.json и иерархия настроек Claude Code: permissions, sandbox, hooks и как их отлаживать

18 мин. чтения

Коротко (TL;DR)

settings.json — это конфигурационный файл Claude Code, где живут разрешения (permissions), переменные окружения, хуки, модель и десятки других ключей. В отличие от CLAUDE.md, который даёт агенту поведенческие подсказки, settings.json — это техническое принуждение: то, что записано в permissions, соблюдается детерминированно, а не «на доверии».

Что важно понять сразу:

  • Настройки лежат на пяти уровнях с жёстким приоритетом: managed (организация) → аргументы командной строки → local → project → user.
  • Массивы (например, permissions.allow) между уровнями не заменяются, а складываются — с двумя исключениями.
  • Правила permissions вычисляются в порядке deny → ask → allow: первое совпадение решает исход.
  • Включённый sandbox сокращает количество запросов на подтверждение на 84% (внутренняя статистика Anthropic) — и это правильный способ ускориться, а не --dangerously-skip-permissions.
  • Когда «настройка не применяется», разбираться помогает связка /status, /config, /permissions и /doctor.

Ниже — как устроена иерархия, как настроить permissions и sandbox безопасно, какие ключи полезны, какие тут реальные риски и как отлаживать конфиг, когда он ведёт себя не так.

settings.json и CLAUDE.md: разное назначение

Новички часто путают два файла и пытаются «настраивать» агента через CLAUDE.md. Официальное разграничение простое: settings — для технического принуждения, CLAUDE.md — для поведенческих договорённостей. CLAUDE.md рассказывает Claude, как устроен проект и как в нём принято работать; settings.json задаёт жёсткие рамки — что инструменту можно, а чего нельзя, и это соблюдается кодом.

Практический вывод: правило «не читай .env» в CLAUDE.md — пожелание, которое можно обойти; то же правило в permissions.deny — барьер. Всё, что критично (секреты, деструктивные команды), живёт в settings.json. Держите это разделение в голове — оно объясняет половину вопросов новичков «почему агент сделал то, что я запретил».

Пять уровней настроек и их приоритет

Claude Code собирает настройки из нескольких источников. Приоритет — от организации к личным предпочтениям:

ПриоритетУровеньГде лежит
1 (высший)Managed (организация)Системный путь / MDM, ставит админ
2Аргументы командной строкиФлаги при запуске claude
3Local (личный по проекту).claude/settings.local.json
4Project (командный).claude/settings.json (в git)
5 (низший)User (личный)~/.claude/settings.json

Логика такая: ~/.claude/settings.json задаёт ваши глобальные предпочтения для всех проектов; .claude/settings.json в репозитории — общие правила команды (коммитятся в git); .claude/settings.local.json — ваши личные переопределения для конкретного проекта. Последний Claude Code сам добавляет в .gitignore при создании, чтобы личные настройки не утекли в общий репозиторий. Managed-уровень стоит над всеми: правило, заданное администратором организации, локальным файлом перебить нельзя — это и есть смысл корпоративного контроля.

Как складываются значения между уровнями

Здесь тонкость, которую почти никто не объясняет. Скалярные ключи (одно значение — например, model) переопределяются по приоритету: выигрывает более высокий уровень. А вот массивы (permissions.allow, permissions.deny и подобные) между уровнями конкатенируются и дедуплицируются, а не заменяются.

Разберём на примере. Пусть в user-файле стоит "allow": ["Bash(git *)"], а в проектном — "allow": ["Bash(npm *)"]. Агент получит оба разрешения: и git, и npm. Массивы не конкурируют — они суммируются. То же с deny: запрет, заданный в managed-настройках, останется в силе, даже если в проектном файле его нет. Это важно понимать, иначе легко удивиться, откуда взялось разрешение, которого нет в вашем текущем файле.

Есть исключения. fallbackModel не складывается: его значение берётся с одного уровня целиком. С availableModels тоньше — он перестаёт мёржиться, только если его задаёт managed-источник (политика организации): тогда применяется именно этот список, а не сумма. На обычных уровнях (user, project, local) availableModels ведёт себя как любой другой массив — конкатенируется и дедуплицируется. Об этой оговорке не пишет ни один популярный гайд, а поведение неочевидное.

Ещё деталь про надёжность. Managed-настройки парсятся толерантно: если в них попала запись, не проходящая схему, Claude Code вырежет только её и применит остальное. Пользовательские, проектные и локальные файлы, наоборот, строгие — одна ошибка в JSON, и файл не применится целиком. Поэтому после ручной правки всегда проверяйте, что JSON валиден: пропущенная запятая молча «выключит» весь ваш settings.json.

permissions: allow, ask и deny

Ядро settings.json — блок permissions. Правила в нём вычисляются в строгом порядке: deny → ask → allow. Первое совпадение определяет исход, дальше поиск не идёт. Значит, deny всегда сильнее allow: если действие подпадает под запрет, никакое разрешение его не откроет.

Разберём на сценарии. Допустим, у вас allow: ["Bash(git *)"], но при этом deny: ["Bash(git push *)"]. Команда git status пройдёт по allow, а git push упрётся в deny — потому что deny проверяется первым. Так строится модель «в целом можно работать с git, но пушить — только вручную».

Три типа правил:

  • allow — разрешить без вопросов (например, Read(src/**), Bash(npm test)).
  • ask — всегда спрашивать, даже если что-то ещё это разрешает.
  • deny — запретить жёстко, поверх всего.

Режим по умолчанию задаёт defaultMode. Основные значения: default (спрашивать в неоднозначных случаях), acceptEdits (принимать правки файлов без вопросов), plan (только планировать, ничего не выполнять), bypassPermissions (пропускать все запросы).

Ещё важный синтаксический нюанс. «Голое» имя инструмента (Bash) в правиле относится к нему целиком, а точечный паттерн (Bash(curl *)) — только к конкретной команде. Путать их — частая ошибка: правило получается либо слишком широким (запретили весь Bash), либо дырявым (закрыли не то).

Про bypassPermissions — честно

bypassPermissions (он же флаг --dangerously-skip-permissions) пропускает все подтверждения, кроме форсированных явными ask-правилами. Единственный встроенный предохранитель — удаление корня и домашней папки (rm -rf / и rm -rf ~) он всё же блокирует. Всё остальное — на ваш риск, поэтому запускать его стоит только в контейнере или изолированной среде, а не на рабочей машине. Если цель — просто меньше кликать «разрешить», для этого есть более безопасный инструмент, о нём ниже.

Паттерн защиты секретов

Официально рекомендованный способ закрыть чувствительные файлы — связка deny на чтение секретов и на канал их утечки:

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Bash(curl *)"
    ]
  }
}

Смысл именно в паре: закрыть чтение .env мало — нужно перекрыть и очевидный канал эксфильтрации (curl), иначе агент, прочитав ключ иным путём, сможет его «отправить». Это тот случай, когда одно правило без другого создаёт ложное чувство защиты.

Sandbox и безопасность: как ускориться правильно

Постоянные запросы на подтверждение раздражают, и велик соблазн отключить их совсем. Правильный ответ — не bypassPermissions, а sandbox. По внутренней статистике Anthropic, включённый песочный режим безопасно сокращает количество запросов на 84%: агент работает в изоляции — запись только в рабочую папку, ограничения сети, — поэтому подтверждать каждое действие уже не нужно. Bash-sandbox поддерживается на macOS, Linux и WSL2.

Идея в разделении: sandbox даёт свободу действий внутри безопасной песочницы, а deny-правила закрывают то, что не должно случиться никогда. Вместе они снимают почти весь поток запросов, не открывая при этом машину нараспашку, как делает bypassPermissions.

Риски: почему границы важны

Раздел, который в туториалах по settings.json обычно опускают. Настройки прав — это не формальность: реальные инциденты показывают, что происходит, когда границы заданы неаккуратно.

  • Инцидент Wolak (октябрь 2025). Разработчик сообщил, что Claude Code выполнил rm -rf, удалив домашнюю директорию, — на Ubuntu/WSL2, причём без --dangerously-skip-permissions. Публичный баг-репорт стал одним из триггеров усиления предохранителей.
  • Инцидент с ~/ (декабрь 2025). Развёрнутый путь rm -rf ~/ привёл к удалению домашней папки — классическая ловушка развёртывания тильды оболочкой.
  • Баг наследования у субагентов (июль 2026). Рабочие субагенты не наследовали allow-правила из settings.local.json и спрашивали подтверждение на каждый вызов инструмента — пример того, как тонкости scope ломают ожидаемое поведение прав.
  • Инъекция через документ (2026). Отдельный, но родственной природы риск: prompt injection через невидимый текст в .docx показал, что модель permissions приходится держать в уме и при работе с чужими файлами, а не только с командами.

Вывод не «Claude Code опасен», а «границы задаём мы». Sandbox плюс аккуратные deny-правила (секреты, деструктивные операции) снимают почти весь риск, не превращая работу в бесконечное «разрешить?». Баланс, который стоит держать: по умолчанию — запрет на опасное, свобода — внутри песочницы.

Полезные ключи settings.json

Кроме permissions, в settings.json есть ключи, которые стоит знать:

КлючЧто делаетПрименяется
modelМодель по умолчанию (например, Claude Sonnet 5 или Opus)Требует рестарта сессии
envПеременные окружения для всех сессий и подпроцессовНа лету
hooksКоманды на события жизненного цикла агентаНа лету
apiKeyHelperВнешняя команда, отдающая API-ключ (шлётся как заголовок)
companyAnnouncementsОбъявления, показываемые при старте

Про перезагрузку: Claude Code следит за файлами настроек и перечитывает их на лету при изменении, так что правки большинства ключей применяются к текущей сессии сразу. Исключение — ключи вроде model и outputStyle: они требуют рестарта.

Ключ env удобен, когда нужно прокинуть переменную во все сессии и подпроцессы, — например, задать прокси или флаг для инструмента. Тут есть нюанс: переменные вроде NO_COLOR через env уходят в подпроцессы, но не меняют цвета самого интерфейса Claude Code — для интерфейса такую переменную ставят в shell до запуска claude. А hooks заслуживают отдельного упоминания: объявляются они прямо в settings.json и вешают вашу shell-команду на событие жизненного цикла. Простейший пример — уведомление:

{
  "hooks": {
    "Notification": [
      { "matcher": "", "hooks": [ { "type": "command", "command": "notify-send 'Claude ждёт ввод'" } ] }
    ]
  }
}

Хуки — это то, что превращает договорённости из пожеланий в гарантии: линтер после каждой правки, блокировка опасной команды до её выполнения. Это тема отдельного разбора, но знать, что хуки живут именно в settings.json, важно уже сейчас: этот файл, в отличие от конфигов редакторов вроде Cursor, совмещает и права, и автоматизацию в одном месте.

Ещё пара ключей, о которых полезно знать заранее. apiKeyHelper — это внешняя команда, которую Claude Code запускает через системную оболочку, чтобы получить API-ключ; её вывод отправляется как заголовок авторизации. Приём удобен, когда ключ нельзя хранить в открытом виде: helper достаёт его из менеджера секретов на лету. А блок worktree.* управляет фоновой работой в изолированных git-worktree (например, worktree.baseRef — от какой ветки ответвляться): эти настройки живут по своим правилам scope и не всегда мёржатся по общему приоритету, так что если вы гоняете параллельные фоновые сессии, их конфигурацию проверяйте отдельно. Знать про эти ключи заранее полезно: наткнувшись на них в чужом settings.json, вы не будете гадать, откуда взялось «магическое» поведение.

Быстрый старт: рабочий settings.json за 5 минут

Чтобы теория не осталась теорией, вот минимальный, но осмысленный проектный .claude/settings.json, с которого разумно начать почти любой репозиторий:

{
  "model": "claude-sonnet-5",
  "permissions": {
    "allow": [
      "Read(src/**)",
      "Bash(npm run test)",
      "Bash(npm run lint)",
      "Bash(git status)",
      "Bash(git diff *)"
    ],
    "ask": [
      "Bash(git push *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Bash(curl *)"
    ]
  },
  "env": {
    "NO_COLOR": "1"
  }
}

Разберём по строкам, что здесь заложено и почему:

  • model фиксирует модель проекта — чтобы вся команда работала на одной, а не на той, что случайно выбрана в чьих-то личных настройках.
  • allow открывает рутину без вопросов: читать исходники, гонять тесты и линт, смотреть статус и диффы git. Это те действия, подтверждать которые каждый раз — только терять время.
  • ask оставляет ручной контроль там, где цена ошибки высока: git push всегда спросит, даже несмотря на общее разрешение работать с git. Это тот самый порядок deny → ask → allow в действии.
  • deny закрывает секреты и канал их утечки — паттерн, который мы разобрали выше.
  • env прокидывает переменную во все сессии и подпроцессы; здесь для примера отключён цвет в подпроцессах, так же задают прокси или флаги инструментов (на цвет самого интерфейса Claude Code этот ключ не влияет).

Положите этот файл в .claude/settings.json, закоммитьте — и вся команда получит одинаковые правила. Личные отклонения (например, вы хотите разрешить себе ещё пару команд) добавляйте в .claude/settings.local.json, который не попадёт в git. Через пару недель работы вы уже будете точечно расширять allow под привычки проекта — но стартовый скелет закрывает 90% потребностей.

Диагностика: когда настройка не применяется

Главная боль — «я поменял settings.json, а ничего не изменилось». Вот рабочий чек-лист.

КомандаЧто показывает
/statusКакие уровни настроек загружены в сессию (строка Setting sources)
/configТекущие значения; с v2.1.181 можно менять по одному: /config key=value
/permissionsИтоговые правила allow/deny после всех мёржей
/contextЧто реально попало в контекст
/doctorОбщая диагностика окружения

Порядок разбора обычно такой. Сначала /status — убедиться, что нужный файл вообще подхватился (частая причина — невалидный JSON в строгом user- или project-файле, который не применился целиком). Затем /permissions — посмотреть, не перекрыто ли ваше allow чьим-то deny с более высокого уровня (вспоминаем порядок deny → ask → allow). Если поведение странное и вы подозреваете накопленные настройки, запустите Claude Code с чистым конфигом во временной папке — через переменную CLAUDE_CONFIG_DIR, указывающую на пустой каталог. Так вы проверите, воспроизводится ли проблема «с нуля» или её создаёт что-то в ваших файлах. Этот приём экономит часы: он сразу отделяет «баг инструмента» от «моей опечатки в JSON».

FAQ

Чем settings.json отличается от CLAUDE.md? settings.json — техническое принуждение (permissions, sandbox, hooks): соблюдается детерминированно. CLAUDE.md — поведенческие подсказки: советы, которые можно обойти. Критичные ограничения — только в settings.json.

Какой уровень настроек главнее? Порядок приоритета: managed (организация) → аргументы командной строки → local → project → user. Managed-настройки админа перебить нельзя. Массивы при этом складываются со всех уровней, а не заменяются (кроме fallbackModel и availableModels).

Как безопасно убрать постоянные запросы на подтверждение? Включить sandbox — он сокращает запросы примерно на 84% за счёт изоляции. Это безопаснее, чем bypassPermissions/--dangerously-skip-permissions, который стоит запускать только в контейнере.

Как защитить .env и секреты? Через permissions.deny: закрыть и чтение (Read(./.env*), Read(./secrets/**)), и канал утечки (Bash(curl *)). Одно без другого дырявит защиту.

Почему правка settings.json не применилась? Три частые причины: невалидный JSON (строгий файл не применяется целиком), правило перекрыто deny с более высокого уровня, или ключ требует рестарта (model, outputStyle). Проверяйте через /status и /permissions.

Что такое managed-настройки и можно ли их обойти? Это настройки, которые задаёт администратор организации на системном уровне (через MDM или системный путь). Они стоят на вершине приоритета — ни project-, ни local-, ни user-файл их не перебьёт. Именно так компания централизованно закрывает опасные действия на всех машинах. В отличие от остальных файлов, managed-настройки парсятся толерантно: одна невалидная запись не выключит весь файл.

Нужно ли коммитить settings.json в git? .claude/settings.json — да, это общие правила команды, и держать их в репозитории правильно: новый разработчик клонирует проект и сразу получает те же разрешения и хуки. А .claude/settings.local.json — личные переопределения, Claude Code сам добавляет их в .gitignore, чтобы они не попали в общий репозиторий.

Курс «Claude Code с нуля до продакшена» · модуль «Конфиг, память, навыки». Полная программа и два маршрута обучения — на странице курса.

Предыдущий урок: CLAUDE.md: инструкция, которую агент читает · Следующий урок: Память Claude Code и memory rot

Поделиться
Связаться:
Крипто- и data-аналитик, инженер-программист (факультет компьютерных наук ХНУРЭ). В IT с 2008 года: администрировал корпоративный мониторинг в «Vodafone Украина», семь лет разрабатывал и продвигал веб-проекты, пять лет руководил маркетингом на метриках — конверсия, CTR, ROI, LTV.Криптовалютными рынками занимаюсь с 2021 года: ончейн-метрики, токеномика, макроэкономические индикаторы. Разработал собственную data-driven модель анализа рынка на 30+ метрик. Стек — Python (pandas, NumPy, SciPy, matplotlib), математическая статистика и EDA; сбор и сверку данных автоматизирую AI-агентами.Принцип — «Don't trust, verify»: каждая цифра проверена по первоисточнику, ключевые — минимум по двум независимым; прогнозы — только сценарии с условиями. Тезис без данных не публикуется.