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 з чистим config-файлом у тимчасовій теці — через змінну 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»: кожна цифра перевірена за першоджерелом, ключові — щонайменше за двома незалежними; прогнози — лише сценарії з умовами. Теза без даних не публікується.