#Ограничьте автономные запуски
Продвинутый уровень · Урок 7 из 7 · около 20 минут плюс время запуска · Нужно: Скрипты с claude -p, Поделитесь настройкой с командой · Сверено с Claude Code v2.1.285 (stable) 09.10.2026
#Цель
К концу урока вы сможете ограничить запуск claude -p без присмотра минимальными привилегиями, песочницей, лимитами ходов и расходов, точкой ревью и оценкой стоимости.
#Что понадобится
- Репозиторий, для которого вы писали скрипт в уроке 4 и которым делились в уроке 6, с командой запуска тестов, и ваша копия шаблона для практики с Node.js LTS и проверками Продвинутого уровня (Практика): проверка запускается из копии. Подготовьте в репозитории папку
.practice/, как описано в уроке 1 Начального уровня, если ещё не сделали этого. - bash и
jqв macOS, Linux или WSL 2. В Linux и WSL 2 песочнице нужныbubblewrapиsocat(Set up Linux and WSL2). - Расход лимита: умеренный. Каждый запуск останавливается на своих лимитах. Экономный вариант: в задании «Ваша очередь» задайте лимиты по запуску на срезе и запустите скрипт ещё на одном срезе вместо всей задачи.
#Идея
Запуск, за которым никто не следит, делает всё, что вы разрешили заранее, поэтому разрешайте мало, а остальное ограничивайте:
- Минимальные привилегии. Режим
dontAskотклоняет каждый вызов, который иначе потребовал бы подтверждения (dontAsk mode), так что разрешите только папки, которые правит задача, и одну команду, которую она запускает. - Песочница. Операционная система ограничивает, куда разрешённая команда может писать и куда обращаться (Configure the sandboxed Bash tool). Сделайте её строгой и обязательной для старта запуска.
- Лимиты.
--max-turnsограничивает число агентных ходов, а--max-budget-usd— оценочные расходы (CLI flags). - Точка ревью. Запретите
git commitиgit push: правила deny действуют в любом режиме (Available modes). Формы, которые правило упускает, напримерgit -C . push,dontAskотклоняет, пока их ничто не разрешает (What a Bash rule doesn't match). Вы читаете diff и коммитите то, что принимаете. - Оценка стоимости. Сначала выполните один срез и задайте лимит расходов по его стоимости.
#Разбор примера
Работайте в своём репозитории. Папки src/ и test/ и команда npm test обозначают ваши собственные: везде ниже подставьте свои.
- Сохраните ограничения как
.claude/bounded-run.json:
{
"permissions": {
"allow": ["Edit(./src/**)", "Edit(./test/**)", "Bash(npm test *)"],
"deny": ["Agent", "Read(./.env)", "Read(./.env.*)", "Bash(git commit *)", "Bash(git push *)"]
},
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"autoAllowBashIfSandboxed": false
}
}
allow: правки в двух папках иnpm testс любыми аргументами. ПравилаEditпокрывают все встроенные инструменты, которые правят файлы, а путь с./отсчитывается от папки, где стартует запуск (Read and Edit).deny: файлы.env;git commitиgit push, где завершающий*совпадает и с командой без аргументов (Wildcard patterns); и инструментAgent, чтобы Claude не мог передать работу субагенту (Built-in subagents), который мог бы работать в собственном режиме разрешений (Permission modes).sandbox: включена; при невозможности запуска — выход на старте (sandbox.failIfUnavailable); никогда не повторять команду вне её (Strict sandbox mode); и пропускать команды в песочнице через ваши правила и режим, а не одобрять их все (sandbox.autoAllowBashIfSandboxed).
Файловые инструменты Claude не могут изменить этот файл во время запуска: в режиме dontAsk запись в защищённую папку .claude/ запрещена, и правила allow этого не меняют (Protected paths).
2. Сохраните скрипт запуска как scripts/bounded-run.sh:
#!/bin/bash
# Runs one unattended task inside the bounds in .claude/bounded-run.json.
set -u
if [ $# -ne 2 ]; then
echo 'Usage: scripts/bounded-run.sh "<task>" <result.json>' >&2
exit 2
fi
before=$(git rev-parse --short HEAD)
claude -p "$1" \
--setting-sources project \
--settings .claude/bounded-run.json \
--permission-mode dontAsk \
--model sonnet \
--max-turns 15 \
--max-budget-usd 2 \
--output-format json > "$2"
status=$?
jq '{subtype, num_turns, total_cost_usd, denied: [.permission_denials[]? | .tool_input.command // .tool_name]}' "$2"
echo "HEAD before: $before, after: $(git rev-parse --short HEAD)"
git status --short
exit "$status"
--setting-sources project: не пускает в запуск ваши пользовательские и локальные файлы настроек (CLI flags), так что правило allow, сохранённое ответом «Yes, and don't ask again» и попавшее в.claude/settings.local.json, не присоединится к ограничениям (Permission system).--settings: файл ограничений, который Claude Code применяет поверх собственных настроек проекта (Change a setting for one session). Правила allow лежат там потому, что запуск-pигнорирует правила allow из.claude/settings.jsonпапки, которой никогда не доверяли (What runs before you trust a folder).allowUnsandboxedCommands: falseв этом файле: поскольку он приходит из--settings, значениеtrueв проекте не может снова включить повтор вне песочницы (Strict sandbox mode). Начиная с v2.1.285, Claude Code также игнорирует настройки репозитория, ослабляющие песочницу, напримерexcludedCommands(Repository settings under an admin-required sandbox).--model sonnet: Sonnet хорошо справляется с большинством задач программирования и стоит дешевле Opus (Choose the right model).--max-turnsи--max-budget-usd: это конфигурация, задайте свои значения. 3. Сделайте скрипт исполняемым и закоммитьте оба файла, чтобы у всех, кто его запускает, были одинаковые ограничения:
chmod +x scripts/bounded-run.sh
git add scripts/bounded-run.sh .claude/bounded-run.json
git commit -m "Add a bounded runner for unattended tasks"
Если git сообщает, что путь игнорируется, git check-ignore -v <path> покажет совпавшее правило; добавьте путь через git add -f.
4. Посмотрите, как лимит останавливает запуск. Задайте тем же ограничениям крошечный лимит расходов:
claude -p "Run npm test and summarize the result" \
--setting-sources project --settings .claude/bounded-run.json \
--permission-mode dontAsk --model sonnet \
--max-budget-usd 0.01 --output-format json > .practice/a-7-capped.json
echo "exit $?"
jq '{subtype, total_cost_usd}' .practice/a-7-capped.json
Будет выведен ненулевой код выхода, затем "subtype": "error_max_budget_usd": запуск остановился на лимите, и JSON всё равно его фиксирует (Handle the result). total_cost_usd может превышать лимит, потому что включает ответ, который его пересёк (Track costs on failed conversations).
5. Оцените стоимость на срезе — одной небольшой части большей задачи:
scripts/bounded-run.sh "Use your Edit tool to add a test for one untested function in src/<file>. Then run npm test as a command on its own, and then commit the test." .practice/a-7-slice.json
Сводка покажет "subtype": "success", число использованных ходов, total_cost_usd, а в denied — каждый вызов, отклонённый вашими ограничениями, например git commit; ваш список будет другим. HEAD до и после одинаковый, а git status показывает новый тест, не закоммиченный. Вывод у вас будет другим. total_cost_usd — оценка на стороне клиента, а не ваш счёт (Track cost and usage); на плане Claude /usage в сессии показывает лимиты использования плана (Commands). Чтобы ограничить всю задачу, умножьте стоимость среза пропорционально и задайте лимит расходов выше, с запасом.
6. Будьте точкой ревью. Прочитайте каждое изменение через git status и git diff, включая файл ограничений, сами запустите npm test и закоммитьте только то, что принимаете. Для второго мнения запустите claude и поручите субагенту проверить diff в свежем контексте и сообщить о пробелах (Add an adversarial review step).
#Ваша очередь
Ограничьте реальную задачу в своём репозитории, которая больше одного среза, — например тесты для каждой непокрытой функции в одной папке.
Критерии приёмки:
- Её запускает
scripts/bounded-run.sh "<task>" <result.json>: один вызовclaude -pв режимеdontAsk, JSON-вывод сохраняется по пути результата, а ограничения из закоммиченного файла передаются через--settings. - Скрипт вызывает
claudeпо имени, а не по пути и не черезnpx, и не меняетPATH: так проверка подставляет вместо него заглушку. - Каждое правило allow называет одну папку или одну команду: никаких голых
BashилиEditи никаких правил на весь проект или целую программу вродеBash(npm *). Ваш закоммиченный.claude/settings.jsonтоже считается: в папке, которой вы доверились, его правила allow присоединяются к правилам файла ограничений (Lists merge instead of overriding). Как иallowed-toolsскиллов репозитория — в запуске, который вызывает такой скилл (Pre-approve tools for a skill). - Правила deny останавливают
git commitиgit push, каждое с завершающим*:Bash(git push)совпадает только с командой без аргументов. - Песочница включена и строгая, пропускает команды через ваши правила, и без неё запуск отказывается стартовать.
- Есть лимит ходов и лимит расходов, превышающий стоимость вашего среза и масштабированный под задачу.
- Скрипт исполняемый, а скрипт и файл ограничений закоммичены.
- Вы запускаете его, затем сами читаете diff и запускаете тесты, прежде чем что-либо коммитить.
#Проверка
Урок пройден, когда выполнено всё это:
-
scripts/bounded-run.shзакоммичен и исполняем, принимает задачу и путь результата (scripts/bounded-run.sh "<task>" <result.json>) и запускаетclaude -pв режимеdontAskс JSON-выводом и закоммиченным файлом--settings. - Он задаёт лимит ходов и лимит расходов.
- Каждое правило allow называет одну команду или одну папку, а правила deny останавливают
git commitиgit push. - Файл настроек включает песочницу в строгом режиме без auto-allow и не даёт запуску стартовать без неё.
-
.practice/a-7-slice.jsonсодержит запуск на срезе, стоимость которого ниже вашего лимита расходов. -
.practice/a-7-capped.jsonсодержит запуск, остановленный лимитом. - Самопроверка (не тестируется): вы прочитали diff и запустили тесты, прежде чем что-либо коммитить.
Запустите npm run check -- a-7 --dir <your repo> из своей копии для практики или npm run check -- a-7 в самой копии. Проверка запускает ваш закоммиченный скрипт с заглушкой вместо claude, так что ваш лимит не расходуется.
Если не проходит первый пункт, убедитесь, что закоммиченный скрипт исполняемый (git ls-files -s scripts/bounded-run.sh начинается с 100755), вызывает claude по имени, а не по пути и не через npx, и не задаёт PATH: проверка читает закоммиченный скрипт, так что коммитьте каждое исправление. Если не проходит правило allow, сузьте его до одной папки или команды, нужной задаче. Если пункт о песочнице называет ключ, добавьте его в файл настроек: без failIfUnavailable запуск, чья песочница не может стартовать, выполняется без песочницы (sandbox.enabled). Если не проходит пункт о срезе, убедитесь, что скрипт отправляет по пути результата только JSON-вывод claude (stdout), и снова выполните шаг 5; срез, завершившийся error_max_budget_usd, означает, что ваш лимит расходов меньше стоимости одного среза, — поднимите его.
#Осторожно
- Ваши ограничения покрывают не всё, что загружает запуск. Хуки и локальные MCP-серверы работают вне песочницы с вашими полными правами (What runs outside the sandbox). Как предупреждал урок 4, запуск
-pбез вопросов использует хуки репозитория и серверы из.mcp.json, а также применяетallowed-toolsскиллов репозитория (What runs before you trust a folder). Прочитайте эти хуки, серверы и скиллы перед ограниченным запуском или добавьте в файл ограничений"disableAllHooks": true, чтобы отключить для него хуки. - Правило deny сравнивается с командой, которую пишет Claude, а не с тем, что делает программа (What a Bash rule doesn't match). Разрешённый
npm testзапускает тестовые файлы, которые запуск может править. В песочнице этот код может писать в любое место рабочей папки, кроме защищённых путей, а внутри.gitзащищены толькоhooksиconfig(Protected paths). Так что он может даже сделать коммит. А вот push из него не доберётся до удалённого репозитория: в режимеdontAskпесочница отклоняет хосты, которые вы не разрешили (Hosts outside your allowed domains, Turn off permission prompts in unattended runs). Поэтому скрипт печатает HEAD до и после, а ваше ревью охватывает каждый изменённый файл. - Динамический workflow запускается через собственный инструмент
Workflow. В таком запуске, как этот, он стартует, только если его одобряет правило allow или хукPreToolUse:Workflowодобряет любой workflow, аWorkflow(<name>)— один сохранённый (Approve the plan before it runs). Агенты workflow подчиняются вашим правилам разрешений, а их режим разрешений определяется правилами для субагентов, так что тип агента, в определении которого заданpermissionMode, может работать в этом режиме (Permission modes). Это субагенты, поэтому их расходы засчитываются в--max-budget-usd. Если вы разрешаете workflow, добавьте в файл ограничений и"workflowSizeGuideline": "small"— это просит Claude использовать меньше агентов, но ничего не ограничивает (workflowSizeGuideline).
#Что дальше
- Choose a sandbox environment: контейнеры и виртуальные машины для запусков, которые песочница Bash не покрывает.
- How we contain Claude across products: инженерный пост Anthropic о том, как ограничить вред, который может нанести агент, в Claude Code и других продуктах.
- Catch security issues as Claude writes code: плагин security-guidance, с которым Claude проверяет собственные изменения на уязвимости, пока вы работаете вместе.
Источники: Choose a permission mode · Configure permissions · Extend Claude with skills · Configure the sandboxed Bash tool · All settings · Settings files and precedence · CLI reference · Create custom subagents · Run Claude Code programmatically · How the agent loop works · Track cost and usage · Manage costs effectively · Commands · Best practices · Orchestrate subagents at scale with dynamic workflows
← Поделитесь настройкой с командой · Оглавление Продвинутого уровня · Итоговый проект Продвинутого уровня → · Тема: Разрешения и безопасность · Застряли на уроке?