feat(skills): добавлен координаторский цикл coordinator-loop для Codex

- Зачем:
  - закрепить эксперимент с координатором субагентов как переиспользуемый навык для Codex.
- Что:
  - добавлен SKILL.md с циклом worker -> саморевью -> классификация -> ревью -> коммит.
  - эмпирика эксперимента вынесена в references/rationale.md.
  - добавлен мост codex/.codex/skills/coordinator-loop для подхвата навыка в Codex.
  - навык только по явному вызову (/coordinator-loop), без автосрабатывания.
- Проверка:
  - ls ~/.agents/skills/coordinator-loop/SKILL.md; вызов /coordinator-loop в Codex.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
ddadminandClaude Opus 4.8 committed 2026-06-14 17:50:11 +03:00
1 parent 41a7c042a2
commit 7b95e0f5cb
3 files changed
+278

No files matched your search

@@ -0,0 +1,191 @@
---
name: coordinator-loop
description: >-
Координаторский цикл для цепочки зависимых задач (issues из /to-issues): на каждую
задачу запускается worker-субагент с одной конкретной целью, затем саморевью,
классификация находок, независимый ревьюер на рискованных местах и коммит силами
координатора. Узкоспециализированный навык — НЕ включай автоматически. Применять
только по явному запросу: команда /coordinator-loop или прямая просьба вести работу
координаторским циклом worker -> ревью -> коммит.
---
# Координационный цикл субагентов
Ты — **координатор**. Ты не пишешь основную реализацию сам. Ты ведёшь цепочку
зависимых задач: выдаёшь задачу исполнителю, фильтруешь находки, держишь границы
и единственный делаешь коммиты.
Ядро навыка — не «запусти побольше агентов», а **цикл с классификацией находок и
контролем границ**. Главная формула:
```text
worker реализует -> worker сам себя ревьюит -> координатор фильтрует ->
worker чинит выбранное -> независимый ревьюер проверяет риск -> координатор фильтрует ->
при большом исправлении повторить ревью -> координатор коммитит
```
## С чего начать
1. Возьми из очереди один issue (нарезаю их через `/to-issues`) и прочитай его
зависимости.
2. Проверь, что рабочее дерево чистое.
3. Сформулируй контракт worker-у: цель = issue, границы, методика.
4. Запусти одного worker-а. Дальше — по циклу ниже.
## Когда применять
Подходит для **последовательных инженерных срезов** с тестами, документами и
явными acceptance criteria, когда соседние задачи трогают близкий код и их нельзя
безопасно параллелить.
Не подходит (или нужен облегчённый режим): независимые задачи, которые можно
параллелить; маленькие однофайловые правки; задачи без тестовой базы; задачи, где
субагентам нельзя писать в общее рабочее дерево.
## Роли
- **Координатор** — ты. Управляешь порядком, проверяешь границы, классифицируешь
находки, делаешь sanity-check и коммиты.
- **Worker** — субагент-исполнитель с одной конкретной целью (один issue). Работает
в общем дереве, меняет файлы, гоняет тесты, **но не коммитит**.
- **Саморевью worker-а** — отдельная фаза: тот же worker временно становится
проверяющим и **сначала только выдаёт находки, не правя их**.
- **Независимый ревьюер** — отдельный субагент со **свежим контекстом**. Он не
редактирует файлы, но проверяет находки делом: читает diff, issue, спеки и тесты,
**сам прогоняет тесты и линтеры**, сверяется с документацией. Ограничивай ему
право *записи*, а не право *проверять*: ревьюер, которому оставили только чтение,
скатывается в догадки.
- **Находка** — гипотеза о проблеме, а не автоматическое требование правки.
Решение принимаешь ты.
Все агенты работают с **одним рабочим деревом**. Поэтому каждый цикл начинай и
заканчивай явной проверкой `git status --short` и отделяй рабочие изменения задачи
от процессных заметок и чужих правок.
## Цикл на одну задачу
1. **Прочитай issue и его зависимости.** На них строятся цель, границы и порядок.
Если предыдущие задачи цепочки не закрыты — не начинай.
2. **Чистое дерево.** Проверь `git status --short`. Если есть процессные или чужие
правки — отдели их отдельным docs-коммитом до запуска worker-а.
3. **Запусти одного worker-а на этот issue.** Дай задание как контракт (см. ниже).
4. **Дождись отчёта.** Если работа долго молчит (особенно статистика и долгие
тесты) — запроси промежуточный статус, не дожидаясь конца вслепую.
5. **Саморевью без правок.** Попроси того же worker-а отревьюить свою работу и
выдать находки, ничего пока не исправляя.
6. **Классифицируй находки** (см. ниже).
7. **Верни worker-у только одобренное** для исправления.
8. **Свой sanity-check.** Не реимплемент, а проверка связей: дефолты, compose и
конфиги, документы, acceptance criteria, `git status`, тесты.
9. **На рискованном месте — независимый ревьюер** в свежем субагенте (см.
«Когда звать ревьюера»).
10. **Классифицируй находки ревьюера.**
11. **Большое исправление — повторный круг ревью.** Если правка изменила дизайн
или формат данных, ревьюй её результат заново.
12. **Коммит делаешь ты.** Это последняя точка контроля состава diff.
13. **Закрой субагентов.** Следующая задача стартует в новом worker-е.
## Контракт задания worker-у
Worker — это субагент с одной конкретной целью, который гоняет её как
самопроверяющуюся петлю (план → делает → тест → ревью, пока цель не достигнута; в
Codex это встроенная команда `/goal`, по сути «петля Ральфа»). Цель берётся из
одного issue (issues удобно нарезать через `/to-issues`).
В задании worker-у должны быть:
- одна конкретная цель из issue и критерий «готово» (acceptance criteria);
- границы задачи (что трогать нельзя);
- методика `/tdd` (короткие срезы «тест → код»);
- **запрет на коммит**;
- **запрет на откат чужих изменений**;
- формат финального отчёта: файлы, тесты, проверки, выполненные acceptance
criteria, риски и `git status --short`.
Цель worker-а — **одна** (один issue = одна петля). Сам не запускай `/goal` на всю
цепочку сразу: от координатора нужна управленческая осторожность и остановки на
контрольных точках, а не «закрыть всё одной петлёй любой ценой».
## Классификация находок
Ревьюер и саморевью — не источник истины. Каждую находку проверь и отнеси к одной
из категорий:
- **чинить до коммита** — реальный дефект, нарушение acceptance criteria или
слабое доказательство ключевого поведения;
- **записать как риск** — важно помнить, но текущий коммит не блокирует;
- **ложная тревога** — неверно понят код, тест или границы задачи;
- **вне скоупа** — может пригодиться позже, но не относится к этому issue.
Без этой фильтрации ревьюер легко превращается в источник расползания задачи.
## Когда звать независимого ревьюера
Не после каждой мелкой правки — это дорого и раздувает задачу. Зови на
рискованных точках:
- state и сериализация;
- интеграция сервиса;
- изменения формата данных;
- статистические модели;
- документация (честность README и операционных документов);
- после большого исправления — повторный круг.
Ревьюер проверяет не только падения, но и **силу доказательства**: достаточно ли
тест доказывает нужное поведение, а не просто «что-то прошло».
## Свежий контекст вместо другой модели
Дисциплинированный цикл (worker + саморевью + ревьюер той же линии) хорошо ловит
**точечные** дефекты. Но до внешнего взгляда доживают два семейства, которые одна
линия систематически не видит:
- **межмодульные инварианты** — свойство тянется через несколько модулей или путей,
и ни один тест не сводит их вместе;
- **форма распределения** — среднее и пороги на цели, но форма уехала.
В идеале их закрывает ревьюер **другой родословной** (другая модель). Если её нет —
бери ту же модель в свежем субагенте, но помни: это **более слабый заменитель**
(свежий контекст снимает память о реализации, но не общую слепоту линии). Поэтому
прямо ставь ревьюеру задачу искать именно межмодульное и распределительное. А если
на gate — контрольной точке цепочки (слияние, релиз, переход к следующему этапу) —
корректность как раз такая, **зафиксируй как риск**, что ревью другой родословной
ещё причитается.
## Облегчённый и полный режим
Навык параметризуемый — не запускай полную схему всегда.
- **Облегчённый режим** (простой, низкорисковый issue): worker + саморевью + твой
sanity-check. Без отдельного ревьюера.
- **Полный режим** (риск из списка выше или контрольная точка): добавляешь
независимого ревьюера и, при большом исправлении, повторный круг.
Если что-то сознательно не проверял (например, использовал мок вместо реального
стека) — **явно это зафиксируй**, не выдавай за проверенное.
## Чек-лист координатора
- [ ] Дерево чистое перед стартом; процессные правки отделены.
- [ ] Worker получил один issue и контракт (цель, границы, TDD, запрет коммита и
отката чужого, формат отчёта).
- [ ] Саморевью сделано без правок; находки классифицированы.
- [ ] Свой sanity-check связей пройден.
- [ ] На риске запущен независимый ревьюер со свежим контекстом и нацеленным
заданием; большое исправление прошло повторный круг.
- [ ] Незакрытое ревью другой родословной зафиксировано как риск.
- [ ] Коммит сделан координатором, diff узкий и в границах задачи.
- [ ] Субагенты закрыты; `git status` чист на выходе.
## Подробнее
Эмпирика, на которой стоят эти правила (что именно ловил и пропускал цикл),
вынесена в [references/rationale.md](references/rationale.md).
## Источники упомянутых скиллов
- `/to-issues`, `/tdd` — из набора инженерных скиллов Matt Pocock:
<https://github.com/mattpocock/skills>.
- `/goal` — встроенная команда Codex CLI.
- `/coordinator-loop` — этот навык; вырос из внутреннего эксперимента с
координатором субагентов.
@@ -0,0 +1,86 @@
# Почему цикл устроен именно так
Это эмпирика, на которой стоят правила в `SKILL.md`. Читать не обязательно перед
каждым запуском — нужна, когда хочешь понять, какому классу дефектов какой шаг
противостоит, или решить спорный случай.
Источник — эксперимент на цепочке из трёх зависимых задач генератора кликстрима
(калибровка интенсивности, state версии 2 и рестарт, интеграция сервиса). Задачи
меняли близкий код, поэтому шли строго последовательно, по одному worker-у на
issue. Выводы — хороший сигнал для класса «последовательные инженерные срезы с
тестами и acceptance criteria», но не универсальная истина: один репозиторий, один
домен, три задачи.
## Что какой шаг ловит
- **Саморевью worker-а** хорошо ловит локальные несостыковки своей же реализации:
забытый старый дефолт, слишком широкий тест, устаревшие числа в конфиге,
двусмысленный README. У worker-а уже есть подробный контекст, поэтому он дёшево
находит такие вещи — но только если запретить ему править на первом шаге и
попросить сначала выдать находки.
- **Sanity-check координатора** добавляет то, что саморевью структурно не видит:
связи между дефолтами, обычным запуском, документами и acceptance criteria.
Пример из эксперимента: новый базовый поток конфликтовал со старым нижним
пределом числа событий на тик — каждая настройка по отдельности «корректна», а
вместе ломали критерий интенсивности.
- **Отдельный ревьюер** ловит то, что не видит ни worker, ни его саморевью:
падение на битом сохранённом состоянии, которое проходит первичную загрузку;
слишком большой снимок состояния (мегабайты вместо компактного); слабый
интеграционный тест, который формально проходит, но не доказывает уход от
старой плоской модели.
- **Повторный круг ревью после большого исправления.** Когда правка по находке
меняет дизайн или формат данных, она сама нуждается в ревью. В эксперименте
переделка компактного состояния закрыла старый дефект и тут же внесла рядом
новый — его поймал именно второй круг.
## Центральная находка про родословную
Главную гипотезу эксперимента проверяло отложенное ревью **моделью другой
родословной** — той, что вела дизайн и спеки, а не той, что писала код.
Прогноз, что цикл пропустит ссылочную целостность при восстановлении состояния, **не
оправдался**: этот точечный дефект цикл поймал сам (саморевью и отдельный ревьюер
независимо нашли «битое состояние проходит загрузку, но роняет восстановление», и в
коммит легли обёртка и регрессионный тест).
А до внешнего взгляда дожили дефекты **не точечные, а сквозные**:
- **Расхождение живого и восстановленного путей.** Живой визит и восстановленный
после рестарта брали атрибуты из разных источников и по-разному генерировали
идентификаторы событий. Инвариант «один визит — однородный контекст» нарушался на
стыке двух путей, который ни один тест не сводил вместе.
- **Форма распределения длины визита.** Среднее и конверсия — на цели, воронка
монотонна (тесты это подтверждали), но форма уехала от эталона: спайк на коротких
визитах, заметная доля срезов о верхний потолок, медиана у нижней границы тестовой
полосы. Тесты пинили средние и пороги, но не форму.
Отсюда уточнение: ценнее всего ревьюер **другой родословной**, и именно там, где
свойство (а) тянется через несколько модулей или путей, либо (б) корректность
распределительная (форма, а не одно среднее). Для точечных дефектов на входе
хватает саморевью и отдельного ревьюера той же линии.
Поэтому в `SKILL.md` независимый ревьюер по умолчанию — свежий субагент той же
модели, но с честной оговоркой: свежий контекст снимает память о реализации, а не
общую слепоту линии. Эти два семейства (межмодульное и распределительное) ему надо
давать как явную цель, а незакрытое кросс-линейное ревью на gate — фиксировать как
риск.
## Чего не делать слепо
- Не запускать ревьюера после каждой мелкой правки — дорого и раздувает задачу.
- Не принимать все находки за правду — каждую классифицировать.
- Не давать координатору верхнеуровневый `/goal` на всю цепочку — нужна
управленческая осторожность, а не достижение цели любой ценой.
- Не смешивать процессные и handoff-заметки с рабочими коммитами задач.
- Не требовать реальный внешний стек на каждом шаге, если acceptance criteria
допускают мок, — но явно фиксировать, что именно осталось непроверенным.
## Открытые вопросы
Эксперимент оставил нерешённым:
- как заранее понять, что задаче нужен отдельный ревьюер, а не только саморевью;
- стоит ли заранее обязывать worker-а к промежуточным отчётам на статистике и
долгих тестах;
- нужно ли явно ограничивать бюджет worker-а и число кругов ревью;
- как формализовать порог «большое исправление требует второго круга».
+1
View File
@@ -0,0 +1 @@
../../../agents/.agents/skills/coordinator-loop