1. Одного особистого налаштування вже замало
Коли ви працюєте наодинці над маленьким експериментом, легко вирішити, що достатньо вибрати акуратний permission mode у своїй сесії й жити спокійно. Але щойно з'являються команда, спільний репозиторій і зони, куди краще не залітати без каски, особистого налаштування стає замало. Один обережний, інший поспішає, третій відкрив не той worktree. Claude в усіх один, а наслідки його дій для репозиторію спільні.
Давайте візьмемо Commerce OS. Звичайне review-required завдання: підправити порядок refund-запитів у вхідних зверненнях підтримки. Читати support/**, ганяти тести, правити код поруч із проблемою й не чіпати payments/**, migrations/**, .env*. Але домовленість, що живе лише в голові або в поточному prompt, крихка: сьогодні Claude чесно лишився в підтримці, завтра вирішив «трохи поліпшити» сусідній код у платежах. І ось уже не bugfix, а сюрприз у двох бізнес-критичних каталогах.
У термінах уже знайомої моделі тут і видно межу capability envelope: він добре описує рамку одного завдання, але сам по собі не робить її правилом репозиторію. За це відповідають L3 permissions. L1 відповідає: що дозволено мені в цій сесії. L3 — що взагалі допустимо для команди в репозиторії. Командний baseline не залежить від настрою, дедлайну й кількості кофеїну в крові.
Тут корисна проста аналогія. CLAUDE.md із фразою «не чіпай payments/» — це табличка на дверях. Хороша, ввічлива. Protected path і deny-rule — це замок. Якщо вся безпека тримається на табличці, то це не політика, а дуже вихована надія.
Ось такий фрагмент у CLAUDE.md корисний:
## Обмеження проєкту
Не редагуй `payments/`, `migrations/` і `.env*` без явного схвалення.
Але сам текст ще не заважає інструменту туди записати. Він фіксує намір; enforcement живе в іншому шарі.
2. Три рівні permissions і місце L3
Щоб не заплутатися в термінах, усю трирівневу модель варто один раз спокійно побачити цілком. Інакше L1, L2 і L3 починають змішуватися в один великий клубок, де вже незрозуміло, хто що обмежує і чому одна й та сама заборона іноді спрацьовує, а іноді ні. Рівні не конкурують — накладаються один на один.
| Рівень | На яке запитання відповідає | Хто володіє рішенням | Приклад |
|---|---|---|---|
| L1 — session permissions | Що Claude може робити в моїй поточній сесії? | Розробник | лише читання, спочатку план, запитувати перед редагуванням |
| L2 — agent permissions | Що може робити конкретний agent? | Автор agent’а / workflow designer | reviewer — тільки читання, tester — тести, без редагування |
| L3 — team permissions | Що взагалі дозволено команді в цьому репозиторії? | Команда / tech lead / managed policy | deny для payments/**, migrations/**, .env* |
Важливий момент: L3 не скасовує L1 і L2 — а накладається згори. Оголосили payments/** protected path — зона закрита, навіть коли в сесії дозволені edits, а агент уміє писати у файли. І навпаки: команда дозволила правки в support/** — reviewer-agent від цього не отримав право редагувати, його L2-контракт може залишатися read-only.
Можна запам’ятати це так:
L1 задає робочий режим розробника.
L2 задає межі конкретного агента.
L3 задає правила майданчика, на якому працюють усі.
На практиці все дуже приземлено: сесія дозволяє правки в support/ після підтвердження, reviewer-agent read-only, а team policy відправляє спроби писати в payments/**, migrations/**, .env* і destructive-команди в deny або на погодження. Система від цього не заплутується — стає передбачуванішою.
І ще одна важлива звичка курсу: точні назви режимів, ключів і команд змінюються від версії до версії, але самі рівні інваріантні. Бачите новий синтаксис — не панікуйте, а запитайте: це L1, L2 чи L3? І відразу зрозуміло, куди його покласти.
3. Allow, Ask і Deny — радіус дії, а не попапи
Дуже легко сприймати allow, ask і deny як дратівливі вікна підтвердження. Але це поганий ракурс: трійка описує не UX, а радіус дії помилки. Питання не в тому, скільки разів натиснути Enter, а чи доповзе невдала AI-дія до небезпечної зони.
Найзручніший спосіб мислити тут — через таку таблицю:
| Режим | Що це означає по суті | Де зазвичай доречний |
|---|---|---|
| allow | дія настільки безпечна, що її можна виконувати без зайвого тертя | читання файлів, пошук, запуск тестів, локальні діагностичні команди |
| ask | дія потенційно корисна, але має пройти через людське рішення | edit, write, git push, зміни поза вузьким approved scope |
| deny | дія надто ризикована для звичайного потоку роботи | protected paths, destructive-команди, secrets, force push |
Якщо зовсім по-людськи, allow — це зона, де Claude може вільно працювати, бо навіть помилка там зазвичай дешева й швидко помітна. Ask — робоча зона з review-межою: тут зміни потрібні, але ви хочете бачити, куди саме йде інструмент. Deny — це зона, де команда заздалегідь вирішила: ні, сюди через звичайний workflow не ходимо.
Нижче — невеликий концептуальний приклад. Точний синтаксис може відрізнятися у вашій версії, тому тут важливіша сама логіка, ніж кожна назва ключа:
{
"permissions": {
"allow": ["Read", "Grep", "Bash(./gradlew test*)"], // читання й перевірки
"ask": ["Edit", "Write", "Bash(git push:*)"], // дії з review-межою
"deny": ["Edit(./payments/**)", "Edit(./migrations/**)", "Edit(./.env*)"] // protected paths
}
}
Зверніть увагу: цей фрагмент не про «заборонити все», а про розумний поділ. Потягнете в ask кожне читання й тест — команда зненавидить і інструмент, і того, хто так налаштував. Перетягнете в allow взагалі все — схема перетвориться на декоративний напис на стіні. Гарне практичне правило таке: deny короткий, але жорсткий; ask покриває те, що змінює стан репозиторію або процесу; allow — безпечне дослідження, читання й перевірка.
Тут зручно зв’язати сьогоднішню тему з минулою лекцією про risk classification. Для low-risk режим м’якший: багато allow, трохи ask, той самий короткий deny. Для review-required читання й тести в allow, edits і push у ask. Для high-risk Claude готує план і артефакти, виконання лишається за людиною.
| Рівень ризику | Типовий L3-підхід |
|---|---|
| low-risk | allow для читання й безпечних правок у вузькій зоні, ask для push, deny для protected paths |
| review-required | allow для дослідження й тестів, ask для будь-яких edits, deny для чутливих зон |
| high-risk | AI переважно готує матеріали, а реальні дії залишаються за людиною |
Часта помилка новачка звучить так: попап заважає — отже, терміново розширюємо allow. Але повторюваний ask не завжди погане налаштування. Іноді це чесний сигнал, що ви зайшли в review-required зону. Так і треба.
4. Protected paths — правило стає замком
Є категорії файлів і каталогів, для яких загального «ну будьте обережні» недостатньо. Їх треба виділяти окремо й захищати так, щоб навіть за невдалого збігу обставин Claude не міг туди записати. Для цього й існують protected paths — локальні зони підвищеної важливості всередині репозиторію.
У Commerce OS хороші кандидати видно майже одразу: payments/**, migrations/**, .env*, іноді infra/** або конфіги прав доступу. Небезпечні вони не складністю, а дорогим blast radius помилки.
| Шлях | Чому його захищають |
|---|---|
| payments/** | платіжна логіка, гроші, повернення коштів, зовнішні провайдери |
| migrations/** | схема даних і потенційно незворотні зміни |
| .env* | secrets і конфігурація середовища |
| infra/** | середовище, деплой, доступи, загальна інфраструктура |
І ось тут особливо важливо пам’ятати ключову формулу лекції:
Prompt і CLAUDE.md задають намір.
Permissions, rules, hooks і protected paths забезпечують межі.
Тобто protected path — уже не просто текстова вказівка, а частина enforcement. Часто це зв’язка deny-rule плюс hook, який спрацьовує перед спробою запису:
{
"hooks": {
"PreToolUse": [{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": ".claude/hooks/block-protected-paths.sh" }]
}]
}
}
Сам hook може бути маленьким і просто перевіряти, чи не потрапляє цільовий шлях до списку захищених. Не треба перетворювати його на космічний корабель. Його завдання — зупинити запис до того, як він стався. Поруч зазвичай живе текстове правило:
# rules/no-secrets-in-prompts.md
Ніколи не вставляй API keys, tokens, passwords і production credentials
у prompts, task specs та приклади даних.
Навіщо і правило, і hook? Rule допомагає людині й Claude правильно мислити. Hook страхує, коли хтось усе ж спробував пройти туди, куди не слід. Один шар навчає, інший страхує.
Переборщити легко. Оголосіть protected path половину репозиторію — працювати стане неможливо, команда почне шукати обхідні шляхи, стратегія втратить довіру. Не «весь backend», а ті області, де помилка особливо дорога.
5. Managed settings і ієрархія командної політики
Навіть хороша permission strategy мало допомагає, якщо лежить не там, де її реально застосовує команда. На ранніх етапах це здається нудною адміністративною деталлю, але саме звідси ростуть історії формату «у мене все працює не так, як у вас» — правила розмазано по різних рівнях налаштувань.
| Рівень | Для чого підходить | Чого туди краще не класти |
|---|---|---|
| user | особисті зручності й персональні звички | командну security-політику |
| project | спільні правила репозиторію | особисті тимчасові експерименти |
| local | особисті налаштування для конкретного проєкту | обов’язковий baseline команди |
| managed | організаційні заборони й production-level policy | усе, що має вільно змінюватися кожним розробником |
Якщо сказати простіше, командна політика має жити там, де її видно й де вона працює для всіх: зазвичай project, у суворіших середовищах — ще й managed. Поклали критичне правило тільки в user settings — командної стратегії у вас немає, є особиста дисципліна одного розробника. Добре, але недостатньо.
Зручна структура у Workflow Kit може виглядати так:
.claude/
CLAUDE.md
settings.json
hooks/block-protected-paths.sh
rules/no-secrets-in-prompts.md
Кожен файл несе свою роль — контекст, дозволи, enforcement, правило поведінки. Разом — уже не хаотичний набір файлів, а система.
Окремо важливо сказати про local-рівень. Він корисний для нотаток, персональних preferences, налаштувань під налагодження. Але це погане місце для обов’язкової межі: правило про payments/** або .env*, що живе лише в чиїхось local settings, захищає не проєкт, а його ноутбук.
А ось managed-рівень потрібен там, де команда або організація хочуть закріпити справді незаперечні речі: не просто домовилися, а зафіксували згори. Заборона на direct push у protected branches, заборона на автоматичні destructive-команди в production-sensitive репозиторії. Будувати enterprise-машину одразу не потрібно, але призначення шару корисно розуміти заздалегідь.
6. Збираємо робочу L3-стратегію для Commerce OS
Тепер давайте складемо все в одну робочу картину, щоб сьогоднішня лекція не залишилася набором розумних слів. Візьмемо знайомий сценарій із Commerce OS: підправити порядок refund-запитів у вхідних зверненнях підтримки. На минулій лекції ми присвоїли б завданню label review-required і зібрали capability envelope. Сьогодні йдемо далі й перетворюємо цей label на командні межі.
| Артефакт | За що відповідає |
|---|---|
| RISK_CLASSIFICATION.md | визначає risk label і capability envelope |
| settings.json | провадить allow/ask/deny на рівні проєкту |
| rules/no-secrets-in-prompts.md | пояснює командне правило поведінки |
| hooks/block-protected-paths.sh | технічно блокує запис у небезпечні зони |
| CLAUDE.md | дає контекст проєкту, команди й домовленостей, але не забезпечує enforcement |
Для нашого review-required завдання підсумковий фрагмент може виглядати так:
Risk level: review-required
Allowed: Read, Grep, tests, edits у `support/**`
Ask: write поза approved scope, `git push`
Forbidden: `payments/**`, `migrations/**`, `.env*`, force push
Rollback: revert PR, regression test залишається в репозиторії
А поруч — фрагмент settings.json:
{
"permissions": {
"allow": ["Read", "Grep", "Bash(./gradlew test*)", "Edit(./support/**)"], // робоча зона завдання
"ask": ["Write", "Bash(git push:*)"], // review-межа
"deny": ["Edit(./payments/**)", "Edit(./migrations/**)", "Edit(./.env*)"] // protected paths
}
}
Що це дає на практиці? По-перше, команда перестає сперечатися на кожному PR, чи можна довіряти Claude, — довіра вбудована в систему. По-друге, рев’юер бачить не лише diff, а й межі, в яких він зʼявився. По-третє, якщо хтось працює сміливіше зазвичай, L3 permissions усе одно утримують загальний baseline проєкту.
І це, мабуть, головний корисний результат сьогоднішньої теми. З нормальною L3-стратегією permissions перестають бути розмовою про дратівливі підтвердження й стають розмовою про передбачуваність. Ви відкриваєте завдання, присвоюєте рівень ризику — і далі Claude працює не «де вийде», а в межах добре освітленої майстерні, де небезпечні кімнати зачинені, інструменти розкладені по місцях, а на столі лежить план.
Окремий сюжет — хмарні поверхні Claude Code
Хмарний планувальник і хмарне рев’ю (умовно /ultraplan, /ultrareview або їхні аналоги — точна назва й доступність можуть змінюватися від версії до версії) виконуються поза вашою локальною session і підпорядковуються окремій permission-моделі: своїм межам хмарного облікового запису, окремому обліку витрат, окремому журналу аудиту й власному набору дозволених шляхів.
Для команди це означає просту, але незручну річ: хмарні агенти мають жити в тій самій логіці «дозволити / запитати / заборонити», що й локальні subagents. Безпечною за замовчуванням вона не вважається. Чутливі шляхи — секрети, дані клієнтів, файли, які за домовленістю не покидають on-prem — не мають витікати в хмару самі по собі, для них потрібен явний список дозволів. А слід аудиту — що відправлено, що повернулося, ким запущено — має потрапляти до загального логування команди, інакше перевірка відповідності перетворюється на ворожіння.
Для завдань рівня review-required це не заміна локальним permissions, а ще одна permission-поверхня поверх них. Рішення про схвалення diff усе одно за людиною, хто б не робив review. Точні механізми — opt-in/out, scoped tokens, конфігурація дозволених шляхів — залежать від версії Claude Code. Модель коротка: хмарна поверхня — ще один інструмент зі своїм blast radius, і описувати її в team policy потрібно явно. У термінах L3 це та сама робота, що й для локальних deny-rules і hooks, просто на поверхні, яка історично могла лишатися поза полем зору команди.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ