Imported from dronrider/devkit (
kit/skills/board-task/SKILL.md). Install upstream withnpx skills add dronrider/devkit --skill board-task. Copyright stays with the author.
name: board-task description: Задача доски docs/TASKS.md от строки до закрытия. Звать, когда трогают задачу: заводят, берут в работу, двигают статус, ставят порядок нескольким строкам цепочкой, пишут сценарий проверки или закрывают.
Задача на доске
Всё, что происходит со строкой задачи от её появления до архива. Кодом эта
процедура не двигает: ветки, ревью, слияние и выкат живут рядом в board-ship,
пачка задач в board-batch, оформление черновиков в board-groom. Правила, из
которых процедура выведена, лежат в RULES.board.md (раздел «Трекинг задач»),
шкалы ранга и цены в RANKING.md, механика в tools/taskctl/README.md.
Доска правится только командами taskctl и только в основном чекауте.
Изменяющие команды из линкованного worktree отказывают сами, а исполнителю с
ревьювером остаётся файл задачи в своём дереве. Смотреть доску через
taskctl list и taskctl show <ID>, а не чтением TASKS.md целиком.
Новая задача
- Разобранная работа идёт строкой сразу, как проявилась:
taskctl addставит её в Backlog по рангу и заводит файл задачи. Перед строкой проходят ворота готовности (актуальность, предмет, конец работы, условия), их полный разбор вboard-groom, раздел «Ворота готовности»; ворота проверяет сессия, а очевидные находки идут строкой сразу, минуя их. - Сырая мысль, ради которой не хочется останавливаться на разбор, идёт мимо
доски:
taskctl draftкладёт её вdocs/tasks/drafts/<ID>.mdи выдаёт ID. Как писать черновик (заголовок-исход в 72 символа, ситуация, осложнение, вопрос, гипотеза), разобрано в скиллеboard-draft, форма вTASKFORM.mdрядом сRANKING.md, разделы «Первая строка» и «Черновик». Оформляется черновик отдельным заходом, скилломboard-groom. - Заголовок короткий и по-русски, тип
bug/task/LLD, ранг разбивкой по пяти слагаемымRANKING.md(сумму и приоритет считает taskctl), цена S/M/L/XL это оценка затрат агента, в ранг она не входит. Каждое слагаемое называется вслух вместе с причиной. Разбивка без причин ничем не отличается от выдуманной, и проверить её потом нечем. - Описания в строке не держать. Там заголовок и ссылка, а разбор в файле
задачи или в
docs/lld/. - Задача, которая замыкает фичу из нескольких строк, несёт в DoD вход для новичка: одна страница первого запуска шагами в README. Признак простой: после неё у пользователя появляется новое поведение, собранное из нескольких задач. Дока каждой правки остаётся в её задаче, а отдельной строки под доку не заводят. Задаче без фичи пункт не нужен.
Что идёт строкой сразу
- Находка по ходу другой задачи, когда симптом виден вживую, предмет очевиден, а конец работы это «починить это место»: баг вёрстки, найденный при тестировании чужой фичи. Отдельный грумминг ей не нужен, ранг ставится вслух с причиной.
- Очевидная нехватка, где предмет назван («нет кнопки X»), а конец работы это «добавить кнопку X».
- Баг на проде, с которым пришёл пользователь и есть воспроизведение: его не откладывать ради черновика.
Что уходит в черновик
- Неочевидная находка, где предмет сомнителен или конец работы неясен:
taskctl draftи грумминг в общем порядке. - Идея, которая тянет на несколько задач: оформляется первая, остальные заводятся отдельными строками с зависимостями, в черновике лежит только сама идея.
- Мысль, на разбор которой не хочется останавливаться: черновик для того и есть, записать за минуту и вернуться потом.
Граница «очевидное или нет» держится суждением, а не перечислением случаев. Если по сессии видно, что ворота пройдут, можно заводить строку, при сомнении надёжнее черновик, его разобрать можно, а строку с рангом наугад переделывать дороже.
Взять в работу
taskctl show <ID>: строка, метаданные, файл задачи, зависимости.agentctl pick <ID>: вердикт называет модель, определение агента и ярус. Этап разработки ставит хук спавна субагента по определениюexec-*, после ревью с замечаниями он же пишет «доработку», команды записи у диспетчера нет. Смена статуса уносит пакет этапов из~/.devkit/runsв раздел «Ход работы» файла задачи. Вердикт со словами про грумминг или разбивку значит, что исполнять рано. Сильная модель зовётся снять неопределённость либо разрезать задачу, и исполнительский вердикт берётся повторным pick по обновлённой строке. Строкаviaне совпала с активным харнесом. Тогда задача уходит не спавном субагента, а командойagentctl run <ID> --workdir <дерево>(tools/agentctl/README.md, раздел «Делегирование (команда run)»). Срок жизни исполнителя меряется двумя мерами, и вторая на диспетчере. Одиночный субагент меряет себя временем сам, командойtaskctl elapsed <ID>на каждом переходе плана. Диспетчер меряет размером контекста субагента, которого держит репликами в чате:subagent_tokensиз уведомления против порогаagentctl rotate. Порог пройден, значит диспетчер просит хвост короткой репликой, а следующее задание отдаёт свежему субагенту, поднятому повторнымagentctl pick <ID>. Формат хвоста в реплике не повторяется, он лежит в определении исполнителя.- Файл задачи заведён вместе со строкой самим
taskctl add. Файл строкам, заведённым до этого правила, добиваетtaskctl file <ID>. Без файла изменяющие команды (move,dep add,set) отказывают и называют её в подсказке. taskctl move <ID> in-progress.- Коммит доски (
docs/TASKS.mdиdocs/tasks/) с пушем сразу, флагами-mи--pushсамой команды taskctl. - Дальше код: ветка, ревью и выкат идут по
board-ship.
Цепочка по просьбе человека
Порядок нескольким строкам человек называет в чате словами: «после DK-A сделай
DK-B и DK-C, потом DK-D». Синтаксис уровней держит не он, а ты. Просьба
разбирается на уровни и ложится на доску одной командой taskctl chain.
Разбор команды в tools/taskctl/README.md, раздел «Цепочка уровнями».
-
Разобрать просьбу на уровни. Уровень это строки, которые вправе идти разом. Следующий уровень ждёт их все. Перечисление через запятую, «заодно» и «вместе с» дают один уровень, «потом» и «после» начинают новый.
-
Прочитать файл каждой строки и сверить предметы соседей по уровню. Этот шаг идёт раньше плана, пропускать его нельзя. Заголовок строки про файлы не говорит ничего, а предмет назван в постановке. Куда ляжет правка, видно грепом по дереву. Две задачи на одном файле разом не идут. Они встретятся конфликтом в слиянии. Уровень с такой парой режется надвое, и вторая встаёт после первой.
-
Сверить строки с готовностью к исполнению. Взвод не берёт строку с открытой развилкой, с неопределённостью 4-5, ценой XL или из состава незакрытой цели. Отказ на любом уровне останавливает всю цепочку без единой записи на доску. Такая строка уходит из цепочки, а человеку называется, чего ей не хватает: грумминга, нарезки или ответа на развилку.
-
Напечатать план до записи:
taskctl chain --after DK-A "DK-B DK-C" "DK-D" --dry-runВывод идёт человеку вместе с доводом, почему уровни легли так. В самом выводе довода нет, там рёбра и взвод.
-
Записать доску той же командой без
--dry-run, с-mи--push.
Одна строка без порядка это taskctl arm, одно ребро taskctl dep add.
Цепочка начинается там, где уровней два.
Конвейер задачи с экрана
Кнопка «Выполнить» на экране дашборда поднимает задачу оболочкой
task-run.py в tmux-сессии task-<ID>. Оболочка ведёт работу одной живой
интерактивной сессией. Первый заказ приходит клиенту первым аргументом,
следующие подаются в тот же процесс клавиатурой окна, а конец каждого прохода
оболочка узнаёт отметкой хука Stop (hooks/turn-mark.py, журнал
~/.devkit/turns.log). Между проходами процесс не выходит. Поэтому долгая
команда и фоновый субагент доживают до конца, а уведомление о них доходит до
головы.
Что из этого следует сессии, которая в таком окне работает:
-
Реплика человека приходит в тот же разговор, и отвечать на неё надо там же. Своего заказа оболочка поверх начатого хода не шлёт.
-
Кончился ход, а строка не закрыта, значит придёт следующий заказ «Продолжай выполнение ». Проходов шесть, три коротких прохода подряд без движения строки оболочка считает воронкой и встаёт.
-
Проход кончает отметка конца с парным «начат». Отметку без пары (её даёт вторая реплика на жалобу стоп-хука) оболочка называет в журнале строкой «непарная отметка конца хода» и ждёт дальше. После честного ожидания счёт холостых начинается заново (DK-966).
-
Трёх ожиданий воронка не считает. Строка в check с видом приёмки user останавливает конвейер по-хорошему, и то же делает mixed с отметкой smoke: агентская половина сценария прогнана, остаток за человеком. Mixed без отметки оболочка сдаёт проверяющему и выходит молча, человека тут не ждут. Проход, кончившийся при живой фоновой работе сессии, не получает заказа. Живой работой тут считаются и субагенты, и запущенные тобой фоновые команды. Следующий ход поднимает их конец, оболочка тут молчит.
-
Ход с живым ожиданием не холостой, и отмечает его сама сессия. Ждёшь машинного события снаружи? До конца хода зови
agentctl waitс условием и кончай ход как обычно. Слияние ушло фоном, тогда так:agentctl wait DK-902 слита DK-930 --until 30m --note "слияние идёт фоном"Условия:
слита <ID>(работа задачи в main),закрыта <ID>(строка в архиве),процесс <pid>(конец фоновой команды). Дальшечас <02:00>(срок это сам час,--untilк нему не пишется),чисто <путь>,есть <путь>,нет <путь>и голыйсрок. Условие называется прямо. Путь к файлу, который появится после слияния, и голый срок с проверкой после него это обход. Событие, которое уже пришло, команда отбивает, и работа идёт дальше в том же ходе. Оболочка ждёт за тебя, проход в воронку и в потолок проходов не считает и вернёт заказ по событию либо по сроку. Без отметки такой ход неотличим от головы, вылетевшей на подъёме, и третий подряд снимает окно вместе с работой (DK-893 и DK-510 за одну ночь). Ожидание человека это другое дело, парковка строки ставит его. -
Строка в архиве или в
blockedостанавливает конвейер, и запаркованная задача зовёт человека уведомителем. -
Незнакомый запрос разрешения виден снаружи. Оболочка пишет его в журнал проекта
.devkit/logи зовёт человека. Узнаёт она вопрос двумя журналами, отметкой хода и строкой уведомителя~/.devkit/notify.log. Хук отметки ложится в настройки харнеса не раньшеdevkitctl doctor --fix, и сессия, поднятая до этого, не пишет отметок вовсе. Права машинного контура раскладывает тот же доктор, дописывать их в обход не надо.
Запасной вход у конвейера печатный, череда проходов claude -p. Он берётся,
когда tmux на машине нет либо оболочку позвали с флагом --headless; там
фоновый ход отбивает рубеж синхронности, и долгие дела в такой сессии
гоняются синхронно.
Файл задачи
docs/tasks/<ID>.md, имя по чистому ID. Разделы, их порядок и то, что в каждый
идёт, описаны в TASKFORM.md рядом с RANKING.md, раздел «Файл задачи» с
таблицами «Разделы автора» и «Контрактные разделы»; часть страницы про
черновик исполнителю не нужна. Здесь форма не пересказывается. Болванку с заголовками кладёт сам taskctl add, порядок
разделов сверяет taskctl lint.
Из формы стоит помнить три вещи, на которых спотыкаются чаще всего. Метаданные
(тип, приоритет, ранг, статус) живут в доске и в файле не дублируются, в файле
остаются только причины по слагаемым ранга. Раздел «Выкат» пишет shipctl merge, руками его не править и файл не переименовывать вслед за правкой ID. По
этой записи считаются очередь выката, состав поезда и откат. LLD-задача
заводится файлом при заведении строки, как любая другая. Дизайн остаётся в
docs/lld/, а файл на него ссылается.
Эталоны прозы берутся до первой фразы файла:
python3 ~/projects/devkit/kit/skills/prose/prose.py sample --genre task --count 4
Чувствительное (IP, доступы, инфраструктура) ни в доску, ни в файл задачи: оно
остаётся в гитигнорнутом local-docs, а в коммитируемом тексте пишется роль
машины. Рубеж держит check-sensitive, но отказ хука это последняя линия, а не
способ вспомнить правило.
Связь с другой задачей, названная в файле входом, обязана стоять на доске
маркером: taskctl dep add <свой ID> <ID предпосылки>, а не оставаться фразой
в тексте. Фразы диспетчер не читает, задача уходит в работу раньше предпосылки,
и расхождение ловит devkitctl doctor (DK-168).
Статусы
Backlog, In progress, Check, Blocked.
Blockedэто обстоятельство снаружи доски (смежник, доступ, сломано не у нас) и только у начатой задачи. Ожидание своей задачи этоtaskctl dep addс маркером[после <ID>].- Вопрос человеку идёт в ленту чата. До вопроса развилку обходит субагент
свежего контекста (
interview, «Обход до первого вопроса»). Он приносит рекомендацию с доводом и строку «источник», без обхода парковки нет. Маршрут идёт по критерию «Кто спрашивает». Внутренность переводится себе (decide <ID> «имя» --leave --by агент), остальное уходит человеку. Развилка заводится раньше, чем задана (decide <ID> --ask --hint, без рекомендации отказ, равный счёт это--tie), а форму вопроса печатаетdecide <ID> --chat, и делается напечатанное. Из сессии панели та же команда паркует строку причиной «вопрос: ...» и зовёт уведомление. Ответ разбираетdecide <ID> --answer, ту же парковку ставитtaskctl move <ID> blocked --reason, а брошенный ход паркует тикdevkitctl watch. Ответ будит строку тиком, будящий возврат коммитит и пушит доску сам. Висящих вопросов на цель не больше двух. Checkэто контроль человеком: закрывает задачу пользователь по приложенному сценарию, а задачу с агентским сценарием агент проверяет и закрывает сам.- В архив уезжает только прошедшее проверку. Не прошедшее возвращается в In
progress одним из двух исходов, исход выбирает проверявший (
board-ship, проверка на проде).
Сценарий проверки
Перевод в Check возможен, только когда сценарий готов: шаги плюс ожидаемый итог, в файле задачи (или в LLD, если проверка описана там).
- Для бага первый шаг воспроизводит исходный баг, а не показывает, что код поменялся; «как раньше и не сломалось» идёт дополнением, а не вместо.
- Сценарий пишется по виду приёмки, назначенному при заведении строки: критерии
вида и обходы против каждого барьера лежат в
ACCEPTANCE.mdрядом сRANKING.md. Вид агентский, пока не назван барьер из шести (глаза, доступ, необратимость, секрет, согласие, событие), и сомнение барьером не считается. Не агентский вид держит раздел «Приёмка» файла задачи с перебором обходов: строка на обход, каждая с исходом и причиной, и строк ровно столько, сколько обходов у названного барьера (это считают воротаmove check). - Агентская часть самодостаточна: шаг считается агентским, когда он прогоняется после выката (или после слияния в main у задачи без выката) и что-то доказывает про выкаченное. Тесты ветки сюда не входят, они зелёные до слияния.
- Команда зовётся тем способом, каким задокументирована, окружение задаётся
явно (временный
HOME, синтетическая доска вместо живой), ожидание проверяется командой, а не фразой «видно в выводе». - Сценарий обкатывается до перевода в Check. Команды шагов кладут в блок с
языком
sh, иtaskctl rehearse <ID>гоняет их в свежем дереве и с временнымHOME: вывод ложится в «Проверку», зелёный прогон ставит там отметку с коммитом. Без свежей отметкиmove checkотказывает и называет команду, а где шаги без выката не гоняются, ворот гасит пометка «- Исключение: обкатка (причина)» в файле задачи. - Сценарий прогоняет не автор правки. Прогон отмечается
agentctl stage <ID> проверка --by <модель>, и строка с прогонявшим уезжает в «Ход работы» файла задачи. - Прогнал агентскую часть сам, а разработку вёл не ты, значит ставь и отметку
выката,
shipctl smoke <ID>. Она снимает очередь выката. Слова «строку не закрывай» у вида mixed сказаны про закрытие, отметку они не трогают. Прогонять сценарий своей правки нельзя, ворота закрытия сверяют имена. - Строку mixed без отметки smoke ждёт проверяющий. Выкат без человека в окне
зовёт его сам, а тик
devkitctl watchстрахует командойshipctl check-run. Модель зовётagentctl check <ID>, код общий с автономным подъёмом.
Вид пересматривается по ходу работы, когда первый шаг, который ранее казался
машинным, оказался ждавшим человека, или наоборот. След пересмотра один, раздел
«Приёмка»: строка с датой, направлением и причиной. Значение в строке доски
правит taskctl set --accept, руками заголовок не трогают, а у барьера
«согласие» повышения вида не бывает: обхода нет по определению.
Закрытие
Агентский сценарий после выката прогоняется тем же порядком, чужими руками, и
реальный вывод вкладывается в файл задачи. Закрывает задачу taskctl close с
датой и коммитами. Он же сверяет прогонявшего с исполнителем последнего
этапа работы над кодом, совпадение имён это отказ с моделью в тексте.
Пользовательский ждёт слова пользователя. Провал сценария это не закрытие, а
разбор по board-ship. Сломанный прод чинится сразу, а принятая работа с
замечаниями возвращается в In progress обычным taskctl move.
Найденные при проверке баги фиксируются в файле задачи строкой с сутью и исходом; баг, к задаче не относящийся, заводится своей строкой в Backlog.
Что тут легко забыть
- Отчёт цитирует статус доски: «готово» и «закрыта» говорятся только про Check и про закрытие, до них это «код в ветке», «ждёт ревью», «слито».
- Что делать дальше, печатает сама команда перехода (
taskctl move,close,shipctl statusиmerge), пересказывать конвейер по памяти не надо. - Коммит, тронувший доску или файлы задач, пушится сразу и без просьбы.
- ID задачи стоит в subject каждого коммита задачи.
- После ручных правок доски (если без них не обошлось) гонять
taskctl lint. - Доменные случаи, которых в метаданных нет (3D-графика, дизайн интерфейсов),
закрываются строками «Модель: ...» и «Эффорт: ...» в файле задачи. Pick читает
их и ставит выше маппинга по каждой оси отдельно. В строке модели пишется
ярус (
mini,base,pro,max), не имя модели инструмента.
