Плагин владел двумя разными вещами сразу — документацией проекта и учётом работ, — и это мешало обеим. Канон нельзя было поставить без задач, задачи без канона, а язык проектных текстов лежал внутри скилла canon и потому принадлежал половине. Теперь плагина два, каждый ставится сам по себе. av-dev-docs: скиллы canon, docs, init; агенты doc-consistency, doc-code-drift, doc-wording; скрипт docs.py. av-dev-tasks: скиллы tasks, session; агенты task-form, task-wording; скрипт tasks.py. Между собой они зовутся через пространство имён, а не по пути в чужое дерево. Все относительные ссылки, пересекшие границу плагина, сняты: tasks больше не указывает в canon, canon не указывает в tasks. Вместо ссылки — имя скилла и оговорка, что вызов может не разрешиться, и это исход, а не поломка. То, что нужно обоим дословно, стало вторым общим домом. Словарь «Сопровождение и эксплуатация» назван в трёх местах трёх плагинов — секция роадмапа, раздел «Эксплуатация» в architecture.md, тема ревью operations — и ни один из трёх им не владеет; он уехал в shared/operations.md, а canon.md и скилл задач везут копии. Три перечня «чем держат проект» уже разъезжались на «метриках и логах» против «мониторинга», так что ссылка тут не годится: плагин, поставленный в одиночку, получил бы указатель в никуда. Тем же способом язык: у av-dev-tasks появилась своя копия language.md. Копий стало 18 при 8 домах. Переименования разведены по смыслу, а не заменой строки: где речь о каноне — av-dev-docs, где об учёте задач — av-dev-tasks. В пайплайне таких мест одиннадцать, и оба адресата там встречаются вперемешку. Журналы (DECISIONS, TODO, HISTORY) намеренно не тронуты: они описывают состояние на момент записи. По той же причине оставлена наблюдённая строка в комментарии docs.py — она цитирует конфиг живого проекта, а не называет плагин. Не входит в этот заход и названо отдельно: слияние canon и docs в один скилл, разделение docs/.pm.json на два конфига и переезд openspec в пайплайн. Гейт зелёный: копии, фронтматтеры, диаграммы, json. Оба скрипта прогнаны после переезда — docs.py version и tasks.py check на фикстуре. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
11 KiB
Адаптация каталога задач
Проект, где задачи уже как-то ведутся, и из имеющегося материала выводится
заполненный каталог задач: цели, задачи, кладбище, индексы. Операция разовая —
после неё проект живёт скиллами tasks и session.
Это часть приведения проекта к канону. Раскладку docs/ целиком ведёт скилл
av-dev-docs:canon; он же зовёт этот сценарий на шаге «каталог задач», потому что
форматом задач владеет tasks, а не canon. Отдельно сценарий вызывается,
когда переводить надо только задачи.
Вход какой угодно: старая раскладка av-dev-backlog (индекс README.md,
кладбище CLOSED.md, приоритеты секциями, транслитные слаги, файлы рядом с
индексом), TODO.md, россыпь заметок, раздел «планы» в README.md, список
шагов роадмапа проекта.
Три правила, из которых всё следует
- Сперва карта, потом файлы. Человеку показывается, что найдено, как разложилось по целям и что не разложилось, — и только после подтверждения пишется хоть один файл. Это то же правило, что у интейка находок ревью: массовое заведение записей без подтверждения — самый дорогой отказ, потому что разгребает его потом переоценка.
- Ничего не терять. Исходный текст переезжает в тело, «зачем» и причина сохраняются, кладбище переносится строка в строку. Переименование слага — не правка, а перенос ссылок: он делается одним проходом вместе с переименованием, иначе останутся битые ссылки, которых никто не проверяет.
- Что не классифицировалось — назвать поимённо. Проглоченный пункт выглядит как «всё перенеслось». Список «не разложилось» идёт в доклад целиком, с причиной по каждому пункту.
Форма: карта — суждение — запись
Механику несёт tasks.py adopt, суждение — ты. Разделено ровно по границе
«машина умеет / не умеет»:
tk="$CLAUDE_PLUGIN_ROOT/skills/tasks/scripts/tasks.py"
python3 $tk adopt scan --from docs/backlog docs/plan.md TODO.md \
--target docs/tasks --out tasks-adopt-plan.json # только чтение
python3 $tk adopt apply --plan tasks-adopt-plan.json \
--refs docs openspec CLAUDE.md README.md # запись
scan ничего не пишет, кроме карты: он распознаёт раскладку, собирает записи,
поля «зачем», причины, кладбище, помечает похожее на транслит и на открытый вопрос в
прозе, и называет поимённо то, что не разложилось. apply пишет каталог
целиком одним проходом и чинит перекрёстные ссылки.
Между ними — твоя работа, которую машина не сделает:
- английские слаги. Перевести
taj-brejk-pri-ravnoj-polnoteвtie-break-equal-completenessможет только тот, кто понимает смысл.scanчестно говорит: проверить надо все слаги, признаки транслита — эвристика; - цели. Шаги роадмапа — готовые цели в
Запланировано(очередь и обоснование у них уже есть); тематические скопления задач — цели вНаправления(«прочность слияния», «журнал и пересборка»). Предлагаешь ты, назначает человек; - что вообще не задача. Обоснование порядка шагов, абзац прозой, заголовок раздела — это не пункты беклога, и они уходят в «не разложилось» с причиной.
Порядок
- Осмотрись. Где лежат задачи, роадмап, заметки. Каталог задач по канону —
всегда
docs/tasks. Секции беклога (--sections) — по умолчаниюЯдро,Инфра; если у проекта деление другое по существу, оно называется здесь, а не подгоняется под умолчание, и становится заголовками##индекса — их единственным домом. Вdocs/.pm.jsonсекции не пишутся. adopt scanпо всем источникам разом. Один прогон, одна карта: два прохода дадут два несогласованных состояния.- Заполни карту:
slug(английский),section,goalу каждой записи; списокgoals— из шагов роадмапа и из тем. Закрытый шаг целью не заводится. Пустойgoalзаконен уfix,choreиresearch— они служат работоспособности, а не направлению; уfeatureцель обязательна. - Покажи человеку карту через
AskUserQuestion, ≤3 вопроса за итерацию, рекомендация первым вариантом. Показывается: сколько записей, предлагаемые цели (порядок и темы) с обоснованием, спорные отнесения, список «не разложилось». Массовые механические решения (слаги, порядок строк) не выносятся — это механика. adopt apply.--refsперечисляет всё, где могут стоять ссылки на слаги: документация, архив изменений,CLAUDE.md,README.md. Скрипт посчитает и покажет, сколько ссылок поправлено и по каким слагам.tasks.py checkи доклад.
apply отказывается писать поверх живого каталога и проверяет карту целиком
до первой записи: неверная секция, дубль слага, цель, которой нет в карте —
всё это отказ до того, как на диске появился хотя бы один файл.
Переходное состояние — объявляется, а не заминается
Сразу после адаптации задачи в большинстве своём не готовы к взятию: у них нет критериев приёмки, а у части может не быть цели. Это нормально, но обязано быть названо, иначе следующий агент примет пустой беклог за поломку.
apply печатает состояние по факту: сколько задач без цели (это ошибки
check) и сколько без критериев (check их ошибкой не считает, но sprint take такую задачу не возьмёт). Закрывается это порциями переоценки — шаг 3
скилла session, 5–8 задач за порцию: проставить цели, превратить «готово,
когда» в критерии с оракулами, вынуть вопросы из прозы в раздел «Вопросы».
Готовность к первому спринту — не «check зелёный», а «есть 2–5 критериев хотя
бы у набора под одну цель».
Чего адаптация не делает
- Не удаляет источники. Старый каталог остаётся на месте: сверить и убрать — дело человека, удалять чужое молча нельзя. В доклад идёт готовая команда.
- Не переписывает подписи ссылок.
[docs/backlog](docs/tasks/BACKLOG.md)— цель поправлена, текст остался; это правится глазами, и таких мест немного. - Не сочиняет критерии приёмки и не придумывает цели, которых в материале нет. Придуманная цель хуже отсутствующей: под неё соберут спринт.
- Не трогает историю. В коммитах старые слаги остаются, и это нормально.
Доклад
- Источники и что в каждом распознано (раскладка, индекс, кладбище, секции).
- Сколько записей перенесено, сколько целей заведено (порядок / темы) и откуда каждая выведена.
- Переименования: сколько слагов, сколько ссылок поправлено и в скольких файлах — числом, а не «поправлены ссылки».
- Не разложилось: поимённо, с причиной.
- Переходное состояние: сколько задач без цели, сколько без критериев, чем и за сколько порций закрывается.
tasks.py check— результат строкой.