Перейти к содержимому

Headless-режим и автоматизация

waibee run запускает агента без интерфейса: на вход промпт, на выход результат в stdout. Никакого TUI, поэтому агента можно вызывать из Makefile, git-хука, шага CI или другой программы, в том числе из другого агента.

Окно терминала
waibee run "объясни, что делает calc.py, одним предложением"

Агент работает в реальном проекте: читает файлы, запускает команды, правит код. Отличие от TUI только в способе общения.

Окно терминала
waibee run --format text "..." # обычный текст, по умолчанию
waibee run --format json "..." # построчный JSON
waibee run --format jsonl "..." # то же самое, второе имя того же формата

json и jsonl дают одинаковый вывод: поток событий, по одному JSON-объекту в строке.

В JSON-режимах каждая строка это отдельное событие:

{"type":"text","text":"ГОТОВО"}
{"type":"goal_evaluated","decision":"met","reason":"В ответе есть слово ГОТОВО"}
{"type":"goal_achieved","duration_secs":80}
{"type":"usage","models":[{"model":"anthropic/claude-haiku-4.5","input_tokens":812,"output_tokens":96}]}

Ответ модели приходит частями в событиях type: "text": собирай их конкатенацией. События goal mode (goal_evaluated, goal_achieved, goal_aborted) появляются, когда цель активна, а завершающая строка usage когда счётчики токенов доступны.

Результат идёт в stdout, логи и предупреждения в stderr. Поэтому $(waibee run ...) подхватывает только ответ, а диагностику можно оставить в логах шага CI.

Без цели waibee run завершается нулём, если агент отработал, и ненулём при ошибке. С флагом --goal код отражает результат проверки:

Код Значение
0 Цель достигнута
1 Исчерпан лимит ходов, цель не достигнута
2 Ошибка агента или проверяющей модели
130, 143 Прерывание: второй Ctrl+C и SIGTERM. По этим кодам в CI видно, что шаг сняли, а не что задача провалилась

Отсутствующий или отвергнутый роутером ключ тоже даёт ненулевой код, а причина пишется в stderr.

Это и есть главный способ встроить агента в пайплайн: --goal описывает, что считается успехом, а код возврата решает, падает шаг или нет. Подробнее в Режиме цели.

По умолчанию агент старается не останавливаться на первом ответе: он формулирует условие завершения по задаче и проверяет, выполнено ли оно. Это дороже и дольше, зато результат не «почти готов». Для вопросов, объяснений и мелких правок условие не формулируется, и запуск сам сводится к одному проходу.

Окно терминала
waibee run "перенеси модуль auth на новый клиент" # работает до проверяемого результата
waibee run --once "объясни, что делает этот файл" # один проход, без проверки

Для вопросов и разовых справок бери --once: там проверять нечего.

Общие флаги (модель, рабочая папка) относятся ко всей команде и ставятся перед run, свои флаги run после него:

Окно терминала
waibee -m haiku run --once "перескажи README в трёх пунктах"
waibee -c ~/projects/api run --format json "какие эндпоинты объявлены?"

waibee run -m haiku не сработает: -m это флаг верхнего уровня.

Флаг Где Назначение
-m, --model до run Модель: псевдоним (haiku) или полный идентификатор
-c, --cwd до run Рабочая папка проекта
--format после run text, json, jsonl
--once после run Один проход без проверки результата
--goal после run Условие завершения, см. Goal mode
--goal-max-iterations после run Предел автопродолжений
--goal-model после run Модель-проверяющий

waibee run работает в режиме доверия, если в settings.json не задан другой: правки файлов и обычные команды выполняются сразу. Значение permissions.mode действует и здесь.

Важное исключение: команда с высоким риском (sudo, curl, удаление по шаблону) всё равно требует подтверждения, а отвечать в headless некому, поэтому запуск встанет и будет ждать. Разрушительные команды отклоняются сразу, в любом режиме. Подробнее: Права доступа.

Что из этого следует для автоматизации:

  • Разреши заранее то, что задаче нужно. Правила allow в settings.json снимают вопрос по конкретным командам, не открывая всё подряд.
  • Ставь таймаут шага. Он же страховка от зависшего запроса на подтверждение.
  • Читающим задачам не нужен доступ на запись. Сформулируй промпт как «проанализируй и опиши», а результат забирай из stdout, не из изменённых файлов.
  • Правки запускай в одноразовой копии. Отдельный клон, worktree или контейнер CI: там нечего терять, если агент сделает не то. Там же уместен режим bypassPermissions.
  • Запрещай опасное явно. Правила deny (например git push, доступ к секретам) действуют в любом режиме.
  • Ограничивай ходы. --goal-max-iterations не даст циклу тянуться до таймаута раннера.
Задача Как ставить
Ревью диффа в PR git diff origin/main > /tmp/d.patch, затем промпт «проверь риски в этом диффе», результат в файл или комментарий
Разбор упавшего теста Промпт с командой запуска: агент сам воспроизведёт и объяснит причину
Черновик CHANGELOG Промпт по git log между тегами, вывод в файл релиза
Массовая правка по списку файлов Цикл в bash: по одному вызову на файл, сначала проверь на двух-трёх
Ночная задача с проверкой --goal "make lint и make test проходят", код возврата решает, чинить ли дальше
Разбор алерта или лога Текст лога в промпт, на выходе гипотеза и место в коде
Инструмент внутри другого агента --once --format json, разбор событий text (пример ниже)
Проверка перед коммитом Git-хук с читающим промптом, при непустых замечаниях вернуть ненулевой код

Промпты для этих сценариев удобно держать не в шелле, а в своих командах .waibee/commands/: тогда они версионируются вместе с проектом.

Агент это обычный процесс: запусти его, прочитай stdout, разбери JSON.

ask.py
import json
import subprocess
TIMEOUT_SECONDS = 600
def ask(prompt: str, cwd: str = ".") -> str:
process = subprocess.run(
["waibee", "run", "--once", "--format", "json", prompt],
cwd=cwd,
capture_output=True,
text=True,
timeout=TIMEOUT_SECONDS,
)
if process.returncode != 0:
# Диагностика агента идёт в stderr, поэтому её и показываем.
raise RuntimeError(f"waibee run завершился с кодом {process.returncode}: "
f"{process.stderr.strip()[-500:]}")
events = (json.loads(line) for line in process.stdout.splitlines())
return "".join(event["text"] for event in events if event["type"] == "text")
print(ask("Одним предложением: что делает calc.py?"))

Так агента подключают как инструмент к другому агенту или к сервису. Он умеет то, чего у вызывающей стороны нет: работать в чужом репозитории с файлами, командами и тестами.

Если нужны не разовые вызовы, а разговор с сохранением контекста между запусками, смотри ACP в терминале.

.github/workflows/review.yml
- name: Установить агента
run: curl -fsSL https://raw.githubusercontent.com/waibee-main/waibee-code/main/install.sh | bash
- name: Ревью диффа
env:
WAIBEE_API_KEY: ${{ secrets.WAIBEE_API_KEY }}
run: |
git diff origin/${{ github.base_ref }}...HEAD > /tmp/diff.patch
waibee run --once --format text \
"Прочитай /tmp/diff.patch и перечисли риски: логические ошибки, потеря данных, ломающиеся контракты. Только замечания по делу, без пересказа диффа." \
> review.md
cat review.md >> $GITHUB_STEP_SUMMARY

Что учесть в CI:

  • Ключ только через секреты. WAIBEE_API_KEY в окружении шага, никогда в коде.
  • Задавай таймаут шага. Агент с проверкой результата может работать долго; ограничение времени в CI обязательно.
  • MCP-серверы проекта поднимаются и в headless. Те, что требуют интерактивной авторизации, в CI не запустятся и будут писать ошибки в stderr. Держи для CI отдельный конфиг без них, см. MCP.
  • Не смешивай чтение и запись в одном шаге. Ревью пусть только читает; правки отдельным шагом, который явно коммитит результат.