Headless-режим и скриптинг через CLI
Есть задачи, которым не нужен интерактивный диалог. Code review в CI, автоматическое объяснение build-ошибок, ночной аудит зависимостей — всё это просто скрипты, которые должны отработать и вернуть результат. Флаг -p (сокращение от --print) переводит Claude Code именно в этот режим: запрос → агентный цикл → вывод результата → выход.
Эта статья — о том, как встроить Claude Code в скрипты, пайплайны и CI/CD так, чтобы он работал как нормальный Unix-инструмент: читал stdin, писал в stdout, возвращал структурированный вывод и не требовал ничего лишнего.
-p: основной флаг headless-режима
Самый простой случай — задать вопрос о кодовой базе и получить ответ:
claude -p "Что делает модуль auth?"Агент прочитает файлы в текущей директории, ответит и завершится. В отличие от интерактивного режима — никакого REPL, никаких запросов разрешений в stdin. Это ключевое: в -p режиме Claude Code всё ещё выполняет агентный цикл (читает файлы, запускает команды — если разрешено), но делает это без пауз на подтверждение.
# Объяснить конкретный файл
claude -p "Объясни логику в src/parsers/csv.ts, особенно обработку quoted fields"
# Быстрый code review изменений
git diff HEAD~1 | claude -p "Сделай краткий code review этого diff"
# Продолжить предыдущую сессию в headless-режиме
claude -c -p "Теперь сосредоточься на database queries"Пайпы и композиция с Unix-утилитами
Headless-режим читает stdin — это открывает стандартные Unix-паттерны.
# Объяснить ошибку сборки
cat build-error.txt | claude -p 'Объясни корневую причину этой ошибки сборки'
# Следить за логом и объяснять аномалии в реальном времени
tail -f app.log | claude -p 'Предупреди, если увидишь паттерны ошибок или аномалии'
# Передать PR diff прямо из gh CLI
gh pr diff 123 | claude -p 'Проверь на потенциальные проблемы безопасности'Одно практическое ограничение: stdin ограничен 10 МБ. Если контент больше — Claude Code завершится с ошибкой. Для больших файлов правильнее указать путь в промпте, а не пайпить содержимое.
Композиция работает в обе стороны: вывод Claude Code тоже можно пайпить в другие утилиты:
# Получить список файлов с проблемами и отправить в grep
claude -p 'Перечисли файлы с потенциальными утечками памяти, по одному пути на строку' | \
xargs grep -l 'malloc'flowchart LR
A["stdin / файл / git diff"] --> B["claude -p 'промпт'"
--output-format json
--allowedTools ...
--bare]
B --> C["Агентный цикл
Read / Bash / Edit"]
C --> D["stdout: JSON"]
D --> E1["jq '.result'"]
D --> E2[">> report.md"]
D --> E3["| grep ERROR"]Форматы вывода: text, json, stream-json
По умолчанию -p возвращает plain text — удобно для чтения, но неудобно для парсинга в скриптах. Флаг --output-format меняет это.
text — стандартный текст, как в терминале.
json — структурированный объект с метаданными:
claude -p "Summarize this project" --output-format jsonВывод выглядит примерно так:
{
"result": "This project is a CSV parser library that...",
"session_id": "sess_01AbCdEf...",
"total_cost_usd": 0.0034,
"cost_breakdown": {
"input_tokens": 1200,
"output_tokens": 340
}
}Поле total_cost_usd позволяет отслеживать расходы на уровне скрипта — полезно в CI для cost tracking без обращения к дашборду.
Парсинг с jq:
# Только текст результата
claude -p "Summarize this project" --output-format json | jq -r '.result'
# Только стоимость
claude -p "Review this code" --output-format json | jq '.total_cost_usd'stream-json — поток JSON-объектов, по одному на строку, по мере генерации. Каждый объект — событие агентного цикла. Используется когда нужно отображать прогресс или обрабатывать токены по мере поступления:
claude -p "Write a detailed explanation of this algorithm" \
--output-format stream-json \
--verbose \
--include-partial-messages | \
jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'Флаги --verbose и --include-partial-messages нужны, чтобы stream-json включал промежуточные события, а не только финальный результат.
Структурированный вывод с --json-schema
Комбинация --output-format json + --json-schema даёт гарантированно валидный JSON по заданной схеме. Агент завершит агентный цикл и вернёт структуру, соответствующую схеме — в поле structured_output:
claude -p "Extract all public API endpoints from src/api/" \
--output-format json \
--json-schema '{
"type": "object",
"properties": {
"endpoints": {
"type": "array",
"items": {
"type": "object",
"properties": {
"method": {"type": "string"},
"path": {"type": "string"},
"description": {"type": "string"}
}
}
}
}
}' | jq '.structured_output.endpoints'Это мощный паттерн для парсинга кодовых баз: агент изучает файлы, а вы получаете данные в виде массива/объекта — без регулярных выражений и хрупкого парсинга текста.
--bare: быстрый старт для CI
По умолчанию claude -p при старте загружает всё то же самое, что и интерактивная сессия: CLAUDE.md, хуки, скиллы, MCP-серверы, автопамять. В CI это часто лишнее — и медленное.
Флаг --bare пропускает автодискавери всего этого:
claude --bare -p "Summarize this file" --allowedTools "Read"В bare-режиме доступны только базовые инструменты (Bash, чтение и редактирование файлов). Всё нужное подключается явно через флаги:
claude --bare -p "Review this PR" \
--mcp-config ./ci-mcp.json \
--append-system-prompt "You are a security reviewer."Важное практическое следствие: bare-режим не читает ANTHROPIC_API_KEY из keychain — аутентификация должна прийти через переменную окружения или --settings. В CI это обычно именно так и настроено.
> Согласно документации, --bare станет режимом по умолчанию для -p в будущих версиях.
Управление инструментами: --allowedTools
В headless-режиме запрос разрешения некому принять — поэтому нужно явно указать, что агент может делать без вопросов:
# Только чтение — агент не изменит ни одного файла
claude -p "Find all TODO comments in the codebase" \
--allowedTools "Read,Bash(grep *),Bash(find *)"
# Чтение, редактирование и конкретные git-команды
claude -p "Look at staged changes and create an appropriate commit" \
--allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"
# Режим acceptEdits — пишет файлы без запроса, но не shell-команды
claude -p "Apply lint fixes" --permission-mode acceptEditsСинтаксис Bash(git diff *) — это permission rule syntax: пробел перед * важен. Bash(git diff *) разрешает любую команду, начинающуюся с git diff, а Bash(git diff*) без пробела — нет.
Лимиты: --max-turns и --max-budget-usd
Два флага, которые делают headless-запуски предсказуемыми по стоимости и времени:
# Не более 5 агентных шагов
claude -p "Investigate the failing tests" \
--max-turns 5 \
--output-format json
# Максимум $2 на запуск
claude -p "Refactor the auth module" \
--max-budget-usd 2.00Если агент достигает лимита --max-turns — завершается с ненулевым кодом возврата. Это удобно для CI: if claude -p ... --max-turns 10; then ... fi.
--max-budget-usd работает только с -p и учитывает total_cost_usd текущего запуска. Это грубый лимит, а не биллинговый контроль — для точного учёта используйте поле total_cost_usd из JSON-вывода.
Практические паттерны
Тайпо-линтер в package.json:
{
"scripts": {
"lint:typos": "git diff main | claude -p \"you are a typo linter. for each typo in this diff, report filename:line on one line and the issue on the next. return nothing else.\""
}
}Security review PR перед мержем:
#!/bin/bash
PR_NUMBER=$1
gh pr diff "$PR_NUMBER" | claude --bare -p \
--append-system-prompt "You are a security engineer. Focus on injection, auth bypass, and data exposure." \
--output-format json \
--max-budget-usd 1.00 \
"Review this PR diff for security vulnerabilities. List each issue with severity." \
| jq -r '.result'Мульти-шаговый анализ с продолжением сессии:
# Первый запрос — сохраняем session_id
session_id=$(claude -p "Review this codebase for performance issues" \
--output-format json | jq -r '.session_id')
# Последующие запросы в той же сессии
claude -p "Now focus only on database queries" \
--resume "$session_id" \
--output-format json | jq -r '.result'
claude -p "Generate a prioritized fix list" \
--resume "$session_id" \
--output-format json | jq -r '.result'Это особенно полезно, когда каждый шаг анализа опирается на контекст предыдущего — агент помнит, что уже нашёл.
Headless в CI/CD
Headless-режим — это основа интеграции Claude Code в GitHub Actions и другие CI-системы. Полноценный пайплайн рассматривается в GitHub Actions и автоматический code review, но базовый принцип прост:
# .github/workflows/claude-review.yml
- name: Claude security review
run: |
gh pr diff ${{ github.event.pull_request.number }} | \
claude --bare -p \
--append-system-prompt "Security reviewer. Output JSON only." \
--output-format json \
--max-budget-usd 2.00 \
"Find security vulnerabilities" \
| jq '.result'
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}Обратите внимание на --bare: без него агент попытается загрузить CLAUDE.md и MCP-серверы из рабочей директории CI-раннера — что обычно не то, что нужно.
See also
- GitHub Actions и автоматический code review — как headless-режим используется в PR workflows
- GitLab CI/CD и headless-автоматизация — тот же паттерн для GitLab
- Git, коммиты и пул-реквесты — git-операции, которые удобно автоматизировать через
-p - Hooks — события жизненного цикла — события PreToolUse/PostToolUse, которые работают и в headless-режиме
- Claude Agent SDK: программная сборка агентов — если
claude -pнедостаточно и нужен полный программный контроль через Python/TypeScript - Облачные агенты: web, routines и фоновые задачи — альтернатива headless-режиму для долгих фоновых задач