Один юніт, крок за кроком
Юніт — найменший шматок роботи, який запускає harness. Ось усе, що відбувається в одному юніті. Runner — звичайний код; модель задіяна лише в середніх кроках.
| Крок | Хто | Що відбувається |
|---|---|---|
| Вибір | runner | Читає корпус і бере наступну задачу, статусом якої володіє агент і яка ще не в роботі. |
| Гілка | runner | Починаючи з implement-етапу, перемикається на гілку задачі, а вперше — створює її. |
| Знімок | runner | Записує гілку, останній коміт і брудні файли, щоб порівняти після юніта. |
| Старт | runner | Запускає координатора через claude -p з промптом етапу і спеціалістами цього етапу через --agents. |
| Розподіл | координатор | Читає реєстр агентів, обирає потрібних задачі спеціалістів і викликає їх. |
| Очікування | координатор | Тримає хід, доки кожен спеціаліст не відповість. |
| Відповідь | спеціалісти | Кожен робить свою вузьку роботу, пише лише те, чим володіє, і звітує координатору. |
| Фініш | координатор | Записує у файл задачі, що вирішив юніт, друкує рядок вердикту, якого вимагає етап, і завершується. |
| Перевірка | runner | Проганяє контракти в такому порядку: scope, task file, trace, gate, closing. |
| Запис | runner | Переводить статус, комітить після зеленого гейту або паркує задачу з причиною. |
Пройди той самий юніт як повідомлення між runner, координатором і його спеціалістами. Третій сценарій показує, що стається, коли координатор перестає тримати хід.
- вибір · гілка · знімок
- claude -p
- напиши тест
- тест готовий
- зроби, щоб пройшов
- тримай хід
- код готовий
- фінал · exit 0
- scope ✓ task file ✓ gate ✓
- коміт · → qa
вибір · гілка · знімокRunner бере T-002 у implementing, перемикається на її гілку і робить знімок дерева.Що отримує координатор
Runner збирає промпт кожного координатора з п'яти частин, у такому порядку:
- промпт етапу —
prompts/spec.md,prompts/plan.md,prompts/implement.mdі так далі, по одному на етап; - постійні правила — правила, потрібні кожному агенту, наприклад ніколи не вбивати процеси за шаблоном;
- спеціалісти цього етапу — ім'я кожного, коли його викликати, і його опис;
## Memory— виміряні факти й нотатки попередніх юнітів, описані нижче;## This run— факти цього юніта: задача, файл, етап, гілка, база, scope, gate, тека артефактів, bounces, адреса застосунку, коли runner його запустив, рядок вердикту, якого вимагає етап, і секції файлу задачі, у які цей етап може писати. Усе інше йде всередину цих секцій як підсекції###; будь-який інший заголовок##зупиняє юніт.
Як запускається координатор
Runner запускає claude напряму, без shell. Smoke-запуск на Claude Code 2.1.308 цю команду прийняв:
claude -p --output-format stream-json --verbose --model <model> \
--permission-mode dontAsk --setting-sources project,local \
--agents .harness/trace/unit-NNNN.agents.json --allowedTools …
--agentsпередає спеціалістів цього етапу, злитих із базового реєстру і реєстру проєкту.--permission-mode dontAskвідмовляє в недозволеному інструменті, а не чекає на людину, якої поруч немає. У smoke-запускуgit commitвідхилено одразу, без зависання, а відмову записано вpermission_denialsподії result.- В allowlist
agent.allowedToolsнемає git commit і push. Це другий паркан за контрактом scope: коміти — робота runner. --setting-sources project,localне пускає в цикл твої особисті хуки користувача.- Оточення задає
CLAUDE_CODE_DISABLE_CLAUDE_MDS=1, тож агенти не вантажать файлиCLAUDE.mdпроєкту і витрачають ці токени на задачу.
harness preview T-002 друкує точну команду і промпт наступного юніта задачі й не витрачає жодного токена.
Тримай хід
Це правило ламає більшість перших спроб написати координатора.
У Claude Code CLI кожен виклик саб-агента асинхронний: виклик повертається одразу, а спеціаліст працює у фоні. У
claude -p повідомлення без виклику інструмента завершує хід, а з ним і процес.
Тож координатор, який роздав роботу трьом спеціалістам і написав «Чекаю на результати», щойно завершив юніт. Спеціалісти закінчують за хвилину, і їхні відповіді не потрапляють нікому.
Страховка — контракт трейсу: якщо обов'язкового вердикту немає, юніт падає, а не проходить на мовчанні.
Ланцюжок збірки: implement, qa, judge
Збірка, перевірка і суд — три окремі юніти. Кожен запускає свіжого координатора, тож суддя ніколи не бачив міркувань implementer, лише результат. Усередині implement-юніта tester спершу пише тести, а implementer — код, з яким вони проходять.
| Юніт | Читає | Може писати | Куди далі |
|---|---|---|---|
| implement | план, його scope; після повернення — звіт | тести й код у межах scope; harness комітить після зеленого гейту | qa |
| qa | коміт і критерії | лише .harness/artifacts/T-NNN/ | PASS → judge · FAIL → implementing · CANNOT VERIFY → parked |
| judge | коміт, план, звіт qa | лише .harness/artifacts/T-NNN/ | CONFIRMED → done · REJECTED → implementing |
Коміт після кожного implement-юніта із зеленим гейтом робить harness, а не агент: у гілці задачі, з повідомленням
T-NNN: <title> (round n). qa і judge рев'юять саме цей коміт.
Ліміт повернень
qa FAIL або judge REJECTED повертає задачу в implementing і додає одиницю до bounces у її frontmatter. Обидва
вердикти ділять один лічильник.
Перш ніж implementer почне повернене коло, implement-юніт викликає debugger. Той читає звіт qa чи судді, знаходить причину і передає implementer діагноз, тож наступне коло лагодить причину, а не пробує наосліп.
Відмова, яка доводить bounces до limits.bounces — 2 за замовчуванням, — уже не повертає задачу. Вона паркує її з
причиною для людини: максимум два implement-кола. Без ліміту implementer і суддя можуть сперечатися вічно, а кожне коло коштує цілий юніт.
Коло, яке нічого не змінило, не паркує задачу, якщо гілка вже містить її роботу; чому це важливо для хибної відмови, пояснює сторінка контрактів.
Пам'ять між юнітами
Свіжий контекст нічого не пам'ятає, тож runner вписує коротку пам'ять у кожен промпт, як секцію ## Memory:
- виміряні факти — статус і bounces задачі, її останні handoff з вердиктами й причинами та diff stat її гілки;
- хвіст
## Logзадачі; - хвіст
JOURNAL.md— нотатки, які попередні юніти лишили наступним; - інші задачі на дошці — id, статус і назва, лише для юнітів spec і plan, щоб специфікація ніколи не рекомендувала те, що вже робить інша задача. Задача з гілкою ще й каже, чи її змерджено в базову гілку, тож план ніколи не будує на роботі, якої там ще немає.
Факти йдуть першими, бо запис у журналі — думка одного агента, а статус у файлі — ні. Жодного хука і нічого в
налаштуваннях проєкту: runner збирає секцію сам, тож harness preview показує і її.