1. Фраза «проверь это» даёт мутный результат
Когда люди впервые начинают работать с агентами, рука сама тянется к коротким командам: «проверь diff», «посмотри тесты», легендарное «review this». Кажется, что умный агент сам всё поймёт. Разбирается он, к сожалению, не в том, что вам нужно, а в том, что проще выдать убедительным текстом.
Представьте типичную сцену в Commerce OS. Вы трогаете refund flow, где логика возвратов завязана на суммы, статусы заказа и ограничения по времени. Отдаёте reviewer-агенту: «проверь текущий diff». В ответ: «Код в целом выглядит нормально, возможно, стоит добавить пару тестов и проверить edge cases». Агент не глупый — вы не задали ему форму результата. Он не знает, возвращать ли замечания по severity, указывать ли file:line, отделять ли гипотезы от фактов, можно ли редактировать код и что делать, если diff накрыл половину модуля.
Посмотрите на разницу между двумя запросами:
Плохо:
Проверь этот diff.
Лучше:
Проверь текущий diff в auth и billing flows.
Код не редактируй.
Сфокусируйся на пропущенных тестах, совместимости API и крайних случаях.
Верни замечания по severity с file:line, evidence и предложенными проверками.
Если diff больше 500 строк — остановись и попроси разбить change.
Во втором варианте агенту уже некуда расплываться, и важно это не только для него, но и для вас — именно вам потом решать, брать результат в работу или гнать на доработку.
Агент без output contract очень похож на коллегу, который на вопрос «ну как там ревью?» отвечает: «в целом нормально, но есть нюансы». Формально разговор состоялся, а пользы примерно как от прогноза погоды в стиле «где-то будет что-то среднее между солнцем и апокалипсисом».
2. Output contract против Session Handoff Note
Чтобы не смешивать разные артефакты, полезно сразу развести два документа, похожих по духу, но разных по цели: в одном вы передаёте дальше состояние задачи, в другом — принимаете результат делегированной роли.
Output contract — это договор о результате, который агент должен вернуть. Не о личности, не о «стиле работы», не о красивом тексте — именно о результате. Вы заранее решаете, что обязано быть в ответе, где доказательства, как помечается неопределённость, что считается нарушением границ и когда агент обязан остановиться.
Для сравнения удобно смотреть так:
| Артефакт | Главный вопрос | Когда используется | Что в нём главное |
|---|---|---|---|
| HANDOFF_NOTE.md / Session Handoff Note | «Что происходит с задачей сейчас?» | Когда вы передаёте работу другой сессии или человеку | Текущее состояние, решения, открытые вопросы, следующий шаг |
| Output contract агента | «Можно ли принять этот результат?» | Когда subagent закончил свою роль и вернул output | Формат результата, evidence, scope, uncertainty, stop conditions |
Session Handoff Note вы уже встречали раньше — он нужен, чтобы не потерять контекст длинной задачи между сессиями. Output contract нужен для другого: посмотреть на результат reviewer- или tester-агента и сказать одно из трёх — «беру в работу», «вернись и уточни», «нарушены границы, не принимаю».
Это различие особенно полезно помнить в Workflow Kit. agents/reviewer.md и agents/tester.md — не просто файлы с ролью, а артефакты, обязанные возвращать результат в предсказуемом формате. Если reviewer пишет свободное эссе, а tester — «тесты добавлены», у вас не инженерный процесс, а литературный кружок с элементами shell-скриптов.
3. Из чего состоит хороший output contract
Сильный контракт не обязан быть большим — наоборот, чем он короче и яснее, тем лучше работает. Но без нескольких секций вы снова скатываетесь в ситуацию, когда агент что-то сказал, а вы угадываете, можно ли на это опираться.
Вот удобная структура, которая тянет и reviewer, и tester, если подкрутить детали под роль:
| Секция | Зачем она нужна | Что вы проверяете |
|---|---|---|
| summary | Даёт короткую рамку результата | Понял ли агент задачу и scope |
| findings | Содержит замечания или предложения | Есть ли у замечаний severity и привязка к коду |
| evidence | Доказывает каждое важное утверждение | Есть ли file:line, команда, лог, diff |
| tests/checks run | Показывает, что реально запускалось | Есть ли команды и exit codes, а не «вроде запускал» |
| uncertainty | Отделяет факты от предположений | Есть ли пометки [hypothesis] |
| changed files | Показывает, нарушил ли агент границы роли | Для reviewer — должно быть пусто |
| next step | Делает результат применимым | Понятно ли, что делать дальше |
| stop conditions | Ограничивает вред при нештатной ситуации | Остановился ли агент там, где должен |
На практике это может выглядеть так:
## Формат вывода
- summary: 3–5 предложений, без воды
- findings: severity, file:line, evidence, recommendation
- tests/checks run: команда + exit code
- uncertainty: отдельный блок с [hypothesis]
- changed files: список или none
- next step: одно ясное действие для разработчика
Точные названия разделов и синтаксис agent file в текущей версии Claude Code могут отличаться — это нормально. Важно не поле summary само по себе, а принцип: результат устроен так, чтобы его можно было проверить, а не только прочитать.
Ещё один полезный способ смотреть на контракт — разделить поля на жёсткие и мягкие.
| Тип поля | Пример | Чем хорош |
|---|---|---|
| Жёсткое | orders/refund/RefundPolicy.java:87, ./gradlew test, exit code 1, changed files: none | Его можно проверить почти механически |
| Мягкое | severity: major, risk: regression in refund flow, recommendation: add integration test | Требует человеческого суждения |
Жёсткие поля защищают вас от красивой риторики, а мягкие делают результат полезным. Если в контракте только мягкие поля, агент превращается в очень уверенного комментатора; если только жёсткие — он выдаёт сухой протокол без смысла. Инженерно хороший контракт держит баланс между этими двумя слоями.
4. Запрос агенту под контракт
Даже хороший контракт бесполезен, если вы ставите задачу в стиле «ну посмотри». Он срабатывает только тогда, когда запрос сам сформулирован как инженерное задание: границы, фокус, запрет на лишнее, ожидаемый формат.
С reviewer-агентом это видно особенно наглядно. Плохо:
Проверь код после моих изменений.
Нормально:
Проверь текущий diff по refund flow в Commerce OS.
Код не редактируй.
Сфокусируйся на regressions, пропущенных тестах и совместимости API.
Верни findings по severity с file:line, evidence и suggested checks.
Если diff больше 500 строк — остановись и попроси разбить change.
Почему это работает лучше? Потому что здесь зафиксированы сразу пять вещей. Во-первых, scope: refund flow, не весь проект. Во-вторых, границы роли: не редактировать код. В-третьих, фокус внимания: regressions, tests, API. В-четвёртых, формат результата: severity, file:line, evidence. В-пятых, условие остановки: diff слишком большой — не геройствовать.
С tester-агентом картина похожая, но акценты другие: ему мало просто сказать «проверь тесты» — лучше сформулировать запрос так, чтобы было понятно, что он пишет только тесты, а production-код не трогает.
Подготовь тестовое покрытие для текущего diff в auth flow.
Production-код не меняй.
Если нужны изменения, ограничься файлами в tests/**.
Верни список сценариев, команды запуска, exit codes и отмеченные [hypothesis].
Если падают больше пяти нерелевантных тестов — остановись и отчитайся.
Обратите внимание: хороший запрос почти всегда опирается на уже существующий output contract, даже не цитируя его целиком. Вы не изобретаете формат заново, а активируете заранее описанную роль. В этом и есть сила Workflow Kit: контракт живёт в agents/reviewer.md или agents/tester.md, а сессионная постановка лишь заземляет его в конкретный diff.
5. Приёмка или отклонение результата
Самая взрослая часть работы начинается не в момент делегирования, а в момент возврата результата. Именно тут видно, построили вы инженерный процесс или просто завели ещё один чат с очень самоуверенным собеседником.
Приёмка делегированной работы обычно сводится к трём решениям:
| Решение | Когда подходит | Что делаете дальше |
|---|---|---|
| Принять | Есть evidence, scope соблюдён, границы роли не нарушены, следующий шаг понятен | Берёте findings в работу или фиксируете отсутствие проблем |
| Вернуть на уточнение | Идея полезная, но не хватает доказательств, ясности или маркировки гипотез | Просите переформатировать output по контракту |
| Отклонить | Нет evidence, были неожиданные edits, нарушены stop conditions или границы роли | Не используете результат и пересобираете задачу заново |
Хороший reviewer-output в Commerce OS может выглядеть примерно так:
### находки
- major — orders/refund/RefundPolicy.java:87
evidence: условие допускает amount == 0, а теста на нулевой refund нет
recommendation: добавить regression test на zero-amount case
### прогнанные тесты/проверки
- ./gradlew test --tests RefundPolicyTest → exit code 0
### изменённые файлы
- none
Здесь почти всё на месте: severity, конкретная строка, evidence, рекомендация, команда, подтверждение, что reviewer ничего не менял. Такой результат можно принимать.
А вот пример, который стоит вернуть:
### находки
- Возможно, здесь есть проблемы с refund flow.
- Стоит ещё посмотреть тесты.
- В целом код выглядит рискованно.
Почему вернуть, а не сразу выбросить? Потому что, возможно, агент действительно что-то заметил, но не оформил результат по контракту. Нет file:line, нет evidence, нет severity, непонятно, что запускалось. В работу как есть — нельзя.
А если reviewer внезапно вернул changed files с production-кодом, хотя роль была read-only, — это уже повод не «уточнять», а отклонять результат как нарушение границ.
Наглядно весь процесс выглядит так:
flowchart TD
A[Агент вернул результат] --> B{Есть evidence?}
B -- нет --> C[Вернуть на уточнение или отклонить]
B -- да --> D{Соблюдён scope и role boundaries?}
D -- нет --> E[Отклонить]
D -- да --> F{Гипотезы помечены явно?}
F -- нет --> G[Вернуть на уточнение]
F -- да --> H{Следующий шаг понятен?}
H -- да --> I[Принять в работу]
H -- нет --> G
Смысл этой схемы простой: вы принимаете не умное впечатление, а структурированный артефакт.
6. Гипотезы помечаем, а не прячем в уверенный тон
Одна из самых неприятных ловушек при работе с агентами — не явная ошибка, а неотмеченная неопределённость. Агент пишет очень уверенно, и только потом выясняется, что половина выводов была догадкой. Поэтому в контракте есть отдельный блок uncertainty, а гипотезы помечаются явно — маркером [hypothesis].
Плохой вариант выглядит так:
- major: refund flow ломается из-за stale cache в billing service
Проблема в том, что это звучит как установленный факт. А где доказательство — лог, трассировка вызова, тест? Может быть, агент просто увидел похожий паттерн и достроил картину.
Гораздо честнее так:
- [hypothesis] possible regression in refund flow
evidence: прямого подтверждения в diff не найдено
why suspect: billing cache читается до проверки refund status
needed check: прогнать integration test на stale status
Во втором варианте агент не стал «менее умным» — он стал пригодным для инженерной работы. Видно, что подтверждено, что пока только предполагается и какой шаг нужен, чтобы гипотезу подтвердить или выбросить.
Особенно это важно для tester-агента. Он часто работает на стыке существующего тестового набора, новых сценариев и неполного знания о проекте. Если он не умеет честно сказать «здесь я предполагаю» — он начнёт закреплять свои догадки в тестах. А это уже тот редкий случай, когда автоматизация ломает систему не громко, а очень вежливо и документированно.
7. В Workflow Kit: reviewer и tester
Чтобы всё это не осталось на уровне абстракции, давайте заземлим тему в артефактах Workflow Kit — именно там контракт перестаёт быть красивой идеей и становится частью поддерживаемого файла agents/reviewer.md или agents/tester.md.
Для reviewer контракт может быть таким:
## Формат вывода
- summary: 3–5 предложений
- findings: severity, file:line, evidence, recommendation
- tests/checks run: команда + exit code
- uncertainty: помечать как [hypothesis]
- changed files: none
- next step: одно ясное действие
А для tester — немного иным:
## Формат вывода
- summary: какое поведение покрывается
- proposed tests: файл + сценарий
- commands run: команда + exit code
- changed files: только tests/**
- uncertainty: помечать как [hypothesis]
- stop conditions: при массовых нерелевантных падениях остановиться
Разница между ними не косметическая. Reviewer по роли должен остаться read-only, поэтому changed files у него обязаны быть пустыми. Tester может менять тестовые файлы, но именно тестовые, а не production-логику. Иначе получится классический сюжет: «агент починил тесты», переписав поведение системы под тест, а не наоборот.
Здесь особенно хорошо видно, зачем контракт вообще нужен. Он не только помогает принимать результат — он ещё и дисциплинирует саму роль. Пока контракт не зафиксирован, reviewer и tester различаются только словами в заголовке файла; как только он появляется, их поведение становится измеримым и предсказуемым.
Точные имена разделов, поля frontmatter и формат agent file могут меняться от версии к версии Claude Code — это не страшно. Страшно другое: когда у агента нет явного договора о результате, а значит, нет и нормальной инженерной приёмки. Когда reviewer и tester возвращают одинаково устроенный, читаемый, проверяемый output, вопрос «можно ли это принять» решается по полям контракта, а не по тому, насколько уверенно написан ответ. Договор о результате — это то, что превращает делегирование из ставки на удачу в предсказуемую операцию с чёткой приёмкой.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ