Языковые правила лежали внутри скилла tasks: англицизмы, неизвестные термины, «сложность формулировки — не признак сложности работы». Три пункта из практики, без общей опоры и без ответа на «а что ещё сюда относится». Дом у языка теперь один — canon/references/language.md. Не в tasks, хотя пришли правила оттуда: они относятся к документам канона, решениям ADR, запискам разведки и сообщениям коммитов в той же мере, что к задачам, а каталог задач и сам часть docs/. Раскладка отвечает, где текст лежит, — этот файл отвечает, каким он должен быть словами. Основа — информационный стиль Ильяхова, взятый не целиком. Взято: полезное действие, глагол вместо отглагольного существительного, активный залог, факт вместо оценки, стоп-слова, одна мысль — одно предложение, параллельность, работающий заголовок. Отброшенное названо вслух, и это отдельный раздел. Инфостиль написан для текстов, где читателя надо удержать, а проектный текст читают потому, что надо. Парцелляция ломает причинную связь, а в решении ценность именно в ней. Запрет вводных целиком режет «если» и «в отличие от» — условия, то есть сведения. Скобки в технической записи несут уточнение: имя команды, единицы, слаг. Без этого раздела правило читается как «пиши короче», и первый же агент начинает резать «поэтому» и «иначе». «Снять корону с себя и надеть на клиента» переведено на здешнего читателя: клиент — ты сам через квартал и тот, кто возьмёт задачу. Таблицы англицизмов и жаргона взяты из скилла prepare-jira-text и дополнены; в устав агента они уехали помеченной копией. Устав обязан быть самодостаточным — он не разрешает пути плагина и не ходит по ссылкам, — а два дома у одного правила здесь уже трижды расходились. scripts/copies.py считает теперь 4 копии при 4 домах. У агента вычитки правил стало двенадцать, разделены на форму записи (только для задач) и язык (для любого проектного текста). Находки докладываются в этом порядке: форма меняет решение «брать или не брать», язык — только цену чтения. DECISIONS тема 21 (ЛЛЛ–ООО, следствия 86–88), changelog канона v3 — пункт 6 и шаг переезда «прочитать и ничего не переписывать задним числом». Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
55 KiB
name, description
| name | description |
|---|---|
| tasks | Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). Заведение задачи, идеи или цели из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, мозговой штурм идеи, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Ритуал между спринтами — скилл session. Не реализует задачи — этим занимается пайплайн проекта. |
Задачи
Задачи — каталог markdown-файлов. Одна запись = один файл items/<slug>.md плюс
строка ровно в одном индексе. Скилл владеет форматом и содержимым:
заводит, редактирует, закрывает, разбирает находки ревью, дробит, штурмует идеи.
Чем он не владеет: ритуалом между спринтами (разбор вопросов → разбор
прошедшего спринта → переоценка → выбор цели и набор) — это скилл session; и
выполнением задачи — это пайплайн проекта.
Пять правил, из которых всё следует
Ситуация не покрыта инструкцией — решай по ним.
- Цель — возможность приложения, задача — шаг к ней. Цель отвечает на «что приложение будет уметь», её «Завершение» — наблюдаемый признак того, что уже умеет; задача отвечает на «что для этого нужно сделать». Оценивается проект по поведению, а не по внутреннему устройству, поэтому и роадмап отвечает не «сколько работ осталось», а «что уже умеет и чего ещё не умеет». Свойство поведения — тоже возможность: «сообщает о своём состоянии», «исход слияния не зависит от порядка доставки» — законные цели.
- Беклог гниёт с той стороны, где его пополняют. Заведение — самая частая операция и с худшим отказом: из одного разговора рождается пять файлов, а переоценка потом разгребает то, чего не надо было заводить. Дедупликация и фильтр на входе дешевле любой чистки. Заводим только то, что не делаем сейчас и о потере чего пожалеем.
- Файл — источник истины, индексы производны. Разошлись — неправы индексы.
Согласованность механизируема и проверяется командой, а не вниманием: всё,
что ловит
tasks.py check, не должно попадать ни в чек-лист, ни в промпт. Поэтому «зачем» живёт в мете файла, а строка индекса его лишь повторяет: пока поле лежало только в индексе, восстановление пропавшей строки теряло его молча и навсегда. Единственное исключение намеренное: в каком индексе лежит задача, знают индексы — «в спринте» это свойство спринта, а не файла, поля-состояния нет. - Причина переживает запись. Выкинутая без причины задача вернётся через
квартал тем же текстом. Реализованная оставляет след в коммите — выкинутая не
оставляет ничего, поэтому у неё есть
REJECTED.md. - Порядка нет, есть цель — но цель есть не у всякой задачи. Приоритетов,
«повысить» и «встать раньше» нет: «что делать дальше» отвечает набор спринта,
а между спринтами порядок не нужен никому. Цель обязательна там, где она и
есть содержание работы, — у новой возможности (
kind:feature). Починка, техдолг и разведка служат работоспособности, а не направлению, и живут без цели законно; в набор спринта они входят помимо его цели. Придуманная им цель — то же враньё, от которого спасает род работы.
Раскладка
Каталог задач — docs/tasks, жёстко: это часть
канона документов, и подгоняется под него
проект, а не наоборот.
docs/tasks/
items/ задачи и цели файлами, <slug>.md, слаги английские
ROADMAP.md состояние проекта: что уже умеет и чего ещё не умеет
BACKLOG.md что можно взять — только задачи, целей здесь нет
SPRINT.md текущий спринт: цель, набор, дата
REJECTED.md ушедшее БЕЗ реализации, с причиной и датой
Правило, снимающее путаницу: BACKLOG.md — то, что берут; ROADMAP.md — то,
подо что берут. Цель в спринт взять нельзя, поэтому в списке берущихся ей не
место.
Четыре секции роадмапа, и первая отвечает на половину вопроса:
| Секция | Англ. | Что в ней |
|---|---|---|
Готово |
Done |
достигнутые цели — строкой с датой, без ссылки на файл: файл удалён, поведение живёт в спеках |
Запланировано |
Planned |
очередь значима и обосновывается прозой рядом |
Направления |
Directions |
очереди нет, тянутся долго |
Разработка |
Tooling |
инструмент и процесс — не возможности приложения, и потому отдельно |
Секции роадмапа канонические, секции беклога — нет, и разница не в любви к
единообразию. У каждой секции роадмапа свой смысл, в первую пишет сам close, и
роадмап, названный по-своему, читался бы только своим автором. Секции беклога
(Ядро, Инфра) смысла не несут — это полки, и остаются делом проекта.
Отсюда три правила, которые проверяет tasks.py check: состав закреплён
(чужая секция — ошибка, а не вольность), все четыре обязаны быть (нет
секции — нет ответа на её часть вопроса), язык один на весь индекс.
--roadmap-sections у init нет: выбирать нечего.
Заголовок секции — с прописной, после него пустая строка. Во всех индексах
одинаково, включая секции беклога, которые проект называет сам. Написание
канонических секций правит check --fix (заодно и ссылку на секцию в мете
файлов: имя секции принадлежит заголовку индекса, файл на неё только
ссылается); отбивку он ставит везде.
Оговорка про Разработка: слово окружение сюда не годится — в
architecture.md оно уже значит боевое окружение приложения, и одно слово в двух
смыслах развело бы документы канона.
Секции «блокеры» в беклоге нет. Блокер — это состояние (спринт не может
продолжаться ни одной задачей), а не полка: он живёт ровно до ответа человека, и
записи в такой секции не успевают жить. Следы блокера остаются вопросами в
файлах задач распущенного спринта. Постоянно пустая секция со старой семантикой
«разбираются пачками» противоречила бы правилу «блокер эскалируется немедленно»,
поэтому init её заводить отказывается, а check о ней говорит. Проекту,
который переезжает с такой секцией, её надо удалить — это единственное место,
где это сказано.
Задача живёт в одном индексе за раз. Взята в спринт — строка переезжает из
BACKLOG.md в SPRINT.md; вышла — обратно. Файл в items/ при этом не
двигается: он и есть запись, индексы лишь показывают, где она числится.
У сделанной задачи записи не остаётся — файл и строка удаляются (close --implemented). Ей хватает коммита и документации проекта; вторая запись была
бы вторым домом для того же факта. Вопрос «что было в спринте N» отвечается
даром: SPRINT.md лежит под git, git log -p docs/tasks/SPRINT.md отдаёт историю
всех наборов без отдельного журнала.
У достигнутой цели запись остаётся, и это единственное исключение. Файл
удаляется так же, а строка переезжает в секцию Готово с датой. Причина в том,
что цель — не работа, а возможность: «что приложение умеет» это половина
вопроса, ради которого роадмап и открывают, и стирать её вместе с файлом значит
оставить инструмент, отвечающий только «что осталось». Вторым домом это не
становится: поведение живёт в openspec/specs/, а роадмап отвечает когда и в
каком порядке оно появилось — другой вопрос. Ссылки на файл в строке нет
намеренно: файл удалён, а битая ссылка — законная ошибка check.
Куда запись может переехать и какой командой — весь набор переходов:
stateDiagram-v2
state "BACKLOG.md — что берут" as B
state "ROADMAP.md — подо что берут" as P
state "SPRINT.md — набор спринта" as S
state "REJECTED.md — ушла без реализации" as R
state "записи нет — реализована" as D
state "ROADMAP.md, «умеет» — цель достигнута" as A
[*] --> B: add
[*] --> P: add --type goal
B --> P: edit --type goal --section
P --> B: edit --type task --section
B --> S: sprint take
S --> B: sprint drop --reason
S --> D: close --implemented
P --> A: close --implemented
B --> R: close --reason
S --> R: close --reason
P --> R: close --reason
D --> B: reopen --reason
R --> B: reopen --reason
A --> P: reopen --reason
Состояния здесь — где числится строка, а не где лежит файл: файл
items/<slug>.md не двигается ни на одном переходе. Стрелок «руками» на схеме
нет намеренно — каждый переход это команда, и другого способа его совершить не
существует.
Схема — сводка: условия и оговорки живут в тексте разделов, и при расхождении прав текст.
Цели
Цель — возможность приложения. Такой же файл в items/, тип [goal],
перечисленный в ROADMAP.md. Формулируется ответом на вопрос «что приложение
будет уметь», а не названием области работ: не «Работа с чтением», а «Чтение
данных клиентами»; не «Рефакторинг слияния», а «Исход слияния не зависит от
порядка доставки».
Свойство поведения — тоже возможность. «Наблюдаемость» это «приложение сообщает о своём состоянии»; «прочность слияния» это «исход не зависит от порядка». Такие цели законны и переформулировки в функцию не требуют — требуют только, чтобы формулировка отвечала на «что приложение делает», а не на «какую часть кода мы трогаем».
Что целью не является — работа над станком. Инструмент, процесс, сборка, сам этот скилл: на вопрос «что приложение будет уметь» они не отвечают. Им отведена отдельная секция роадмапа, чтобы они были видны в том же экране и при этом не читались как возможности продукта.
Секция выбирается так: очередь значима и обоснована прозой — Запланировано;
тянется долго и очереди не имеет — Направления; не про приложение —
Разработка; в Готово кладёт сам close.
- Список задач цели выводится, а не хранится. В теле цели — зачем она и что
считается её завершением; перечня задач там нет. Он был бы третьим индексом и
поехал бы на первой же закрытой задаче, а
checkпро него не знает. Связь однонаправленна: задача несёт тегgoal:<слаг>, перечень даётtasks.py list --goal <слаг>. - Статус цели выводится. Цель достигнута, когда у неё не осталось открытых
задач;
[x]/[~]руками не ведутся, аcloseцели с живыми задачами скрипт запретит. Достижение —close <цель> --implemented: файл удаляется, строка с датой переезжает вГотово. Ошиблись —reopenвернёт файл и снимет строку достигнутого, чтобы роадмап не утверждал того, чего нет. Единственная оговорка: цель без задач неотличима — «ещё не разобрана» или «всё закрыто». Различает тегdecomposedв мете цели: он ставится, когда цель разложена на задачи. Тег, а не строка в теле — потому что проверяется механически:checkнапоминает о нём у пустой цели (замечанием, не ошибкой — неразобранная цель это законное состояние), аcheck --fixсам проставляет его цели, у которой задачи есть. - Тип
[epic]упразднён. Он был зонтиком между целью и задачами — «задача, которая не мерджится целиком». Зонтик теперь цель, а слишком крупный шаг просто дробится на шаги помельче под той же целью, и промежуточному типу места не осталось. Замер подтвердил: ноль употреблений на 97 записей двух живых проектов. Встретился в чужом беклоге — это цель либо набор задач, иcheckназовёт его неизвестным типом.
Род работы
Тип записи и род работы — две оси, и путать их нельзя. Тип отвечает «что это
за запись» (цель, идея, задача), род — «какого рода работа»: feature, fix,
chore, research. Одним значением на оба вопроса не ответить: идея бывает
про функцию, а цель функцией и является.
feature— снаружи появляется или меняется то, чего раньше не было.fix— поведение расходится с заявленным, и расхождение воспроизводится. Не воспроизводится — этоresearch, а неfix.chore— обслуживание: зависимости, сборка, перенос, чистка. Наблюдаемое поведение не меняется, и в этом всё дело: уchoreтест готовности слабее честно, а не молча. «Что станет наблюдаемо иначе» здесь отвечается разработчику («перестанет собираться два раза», «уедет последний вызов устаревшего API»), а не пользователю. Пока рода не было, такие задачи либо не заводились, либо формулировались как выдуманная польза.research— исход работы знание, а не изменение системы: ответ на вопрос, замер, разведка. Приёмка — записанный ответ (docs/research/, ADR, тело задачи), а не изменённый код.
Дом рода — тег kind:<род>, а не префикс заголовка и не поле меты: теги
здесь единственный механизм разметки, и list --kind fix работает даром. Цена
известна: в строку индекса род не попадает (индексы производны), и «в наборе одни
починки» видно командой, а не глазами по SPRINT.md.
Словарь закрыт. Открытый разъедется на синонимах — bug, bugfix, fix,
defect, — и отбор по роду перестанет отвечать на свой единственный вопрос. Ни
один род не подходит — это сигнал, что в задаче их два и её надо разделить.
Род обязателен у задачи, у цели запрещён, у идеи необязателен — идея получает
его, когда становится задачей. Требуется он там, где по нему принимают решение:
sprint take без рода откажет. check о пропаже только напоминает — беклог,
заведённый до появления рода, законен, и переоформлять его «заодно» здесь не
просят.
Род решает и то, обязательна ли цель. feature без цели не бывает: новая
возможность и есть содержание цели, и если подходящей нет — либо она заводится,
либо это не feature. fix, chore и research живут без цели законно, и
check о них молчит: они служат работоспособности, а не направлению. Это
единственный случай, когда род что-то определяет за пределами отбора, — и
определяет он учёт, а не процесс проверки.
Род не выбирает профиль ревью и вообще ничего не предписывает пайплайну.
Профиль выбирается по факту изменения, а не по роду задачи: chore бывает
миграцией схемы, fix — правкой публичного контракта. Правило «предписание
процесса в теле задачи снимается» родом не отменяется, а подтверждается: он
описывает работу, а не то, как её проверять.
Как написана задача
Три требования к тексту. Первое — про заголовок, два остальных про то, чтобы задачу можно было оценить, не открывая код.
Заголовок отвечает на вопрос своего типа. Вопросов три, поэтому и форм три:
| Тип | Отвечает на | Пример |
|---|---|---|
| цель | что приложение будет уметь | Соперником может быть компьютер |
| задача | что нужно сделать | Печатать поле одним куском кода |
| идея | о чём она | Подсказка следующего хода |
Задача — глаголом в неопределённой форме, перед ним допускается «не»: «Не отбрасывать молча лишние символы в ходе», а не «Лишние символы молча отбрасываются». Описательный заголовок называет состояние, а из состояния не видно, чего от работы ждут: «Ничья объявляется, пока клетки есть» одинаково читается и как жалоба, и как задание, — и в списке, где решают «брать или не брать», это разные вещи. Идея формы действия не несёт намеренно: что делать, ещё неизвестно, и заголовок-действие обещал бы решённость, которой нет.
Из этого же правила растёт разница индексов: роадмап — список возможностей, беклог — список работ, и если заголовки перепутать формами, каждый из них начинает читаться как другой.
check считает заголовки не в форме действия и печатает число в блоке
здоровья, не замечанием на файл: проверка эвристическая (первое слово на
-ть/-ти/-чь), а беклог, заведённый до правила, не переоформляют «заодно».
Годность формулировки — не машине: её смотрит
агент вычитки.
Функции и границы, а не намерения. Задача называет, что система начнёт делать, и какие границы это трогает: эндпоинт или команду, таблицу и миграцию, формат на диске, публичный тип пакета, внешний сервис. Перечень живёт разделом «Затрагивает» (форма — references/task-format.md) и требуется к взятию в спринт. Без него задача оценивается по объёму текста, а не по объёму поверхности, — и оценка систематически занижена ровно там, где текст короткий, а границ много. Названы границы, а не то, как они изменятся: план реализации живёт в предложении об изменении, а не в задаче.
Предметно, но без усложнения. Текст задачи читает человек, который решает, брать её или нет, и делает это по строке индекса и одному экрану тела.
Язык — общий для всех проектных текстов, и живёт он одним файлом: ../canon/references/language.md (информационный стиль, применённый к задачам и документам канона; там же таблицы англицизмов и жаргона и то, что из стиля отброшено намеренно). Задаче он даёт четыре требования, которые нарушаются чаще прочих:
- глагол вместо отглагольного существительного: «обработчик не проверяет владельца», а не «проверка владельца не осуществляется»;
- факт вместо оценки: «время ответа доходит до 800 мс», а не «работает медленно». Оценка без факта рядом — настроение, а не сведение;
- англицизм с живым русским аналогом заменяется: не «зафиксить флоу», а
«починить порядок доставки». Имя вещи не переводится: слаг, команда, тип в
коде,
API; - термин не из документов проекта вводится одной строкой или не употребляется. Свой словарь у задачи — самый дешёвый способ сделать беклог нечитаемым для того, кто вернётся к нему через квартал.
И одно требование, которое есть только у задачи: сложность формулировки — не признак сложности работы. Задачу, которую не удаётся сказать просто, чаще всего не удаётся и оценить: это либо две задачи, либо идея.
Эти правила — про язык, а не про объём: короткая задача без границ хуже длинной с ними.
Инструмент (tasks.py)
Пусть tk="$CLAUDE_PLUGIN_ROOT/skills/tasks/scripts/tasks.py", а D —
docs/tasks от корня проекта. --dir стоит в примерах намеренно: вызов из
подкаталога — обычное дело.
python3 $tk check --dir D # согласованность индексов + здоровье
python3 $tk check --dir D --fix # + починить дрейф (секция, заголовок, дубли, «зачем», форма меты)
python3 $tk list --dir D [--stale] [--section S] [--type T] [--kind K] [--tag a,b] [--goal S] [--index …] [--questions]
python3 $tk add --dir D --slug S --title T [--type goal|idea] [--section S] [--goal G] [--kind K] [--why «зачем»] [--tag a,b]
python3 $tk edit S --dir D [--title T] [--why «зачем»] [--type T] [--goal G] [--kind K] [--add-tag a,b] [--rm-tag c]
python3 $tk move S --dir D --section S [--reason R] [--after S | --first]
python3 $tk close S --dir D --reason R # в REJECTED.md + удалить (ушла без реализации)
python3 $tk close S --dir D --implemented # просто удалить (реализована и закоммичена)
python3 $tk reopen S --dir D --reason R # вернуть закрытую: приёмка не сошлась
python3 $tk sprint start --goal S --dir D | take S… | drop S… --reason R | close [--dissolve --reason R]
python3 $tk init --dir D [--sections …] [--roadmap-sections …] [--items …] [--backlog …] …
python3 $tk adopt scan --from … | apply --plan … # разовая адаптация, references/adopt.md
Коды выхода — единый словарь; на нём ветвятся скиллы, а не на тексте вывода:
| Код | Что случилось | Что делать |
|---|---|---|
| 0 | сошлось / сделано | дальше по сценарию |
| 1 | только check: найден дрейф индексов и файлов |
check --fix, остаток разобрать |
| 2 | ошибка употребления: аргументы или нарушенное правило | читать сообщение, это отказ по существу |
| 3 | окружение: каталог не найден, конфиг битый или мимо диска | чинится путём или docs/.pm.json, повтор не поможет |
| 4 | внутренний сбой | дефект скрипта, доложить |
Различать 1 и 3 обязательно: «дрейф в беклоге» — рабочая ситуация, «каталога нет» — нерабочая, и одинаковая реакция на них была бы неверна в обоих случаях.
Тип — английское ключевое слово goal / idea / task (как и прочие токены
команд); task префикса не несёт, остальные кодируются [goal]/[idea] в
заголовке. Текст задачи при этом русский.
Мутации правят файл и индексы заодно — руками строку индекса или мету
не пиши, зови add/edit/move/close/sprint. Смена заголовка, «зачем», типа,
цели, рода работы и тегов — это edit: он держит H1, мету и индекс в синхроне.
Снятие тега — --rm-tag (после ответа на вопрос снимается question), смена
цели — --goal, рода — --kind; оба заменяют прежнее значение, а не добавляют
второе.
Переезд между индексами — следствие смены типа, а не отдельная команда.
edit <slug> --type goal --section <часть роадмапа> переносит строку из
BACKLOG.md в ROADMAP.md (и обратно --type task --section <секция беклога>);
move двигает только внутри одного индекса и пишет причину. --section у
edit работает только при таком переезде — иначе он отсылает к move,
потому что смена секции без причины и есть тот дрейф, который потом никто не
объяснит. Задача в наборе спринта тип не меняет вовсе: сперва sprint drop.
Тело задачи скрипт не трогает:
add кладёт заголовок, мета-блок и шаблон с подсказками, тело дописываешь
редактором (пока плейсхолдер на месте, check напоминает).
check — единственный судья согласованности; что именно он ловит, скажет его
вывод, здесь не пересказываем. Гоняй его в начале сессии и после каждой
правки, даже если правил мутациями: дрейф мог накопиться раньше. Накопившееся
чини check --fix — он детерминированно правит то, где истина однозначна
(секция, заголовок, дубли, «зачем» из индекса в файл, старая форма меты,
пометка decomposed у цели с задачами), а неоднозначное (задача сразу в двух
индексах, нечего восстанавливать) печатает отдельной пометкой НЕОДНОЗНАЧНО —
это тебе, и это идёт строкой доклада. Ссылка на исчезнувший файл в пометку не
попадает: --fix её просто не трогает, и она остаётся ОШИБКА обычного
check — то есть видна, но в докладе её надо назвать отдельно.
--fix правит и файлы — ровно в двух местах, где источник ровно один и
выбирать не из чего: «зачем», оставшееся только в индексе, переезжает в мету,
и цель, у которой есть задачи, получает тег decomposed. Оба случая печатаются
поимённо.
Что механизировано, а что нет. У задачи, взятой в набор (sprint take и
check по задачам спринта), проверяются три вещи, и у каждой своя глубина:
- критерии приёмки — число пунктов жёстко (меньше двух отказ, больше пяти замечание), наличие оракула эвристикой по слову «оракул» в пункте;
- род работы — жёстко: назван и из закрытого словаря;
- раздел «Затрагивает» — только наличие непустого. Полнота перечня машине не видна: границу, которую забыли назвать, она от отсутствующей не отличает.
Настоящий оракул от слова «оракул» машина тоже не отличает, поэтому эвристика даёт только замечание, и в докладе это называется как есть: «проверено число пунктов и наличие границ, годность оракулов и полнота границ — глазами».
Формат файла, меты, слага, индексов и REJECTED.md —
references/task-format.md. Там же тест «готова к
взятию», требования к критериям приёмки и раздел «Затрагивает».
Сценарии
Завести задачу, идею или цель из диалога
- Фильтр. Делаем прямо сейчас — не заводим. Не пожалеем о потере — не заводим. Родилось три кандидата — покажи их и спроси, какие заводить: молча заведённая пачка и есть тот самый отказ из правила 1.
- Дедуп.
listплюс поиск по слагам, полю «зачем» и телам (grep -ril), включаяREJECTED.md. Нашлось среди живых — дописываем в существующий файл, а не заводим соседний. Нашлось вREJECTED.md— покажи пользователю ту строку и что изменилось с момента отказа (addпредупредит и сам, но молча заводить нельзя). Две задачи об одном — самая дорогая находка переоценки. - Тип по тесту готовности (см. task-format): проходит — задача, не
проходит — идея (
--type idea). Не делается одним заходом — это не эпик, а несколько задач под одной целью: дроби сразу. Возможность приложения, а не шаг — цель (--type goal). - Цель задачи — если род её требует. У
featureдолжен быть--goal <слаг>: новая возможность и есть содержание цели. Подходящей нет — либо она заводится (--type goal), либо перед тобой неfeature. Уfix,choreиresearchцели может не быть вовсе, и придумывать её не надо. У идеи цель проставляется, когда идея становится задачей. - Род работы —
--kind feature|fix|chore|research(см. «Род работы»). Не подходит ни один — задача не одна, разбирай. add …, затем допиши тело редактором: одна фраза, затрагиваемые границы, критерии приёмки с оракулами, рамки. «Зачем» отвечает «зачем нужна эта задача» — состояние, остаток, боль, — а не пересказывает первый абзац, и пишется для человека: не «канонизация внутри транзакции», а «тело 40 МиБ держит блокировку 5 секунд, соседние доставки уходят в отказ».check.
Разобрать находки аудита или ревью
Ревью и аудиты — тоже источник задач, но с зеркальной диалогу опасностью: не
пять файлов из одной мысли, а сорок файлов из сорока сырых находок. Защита та
же, что в самом ревью: кластеризация по причине, дедуп против живых и
REJECTED.md, находка без свидетельства → идея, а не задача, и карта кластеров
пользователю до создания файлов. Порядок, отображение серьёзности и привязка к
целям — references/from-review.md.
Прийти в репозиторий, где задачи уже как-то ведутся
Разовая операция: вывести каталог задач из старой раскладки беклога, TODO.md,
заметок или списка шагов роадмапа — references/adopt.md.
Сюда же относится переименование транслитных слагов в английские: оно делается
одним проходом вместе с починкой перекрёстных ссылок, а не по одному слагу.
Если переводить надо не только задачи, а весь docs/ — это скилл
av-dev-pm:canon, и он зовёт этот сценарий сам на своём шаге.
Декомпозиция и штурм идеи
references/split.md. Обе операции превращают одну запись в несколько, и у обеих есть проверяемый тест: части должны мерджиться порознь и каждая давать видимую пользу, а у штурма исход «выкинуть» — полноправный.
Там же шов: где резать, когда допустимых мест несколько. Коротко — по границе, которая одна поднимает ступень ревью выше остальных; и не резать, когда обе половины остаются в одной ступени, потому что несокращаемый костяк проверок платится за каждую задачу отдельно.
Вычитка формулировок
Язык записей судит отдельный проход — агент task-wording, а не тот же
агент, который их только что написал: самопроверка текста слабее всего ровно
там, где формулировка казалась удачной при написании.
Зовётся он пачкой, а не на каждую запись: после заведения нескольких задач, после разбора находок ревью и на переоценке. Ему передаётся список файлов и — если есть — паспорт, архитектура и конвенции проекта: по ним он отличает неизвестный термин от известного.
Он ничего не правит. Возвращает готовые формулировки, и их подставляет скилл:
заголовок — edit <слаг> --title …, «зачем» — edit <слаг> --why …, остальное
редактором. Заголовок и «зачем» — это то, по чему задачу выбирают, поэтому
менять их молча нельзя: покажи предложенное пользователю вместе с тем, что
было. Правки в теле (границы, критерии, язык) применяются сразу.
Что он смотрит и чего не смотрит — в его уставе; коротко: форму записи —
заголовок по типу, «зачем» вместо пересказа, границы вместо замысла, годность
оракулов, предписания процесса; и язык — залог и отглагольные, оценка без
факта, стоп-слова, англицизмы, жаргон, неизвестные термины. Всё, что ловит
tasks.py check, он не трогает намеренно.
Гигиена полей
Правится по ходу любой операции, которая задачи касается (но не «заодно» по всему беклогу):
- протухшее «зачем» — задача изменилась, а поле отвечает на старый вопрос;
особенно после ответа на вопрос задачи: «Решено: …» на «почему это лежит в
беклоге» уже не отвечает. Переписывается
edit <slug> --why …— он правит мету файла и строку индекса заодно; - вопрос, застрявший в прозе — вынимается в раздел «Вопросы» плюс тег
question(edit --add-tag question), иначе он не виден ниlist --questions, ни правилу «задача с открытым вопросом в набор не берётся»; - тег, который некому снять —
questionпосле ответа снимаетсяedit --rm-tag questionвместе с записью ответа в тело и опустошением раздела «Вопросы»: судит раздел, а не тег (references/task-format.md); - свойство репозитория в рамках — номер миграции, хеш, версия зависимости: в лежалой задаче протухает молча и становится ложной рамкой. Снимается; снимок берётся при постановке, а не при заведении;
- предписание процесса в теле — «делать таким-то профилем ревью», «взять такой-то агент»: это второй дом для правила выбора и путь понизить требования решением, принятым до проектирования. Снимается;
- род, разошедшийся с задачей — задача заводилась починкой, а после разбора
оказалось, что поведение никогда и не было заявлено: это
feature, а неfix. Правитсяedit <slug> --kind …; род, оставшийся от прошлой формулировки, врёт ровно там, где по нему отбирают; - границы, названные вместо реализации — «переписать хранилище на новый
драйвер» в разделе «Затрагивает» это не граница, а замысел. Границы —
таблица points и её миграция,эндпоинт POST /ingest,формат отпечатка на диске. Переписывается перечнем; - англицизм и термин из ниоткуда — правится по ходу той же операции, что касается задачи (см. «Как написана задача»). Именно по ходу: беклог не переписывают ради языка.
Переносимость
Скилл независим от языка программирования, сборки, CI и трекера: он ничего не знает ни про Go, ни про npm, ни про конкретный багтрекер — задачи для него просто каталог markdown. Текст задач — русский (язык документации проекта); зашита только латиница слага. OpenSpec ему тоже не нужен.
- Каталог задач —
docs/tasks, жёстко, и--dirпередаётся явно всегда: раскладка канона одинакова во всех проектах, и искать больше нечего. Каталога нет — код 3 и вопрос человеку;initзаводит его только когда проект действительно новый, а перевод чужой раскладки делаетav-dev-pm:canon. У скрипта поиск вверх по дереву ещё жив — он для непереведённых проектов, и полагаться на него скилл не должен: молча найденный чужой каталог это дрейф. - Настройки живут в
docs/.pm.json, ключtasks: имена файлов и заголовков, и только если они отличаются от умолчания. Один конфиг на весь канон, а не по одному на каталог. Неизвестный ключ — код 3 на любой команде, так что лишнее слово в этом объекте останавливает работу с задачами целиком. - Секции беклога берутся из заголовков
##индекса как есть; их количество и названия — дело проекта (умолчаниеЯдро/Инфра). В конфиге их нет — второй список разошёлся бы с заголовками молча.
Вызов из другого плагина
$CLAUDE_PLUGIN_ROOT раскрывается только внутри своего плагина: пайплайн
задачи, конвейер ревью и любой другой чужой контекст до tasks.py по этой
переменной не дотянутся. Мост — вызов скилла через пространство имён, а не
путь:
Чужой контекст зовёт
Skill av-dev-pm:tasksи называет, что нужно сделать («закрой задачу<слаг>, реализована»). Скилл разрешает свой$CLAUDE_PLUGIN_ROOTсам. Путь наружу не выносится вовсе.
Плагина в проекте нет — вызов не разрешится, и вызывающий не выдумывает путь и не правит индекс руками, а сообщает в докладе, что учёт задач остаётся за владельцем.
Слоты проекта
Почти всё, что скиллу нужно знать о проекте, отвечает канон структурой: куда
переезжает суть реализованной задачи — openspec/specs, adr/, архив change;
какие в проекте оракулы — семантика гейта в CLAUDE.md. Отдельными слотами
остаётся то, чего из раскладки не вывести. Проект дописывает в CLAUDE.md:
- Что такое «сделана» — чем задача выполняется (пайплайн проекта) и что входит в его определение готовности. Скилл требует лишь форму: пайплайн проекта пройден + критерии приёмки проверены поимённо.
- Что считается необратимым и потому спрашивается у человека всегда (деплой, выкладка наружу, удаление или перезапись данных).
Ни того ни другого скилл не угадывает: не нашёл — спрашивает пользователя, а не подставляет умолчание.
Общее для всех сценариев
- Развилки — пользователю. Через
AskUserQuestion, с уже сформулированным предварительным суждением (рекомендация — первым вариантом). Что выкинуть, под какую цель отнести, какая рамка идеи верна — решение пользователя. Слаг, формулировка, порядок строк в индексе — механика, делаем сами. - Не больше трёх вопросов за раз. Пачка длиннее трёх тяжела для ответа; решений больше — веди несколько итераций диалога по ≤3, а не один перегруженный запрос. Между итерациями применяй уже решённое.
- Границы покрытия в отчёте. Любая сессия разбора, штурма или интейка заканчивается строкой «просмотрено N из M, не трогали — …». Отчёт без неё сообщает «беклог разобран», не сообщая, какая его часть осталась нетронутой.
- Ничего не удаляем молча. Файл исчезает только через
close—--reason(ушла без реализации) или--implemented(реализована). Прямогоrmнет. - Слаги английские, kebab-case, не транслит:
tie-break-equal-completeness, а неtaj-brejk-pri-ravnoj-polnote. Заголовки, тела и «зачем» — русские.
Чего этот скилл не делает
Не пишет код, не заводит спеки и предложения об изменении, не берёт задачу в
работу — этим занимается пайплайн проекта. Не ведёт спринт и не проводит сессию
между спринтами — это session. Не решает за пользователя, что важно. Не
переоформляет существующие задачи «заодно»: правится то, чего касается операция.