Update SKILL.md files to clarify usage of phase and bug handling skills. Added details about agent waves in phase-work, phase-review, and side-work descriptions, emphasizing the shared merge lock and the distinction between different task types. Improved guidance on handling ongoing phases and the importance of not interfering with others' work.
ci / server (push) Failing after 3m39s
ci / client (push) Failing after 2s

This commit is contained in:
Leonid Pershin
2026-08-20 09:30:24 +03:00
parent 9665302948
commit 723f60a9ca
7 changed files with 415 additions and 17 deletions
+173
View File
@@ -0,0 +1,173 @@
---
name: phase-orch
description: >-
Оркестрирует параллельных агентов /phase-work и /phase-review по графу фаз
в docs/phases/. Аргумент — целевая ширина волны: `/phase-orch 2-3`,
`/phase-orch 3`. Используй при «запусти N разработчиков», «веди срез»,
«оркестрация», «раздели срез между агентами и следи», «продолжай волну».
Не пишет код фаз сам. Не для одной фазы (/phase-work), одного бага
(/bug-work), задачи вне среза (/side-work) и одиночного ревью
(/phase-review).
---
# Оркестрация среза
Ты **координатор**, не разработчик. В этом чате не пишешь код фаз, багов и
side-work. Фазы делают фоновые агенты по [`phase-work`](../phase-work/SKILL.md);
проверку закрытых срезов — по [`phase-review`](../phase-review/SKILL.md).
Твоя работа: держать волну нужной ширины, не запускать фазы с открытыми
зависимостями и не оставлять слот пустым, если есть чем его занять.
## Соседи
| Фраза | Куда |
| --- | --- |
| «сделай фазу 25», «возьми фазу» | `/phase-work` |
| «запусти троих», «веди срез», «продолжай волну» | этот скилл |
| «проверь срез», одно ревью | `/phase-review` |
| «баг», «почини» | `/bug-work` |
| «сделай отдельно», «вне среза» | `/side-work` |
Независимые side-фазы параллельно — тоже этот скилл (так уже сказано в
side-work). Слоты волны багами не заполнять.
## Аргумент
`/phase-orch` или `/phase-orch 2-3` или `/phase-orch 3`.
| Запись | Цель |
| --- | --- |
| нет числа | **23** слота |
| `N` | ровно **N**, если граф даёт; иначе сколько даёт, остаток — ревью |
| `A-B` | держать **от A до B** живых агентов |
N — **одновременные** агенты, не «запусти N и забудь». Пять слотов при двух
независимых ⬜ — это два разработчика, не пять простаивающих.
Потолок без явной просьбы — **4**. Модель разработчикам — та, что назвал
пользователь; иначе та же, что у координатора.
## Старт
1. Прочитай `docs/phases/README.md` и `docs/phases/reviewed.md`.
2. Посчитай, сколько ⬜ с **закрытыми** зависимостями (шапка фазы). 🔄 не бери
как новый захват.
3. Проверь `git branch --list "phase/*"` и `review/*` — заявка уже стоит.
4. Запусти первую волну (см. «Чем занять слот»). Каждому разработчику —
**номер фазы** в промпте, чтобы не гонялись за одной ⬜.
5. **Стоп координатора до уведомления.** Не делай работу агента в foreground.
Не полли транскрипты без сигнала («завис», «продолжай», completion).
Каждый ответ пользователю **заканчивай** списком живых агентов (см. ниже).
Дальше цикл: уведомление или реплика пользователя → пересчёт слотов → запуск
или пинок → снова стоп.
## Чем занять слот
Порядок. Следующий пункт — только если предыдущий не набрал ширину волны.
1. **Разработчик** на ⬜ с закрытыми зависимостями, без ветки `phase/<N>-*`.
Один агент — одна фаза, промпт «новый захват» из
[`worker-prompt.md`](worker-prompt.md).
Замена зависшего — **не** этот пункт: это продолжение 🔄, запуск с
**существующей** веткой и worktree, 🔄 не сбрасывать.
2. **Слияние**. Ветка готова, в `main` нет — merge-агент, не второй автор фазы.
Зависимую фазу **не** стартовать, пока зависимость не в `main` (не «на ветке»).
3. **Ревьюер**, если разработчиков больше некуда ставить:
- следующий срез не в `reviewed.md`, или `git log <хеш>..HEAD -- <пути>` непустой;
- срез в работе (есть ⬜/🔄) — можно, в журнале «в работе на момент проверки»;
- два ревьюера — два среза **или** два этапа большого среза (A / B–C),
никогда один этап; **разные** разделы журнала и ветки `review/…`;
- фазу 🔄/⬜ как «готовую» не закрывай; дописалась посреди ревью — допиши в
тот же проход, не начинай срез заново.
4. Слот пустой — так и скажи. Не выдумывай фазу, не ставь второго автора на 🔄,
не сажай `/bug-work` в слот.
Параллельные разработчики не должны править одни файлы без нужды. В промпте
назови соседа и стоп-границу фазы. Общие `docs/phases/README.md`,
`docs/protocol.md`, `AGENTS.md` — точечно.
## На уведомлении агента
| Исход | Действие |
| --- | --- |
| Фаза в `main`, ✅ | слот свободен → п. «Чем занять слот» |
| Фаза на ветке, merge не вышел (грязный `main`) | merge-агент, если пользователь уже разрешал stash→merge или сказал «сливай». Иначе спроси |
| Ревьюер влил журнал | слот свободен |
| Агент уступил / снят | не запускай дубль той же фазы, пока не ясно, что ветка свободна |
| Пользователь: пауза, только слияние | interrupt разработчикам: коммит WIP **на своей ветке**, не merge, не main. Merge-агентов не трогать |
| Пользователь: последняя волна / остановись | interrupt: добей свою фазу (и merge) и стоп. **Новых** агентов не запускать, в том числе по completion |
| Пользователь: продолжи | снять паузу с WIP-ветки (`resume` с хешем коммита), не начинать фазу с нуля |
Зависимую ⬜ не открывать, пока зависимость 🔄 или лежит неслитой веткой.
## Зависание
Транскрипт из 1–2 сообщений («читаю скилл» / `GetMcpTools`) при живом агенте
дольше ~15 минут, или тишина после interrupt — **завис**.
1. `resume` + `interrupt`: брось MCP (`cursor-app-control` не звать), не читай
скилл заново, продолжай с ветки/worktree.
2. Второй раз — старый: «уступи, git не трогай». Новый агент — **продолжение**
того же 🔄: та же ветка и worktree, промпт «замена зависшего». Это не новый
захват ⬜ и не второй автор.
3. Не убивай `HSchool.Server` из-за MSB3021. Dev-сервер не поднимай.
Подробности: [`hangs.md`](hangs.md). Пинает координатор, не отдельный агент.
## Слияние
Сливает **тот же** phase-work, что делал фазу. Не вышло (грязный `main`, lock,
дерево не на `main`) — merge-агент по блоку «Слить в main» из phase-work и
шаблону в [`worker-prompt.md`](worker-prompt.md). «сливай» — merge-агент
по шаблону, не второй автор фазы.
- Замок `merge/lock` **общий**: фаза, баг, ревью, side. Чужой — ждать, не
снимать и не воровать.
- Основное дерево должно **уже** стоять на `main`. Если там `bug/…` (или
другая ветка пользователя) — не `checkout`, не stash, не merge; слот ждёт.
- Грязный `main`: без явного «сливай» — не stash. С разрешением — это
исключение к dirty-main из phase-work, только в промпте merge-агента:
`stash push -u` **своего** ярлыка, merge, pop только его. Конфликт pop —
оставить stash, не форсировать. **Не** stash’ать незакоммиченное живого
worktree соседа.
- Конфликт README: обе стороны (пришедший ✅ и чужие 🔄/✅).
- `protocol.md`: оставить все блоки (сессия + карточка + темп), не бампить
версию чужой фазы.
- После merge: `branch -d` (не `-D`), снять lock, worktree remove.
## Промпт агента
Координаторский чат **не виден** субагенту. В каждом запуске: скилл, номер
фазы, пути документов, соседи, стоп фазы, worktree **вне** репо
(`…/wt-phase-<N>`), «не пушь», «Server не убивай», отчёт из phase-work.
Замена зависшего — существующая ветка в промпте, не пустой `git branch --list`.
Шаблон: [`worker-prompt.md`](worker-prompt.md).
## Чего не делать
- Писать код фазы, бага или side-work в этом чате.
- Запускать разработчика на фазу с открытой зависимостью «чтобы прогрелось».
- Двух `/phase-work` на один номер.
- Ревьюера вместо единственного свободного разработчика, если слот один и
есть ⬜ с закрытыми зависимостями — сначала код.
- Автопродолжения после «остановись» / «последняя волна».
- `git push`.
- Переставлять чужие 🔄/✅ (замена зависшего 🔄 не трогает: статус тот же).
- Снимать чужой `merge/lock` или `checkout` основного дерева с `bug/…` на `main`.
- Заканчивать ответ без списка агентов (ниже).
## Список агентов
**Последний блок каждого ответа** пользователю — кто сейчас жив. Даже если
в этом ходе никого не запускал и даже если только спросил «можно stash?».
Не прятать в середину отчёта.
| Имя | Роль | Статус |
| --- | --- | --- |
| [Имя](id) | разработчик 32 / merge 36 / ревьюер 29–31 | пишет / сливает / ждёт lock / завис / WIP на паузе |
Пусто — одна строка: «агентов нет».
+77
View File
@@ -0,0 +1,77 @@
# Зависания и грязный main
То, на чём оркестрация этой сессии ломалась. Не чинить «на всякий случай» —
только когда симптом совпал.
## Транскрипт
Живой агент, а в jsonl только стартовый user-промпт и «читаю скилл» /
`GetMcpTools` — он не работает. После `interrupt` снова одна строка —
повторный завис.
Не поллить транскрипты без повода: completion, «завис», «продолжай», тишина
заметно дольше обычной фазы.
## MCP
`GetMcpTools` на `cursor-app-control` и ожидание echovault держали агента
полчаса. В промпте: **не звать cursor-app-control**; memory — один раз или
без неё.
## Interrupt
Короткий промпт: не начинай с нуля, брось MCP, вот ветка и worktree, вот
незакоммиченное, которое нельзя выкинуть. Длинный повтор всего скилла снова
вешает.
Два зависания подряд — старый уступает («git не трогай»), новый — продолжение
того же 🔄: та же `phase/<N>-*` и тот же worktree, статус не сбрасывать.
Это не новый захват ⬜ и не второй автор. Пинает координатор, не отдельный агент.
## Worktree
Путь **вне** репозитория. `node_modules` копировать из основного дерева или
`npm ci`; копия worktree внутрь себя забивает диск. `git worktree remove
--force` после merge; каталог с битым `node_modules` может остаться — prune.
Первая сборка в worktree длинная — это не завис.
## Грязный main и чужая ветка
`merge/lock` общий: фаза, баг, ревью, side. Чужой — ждать, не снимать.
phase-work не сливает, если `status --porcelain` непустой. Портреты, SwarmUI,
чужой WIP на карточке блокировали 32/36/35/38/41.
Основное дерево должно уже стоять на `main`. Если пользователь на `bug/…`
не `checkout main`: снимешь ему IDE. Merge-агент стоп, слот ждёт.
Пользователь сказал «сливай» — stash `-u` своим сообщением, merge, pop
только его. Pop с конфликтом: stash живёт, дерево не калечить.
Не stash’ать файлы, которые пишет сосед в **основном** дереве (он обязан
быть в worktree; если нет — merge-агент стоп и отчёт «main занят»).
## DLL и тесты хоста
MSB3021/3027: процесс пользователя держит `HSchool.Server`. Не убивать.
В отчёте: AppHost на main не пересобрался. Весь `dotnet test` solution
из-за этого не гонять — и так не надо: только проект из Testing policy.
После фазы сессии хостовые тесты логинятся в `ResetAsync`. Два игрока — две
куки, не общий jar. `OpenSchool` / часы от гостя не доходят — сокет-тесты
открывают школу **владельцем**.
## Клиент
`npm test` на Windows иногда падает в параллели — `--maxWorkers=1`.
`vitest` зелёный при мёртвом `tsc`: лови `npm run build` (дубликат ключа,
неиспользуемый import).
## Pause / last wave
Пауза: WIP-коммит на ветке фазы, worktree оставить, main не трогать.
Продолжение: `resume` с хешем WIP, не `git branch` заново.
«Остановись» / «закончи с этими»: текущие доводят merge, координатор **не**
открывает следующую ⬜ по completion.
+125
View File
@@ -0,0 +1,125 @@
# Промпты субагентов
Координатор подставляет номер, пути, соседей. Субагент не видит этот чат.
Тесты везде как у `/phase-work`: только проект(ы) из Testing policy в
`AGENTS.md`, `--filter` на новый класс. Весь `dotnet test` solution и парный
`npm test` «для уверенности» не гонять. Клиентский Vitest — только если
трогали `src/HSchool.Client`. `HSchool.AppHost.Tests` — только HTTP / сокет / хост.
Общее во все промпты: не пушь; `HSchool.Server` не убивай; dev-сервер не
поднимай; `cursor-app-control` не вызывай; memory — один раз или без неё;
stash с пометкой portraits / чужой wip не pop.
## Разработчик — новый захват ⬜
```
Ты агент разработки h-school. Следуй `.claude/skills/phase-work/SKILL.md`
буквально. Один запуск — одна фаза: **<N>. <имя>**. Чужие фазы не трогай.
Репо: <корень>. Сливать только в основном дереве, и только если оно уже на
main (не checkout ветки пользователя bug/…).
Фаза: docs/phases/<файл>.md
Дизайн среза: docs/design/<файл>.md
Инварианты: AGENTS.md
Индекс: docs/phases/README.md — эта фаза сейчас ⬜.
Соседи (🔄 / параллельно): <номера и чего не трогать>.
Стоп фазы: <из её файла>.
Windows Vitest: при падении параллели — `--maxWorkers=1`.
Застолбить до кода:
1. git branch --list "phase/<N>-*" — пусто, иначе стоп (это чужой захват).
2. git branch phase/<N>-<slug>
3. 🔄 в README основного дерева, отдельный коммит только этой строки.
4. git worktree add <scratch>/wt-phase-<N> phase/<N>-<slug>
Клиент: npm ci или копия node_modules (не рекурсивно в себя).
Задачи и обязательные тесты — как в файле фазы целиком.
Гоняй только проект(ы) из Testing policy в AGENTS.md, `--filter` на новый
класс. Весь solution не гонять.
Общие файлы (README фаз, protocol.md, AGENTS.md) — точечно.
HTTP/протокол — docs/protocol.md тем же коммитом; версию сокета не бампить,
если фаза этого не требует.
Слияние по скиллу: убрать worktree, merge/lock (общий: фаза/баг/ревью/side;
чужой — ждать, не снимать), merge --no-ff, конфликт README — обе стороны.
Грязный main или дерево не на main — не сливать, не checkout, снять lock,
отчёт. Stash сам не делай.
✅ в README — последним коммитом ветки, только строка статуса.
Не сливай чужие ветки.
Отчёт: фаза и ветка; задачи; тесты списком; какой проект прогнал; незакрытое; слита ли.
```
## Разработчик — замена зависшего
Продолжение того же 🔄, не новый захват ⬜. Координатор уже знает ветку.
```
Ты продолжение того же /phase-work, не второй автор.
Следуй `.claude/skills/phase-work/SKILL.md`. Блок «Как застолбить» пропусти.
Фаза: **<N>. <имя>**. Ветка уже есть: **phase/<N>-<slug>**.
Worktree: <путь>/wt-phase-<N> — работай там.
🔄 не сбрасывай и вторую ветку не создавай. `git branch --list "phase/<N>-*"`
не обязан быть пустым — это не гонка.
Не начинай фазу с нуля. Брось MCP (cursor-app-control не звать).
Дочитай незакоммиченное в worktree, не выкидывай его.
Дальше — как обычный разработчик: задачи фазы, тесты по Testing policy
(`--filter`, не весь solution), слияние по скиллу (грязный main / не на
main — не stash, не checkout, отчёт).
Соседи: <номера>. Стоп фазы: <из файла>.
Отчёт: как у phase-work.
```
## Merge-агент
Только названная ветка. Код фазы не писать. Протокол — «Слить в main» в
phase-work; stash — только если ниже явно сказано, что пользователь сказал
«сливай».
```
Только слияние ветки <phase/<N>-<slug> | review/<slug>>. Код не писать.
Следуй блоку «Слить в main» из `.claude/skills/phase-work/SKILL.md`.
Замок merge/lock общий (фаза, баг, ревью, side): чужой — ждать, не снимать.
Основное дерево должно уже быть на main. Если там bug/… или другая ветка
пользователя — не checkout, не stash, стоп, отчёт.
<выбрать одно:>
Грязный main: пользователь сказал «сливай». Это исключение к dirty-main
из phase-work. stash push -u своим ярлыком, merge --no-ff, pop только его.
Конфликт pop — оставить stash, дерево не калечить. Чужой wip / worktree
соседа не stash’ать.
<или:>
Грязный main — не stash, снять lock, отчёт.
Конфликт README — обе стороны. protocol.md — не выкидывать чужие блоки.
После успеха: branch -d (не -D), снять lock, worktree remove.
Не пушь. HSchool.Server не убивай. Весь solution не гонять: конфликт только
в статусе — тесты не нужны; в коде — узкий проект из Testing policy.
Отчёт: слита ли; что помешало (lock / не main / dirty / конфликт).
```
## Ревьюер
Урезанный объём задаёт координатор. Это всё ещё `/phase-review`.
```
Следуй `.claude/skills/phase-review/SKILL.md`. Один проход — только фазы
<X><Y> (этап <A> среза <имя>), не весь срез и не следующий.
Свой заголовок в docs/phases/reviewed.md. Чужие разделы журнала не затирай.
Ветка review/<slug>, worktree вне репо: <scratch>/wt-review-<slug>.
Слияние как у phase-work: merge/lock общий, --no-ff, не пушь.
Основное дерево уже на main; не checkout bug/….
Тесты — Testing policy, `--filter`, не весь solution.
Фазу 🔄/⬜ как готовую не закрывай.
Отчёт: что проверено; что дописано; что исправлено; открытое; слита ли ветка.
```