diff --git a/.tasks/2026-08-24-01062-mappa-task-work.md b/.tasks/2026-08-24-01062-mappa-task-work.md index f5c7dde..b22f4c6 100644 --- a/.tasks/2026-08-24-01062-mappa-task-work.md +++ b/.tasks/2026-08-24-01062-mappa-task-work.md @@ -17,4 +17,15 @@ Rewrite using-tasks + task-format + task-loop + priority-due → **mappa-task-wo ## Completed steps +- [x] skills/mappa-task-work/SKILL.md v1.0.0 — центральный цикл: ориентация → выбор работы (claim, priority/due) → исполнение → сдача (close + review-umbrella) + пауза/переключение +- [x] Loop-mode ВНУТРИ (вариант A, отдельный скил не создаётся): «поработай очередь»/«work the queue» → цикл claim→work→close→claim; пустая очередь = стоп, без демона/CronCreate; session_break gate; consult gate (human-only/strict-human → STOP перед close/commit) +- [x] Priority/Due-раздел: приоритет = территория человека, агент ставит только при создании, дефолт P1, просрочка → admin_overdue_scan notify однократно, без авто-бампа +- [x] Формат таски (из task-format): mappa task_create схема (priority/due при создании) + legacy STATUS.md блок (переходный, Weight/Notify обязательны) +- [x] Поглощены: using-tasks (борд/лиз/close/notify/рефы [[task:N]]), task-format (формат), task-loop (loop-mode), task-priority-due (раздел). Старые имена — триггер-синонимы в description +- [x] lint clean (65 skills, 0 violations); build.sh → dist/mappa-task-work.skill (старые .skill удалены); install.sh → dual; старые удалены из живых диров +- [x] GREEN micro-test: свежий pi -p на «поработай очередь» → активация mappa-task-work, loop-mode, стоп-гейты, пустая очередь = стоп без поллинга + ## Notes + +- RED-базис: контент унаследован из трёх скилов (все прошли ревью/smoke); дельта = слияние + цикл-фрейминг + priority/due раздел. Полный behavioral smoke (вкл. loop-mode, session-break, empty-stop) — за #1065. +- Убраны: task-loop ссылки на projects-meta claim (primary — mappa task_claim_next; file channel — переходный, описан в секции legacy). diff --git a/dist/mappa-task-work.skill b/dist/mappa-task-work.skill new file mode 100644 index 0000000..c3c5b6e Binary files /dev/null and b/dist/mappa-task-work.skill differ diff --git a/dist/task-format.skill b/dist/task-format.skill deleted file mode 100644 index c0a732f..0000000 Binary files a/dist/task-format.skill and /dev/null differ diff --git a/dist/task-loop.skill b/dist/task-loop.skill deleted file mode 100644 index ab5e2af..0000000 Binary files a/dist/task-loop.skill and /dev/null differ diff --git a/dist/using-tasks.skill b/dist/using-tasks.skill deleted file mode 100644 index 54d55f3..0000000 Binary files a/dist/using-tasks.skill and /dev/null differ diff --git a/skills/mappa-task-work/SKILL.md b/skills/mappa-task-work/SKILL.md new file mode 100644 index 0000000..174574a --- /dev/null +++ b/skills/mappa-task-work/SKILL.md @@ -0,0 +1,296 @@ +--- +name: mappa-task-work +author: ours +version: 1.0.0 +description: > + Центральный цикл работы с тасками в Mappa: ориентация → выбор работы + (claim, priority/due) → исполнение → сдача (close + review-umbrella) + + loop-mode «поработай очередь». Борд = сущности mappa (решения 14/15/19/20); + мутации под лизом. Поглощает using-tasks + task-format + task-loop + (loop-mode ВНУТРИ) + priority-due-раздел (старые имена — триггер-синонимы). + Триггеры: «что на досках», «возьми таску», «какой статус», «update status», + «pause», «switch to X», «где мы остановились», «work the queue», «поработай + очередь», «прогони доску». Приоритет = территория человека: агенты ставят + P0-P2/дедлайн только при создании, дефолт P1; просрочка → notify, без + авто-бампа. НЕ про делегирование (→ mappa-delegation), НЕ про доску-обзор + (→ ops/using-system-snapshot). +--- + +# mappa-task-work + +Центральный цикл работы с задачами: **ориентация → выбор работы → исполнение → +сдача**. Борд — сущности mappa (`type=task`, `t:N`): чтение — карв-аут лиза, +**любая мутация — под лизом проекта** (решение 19). Скилл = цикл, не тул: +одна механика на выбор/исполнение/сдачу, плюс **loop-mode** («поработай +очередь») внутри — отдельный скил не создаётся. + +> **Переходное (file channel).** Пока поллер/кэш читают файловые борды +> (`.tasks/STATUS.md`), legacy-канал живёт: блоки в файле обязаны строгому +> формату (см. «Формат таски» ниже), мутации — через `mcp__projects-meta__tasks_*` +> (Gitea-коммиты). Новые таски — через `mcp__mappa__task_create`. Не смешивай. + +## Когда использовать + +- «что на досках», «возьми таску», «какой статус», «update status», «pause», «switch to X», «где мы остановились». +- «work the queue», «поработай очередь», «прогони доску» → **loop-mode**. +- Смена задачи / пауза / конец сессии — держать борд консистентным. + +**НЕ для:** делегирования другому агенту/проекту (→ `mappa-delegation`), +промоушена (→ `mappa-brainstorm-promote`), инфра-диагностики (→ `using-vds-ops`), +кросс-проектного обзора (→ `using-system-snapshot`). + +## MCP-поверхность + +| Операция | Тул | Примечание | +|---|---|---| +| Взять следующую ready-таску | `mcp__mappa__task_claim_next(project, owner)` | атомарно: лиз + таска; → `{ok, token, task}` | +| Продлить лиз | `mcp__mappa__task_heartbeat(project, claim_token)` | долгие таски | +| Создать таску | `mcp__mappa__task_create(project, slug, title?, description?, status?, priority?, due?, claim_token)` | под лизом; per-type номер (решение 20) | +| Закрыть таску | `mcp__mappa__task_close(project, id, claim_token)` | под лизом | +| Прочитать таску | `mcp__mappa__entity_get(id)` | id internal из search/claim | +| Список борда | `mcp__mappa__entity_search(q, type='task', project=<имя>, limit)` | все статусы | +| Дерево parent_of | `mcp__mappa__graph_tree(root, depth?, fields?, limit?)` | зонтики/иерархия | +| Связанные сущности | `mcp__mappa__graph_neighbors/backlinks(id)` | рефы к таске | +| Просрочка | `mcp__mappa__admin_overdue_scan(project?)` | P2-джоба: notify в инбокс, без мутаций | +| Уведомление при закрытии | `mcp__mappa__inbox_send(project=, from=<своя>, subject, body)` | письмо комиссионеру | + +**Лиз = лок на запись (решение 19).** Одна строка leases на проект: если другой +агент держит лиз — `task_claim_next` вернёт **422 busy**. Это серверный аналог +старого `.tasks/.lock`: проверять «а не поллер ли работает» руками не нужно — +сам claim скажет. Чтения лиза не требуют. + +**Рефы и id (#1037/#1028).** Таски наружу несут `ref: "t:N"` полным именем +первым полем (`task:N`, конвенция #1028), `num` следом, глобальный `id` — +internal (последним, для addressing в тулах). Ссылайся на таску +`[[task:N]]`/`task:N` в прозе (слаг/имя первым, реф как якорь: «таска +`mappa-task-work` (task:1062)»), никогда `#<глобальный id>`. + +## Статусы (эмодзи для презентации) + +| Эмодзи | Статус | Значение | +|---|---|---| +| ⚪ | `ready` | не начата, полностью определена | +| 🔴 | `active` | в работе (обычно одна) | +| 🟡 | `paused` | в процессе, возобновляема | +| 🔵 | `blocked` | ждёт внешнего входа | +| 🟢 | `done` | закрыта | + +Не путай: 🟢 — *done*, не «готово». Ready — ⚪. + +--- + +## Цикл + +### Фаза 0 — Ориентация + +1. **Инбокс-свип** — `mcp__mappa__inbox_monitor(project=<имя>)`: непрочитанные + письма могут менять план. Обработай каждое по `mappa-messaging`. +2. **Борд** — `entity_search(q, type='task', project=<имя>, limit=50)`: отсортируй + по статусу (🔴 → 🟡 → ⚪), по одной строке на таску, цитируй slug. +3. Если user назвал таску — `entity_get(id)` по её рефу/номеру. +4. Подтверди одним предложением: «Мы в середине X, следующий шаг — Y». +5. Спроси, верен ли план, перед действиями. + +### Фаза 1 — Выбор работы (claim, priority/due) + +1. `mcp__mappa__task_claim_next(project, owner)` — атомарно: лиз + следующая + ready-таска. `owner` = `::`. + Порядок выдачи: **P0-пул первый, внутри по дедлайну (просроченные первыми), + потом P1, потом P2**; отсутствующий priority = P1 (task-priority-due). +2. **Локально-первая рекомендация** — борд cwd первым; кросс-проект — футонота + (`Cross-project: N 🔴 active — см. tasks_aggregate`) только если N>0 и в cwd + нет активной 🔴. Кросс-проектные ургенты — информация, не драйвер «что делать здесь». +3. **Priority/Due — территория человека (раздел task-priority-due):** + - Агент ставит `priority`/`due` **только при создании** таски (явные параметры + или строки `**Priority:** P0|P1|P2` / `**Due:** yyyy-mm-dd` в description). + Отсутствует → дефолт P1, без дедлайна. + - **После создания агент не меняет** приоритет/дедлайн — прецедент человека + структурный (update агентами отклоняется сервером). Обнаружил, что таска + на самом деле P0 → паркуй вопрос человеку, не бампай сам. + - **Просрочка:** due < today при ready/active → `admin_overdue_scan` уведомляет + в инбокс **однократно, без мутаций** — никакого авто-бампа/авто-смены приоритета. + +### Фаза 2 — Исполнение + +- **Одна активная таска** 🔴 на проект. Не параллель. +- Читай description + per-task файл (`.md`, где есть) до старта. +- Долгие таски: `task_heartbeat(project, claim_token)` (лиз по TTL, дефолт 600s). +- **`session_break` gate** (из task-loop): если в description таски есть маркер + `session_break` — после close НЕ клейми следующую: печатай + `🔚 SESSION BOUNDARY …` и останавливайся (домен-свитч / milestone / тяжёлая инфра). + +### Фаза 3 — Сдача (close + review-umbrella) + +1. **Pre-close coverage check.** Собери acceptance criteria из description. Для + каждого — evidence: тест в диффе, артефакт, ссылка на дизайн. Нет evidence на + критерий → спроси user'а «закрывать или подождать coverage'а». +2. Resolve/drop открытые вопросы. +3. `task_close(project, id, claim_token)` → статус `done`. +4. **Notify-письмо (кросс-проектные таски).** Если таска пришла из другого + проекта (в description/meta есть `from:`/`notify:`) — `inbox_send` + комиссионеру: `project=`, `subject="[event: closed] "`, + body = итог (сделано, acceptance, ссылки). Живая сессия пишет сама. + Таска 🟢 ≠ комиссионер узнал. +5. **Review-umbrella для impl-тасок** (канон `mappa-delegation`): если таска + имплементационная и закрыта — парная `-review` уже должна быть + создана при постановке (status=blocked, blocker=impl#); закрытие impl + разблокирует ревью. Не создавай review сам, если её не было — это работа + постановщика; упомяни в close-note. +6. Дополни summary-строку в handoff/вики при наличии. + +### Пауза / переключение / конец сессии + +1. Текущая 🔴 → `task_close` если завершена (см. Фазу 3), иначе пометь + `status=paused` (owner остаётся; «where stopped» — в description или handoff). +2. **Инбокс-свип** на границе тасок (`inbox_monitor`). +3. Возьми следующую: `task_claim_next` (лиз + таска). Прежняя остаётся 🟡. +4. Подтверди ориентацию перед стартом. + +> **Never lose Where I stopped** — критичное поле: в description (последний +> абзац) или в handoff-сущности (`mappa-closing-ritual`). Перед концом сессии +> обязательно запиши handoff. + +--- + +## Loop-mode — «поработай очередь» + +Один триггер-сёрфейс: «поработай очередь» / «work the queue» / «прогони доску» +→ этот режим. Work the board **в этой сессии**: claim → работа → close → claim, +пока очередь не пуста или user не сказал стоп. **Интерактивный цикл, не демон.** + +``` +claim_next(project, owner) → пусто? → STOP «борд пуст» (не поллить) + ↓ таска +работа в этой сессии (read description + .md) + ↓ +завершена? нет → park: blocked (внешний) | paused (возобновляемо) → claim_next + ↓ да +consult_policy (из claim): human-only/strict-human → STOP перед close/commit, спросить user + ↓ auto +pre-close coverage check → task_close + ↓ +session_break на таске? → да: печатай 🔚 SESSION BOUNDARY, STOP + ↓ нет +claim_next … +``` + +- **Пустая очередь — естественный стоп, не wait-loop.** Нет `CronCreate`, нет + спавна субагента, нет коротких поллеров — это работа отдельного поллера. + Длинный watch («работай пока не скажу стоп» + явно «продолжай проверять») — + только один `ScheduleWakeup` с интервалом ≥1200s, никогда `CronCreate`. +- **Не завершаемая таска:** внешний блокер → `status=blocked` + blocker + (конкретный факт + что нужно); прервал ты (бюджет/стоп) → `status=paused` + + where_stopped. Одна упавшая таска не останавливает цикл — паркуй и дальше. +- **Heartbeat:** claim живёт ~10 мин — если таска дольше ~8 мин, `task_heartbeat` + периодически. +- **Consult-гейт:** `auto` → автопилот до close; `human-only`/`strict-human` → + работай, затем **STOP перед close/commit** и спроси user. Push никогда не + автоматический (project-discipline Rule 4: commit freely, push по явному + гранту). + +--- + +## Формат таски (из task-format) + +### Primary: mappa task_create + +Создание задач — **через тул, не руками** (решение 20): сначала лиз +(`task_claim_next`) → `task_create`. Номер `t:N` назначает сервер — не выдумывай. + +``` +mcp__mappa__task_create( + project: <имя проекта>, // обязателен + slug: , // обязателен, латиница + title: <одна строка>, // опционально + description: , // тело; [[refs]] → рёбра (решение 4) + status: ready | active | paused | blocked | done, // по умолчанию ready + priority: P0 | P1 | P2, // только при создании; отсутствует → P1 + due: yyyy-mm-dd, // только при создании; отсутствует = нет + claim_token: <токен лиза проекта> // мутация под лизом (решение 19) +) +``` + +Slug-правила: короткий, lowercase, kebab-case, латиница. Description — markdown, +`[[refs]]` на связанное. Priority/Due — при создании ИЛИ строками в description +(`**Priority:** P0|P1|P2`, `**Due:** yyyy-mm-dd`; явные параметры переопределяют). + +### Legacy: блок .tasks/STATUS.md (интерм до флипа поллера) + +Пока файловый поллер не переключён на mappa (#984), блоки в `.tasks/STATUS.md` +обязаны строгому формату — иначе поллер молча пропускает: + +```markdown +## ⚪ [#1234 my-task-slug] — One-line description. + +**Status:** ready +**Created:** 2026-08-23 +**Where I stopped:** (not started) +**Next action:** First concrete step the claiming agent runs. +**Branch:** master +**Weight:** needs-claude +**Notify:** OpeItcLoc03/workshop + + +--- +``` + +Три load-bearing правила: **(1)** шапка точно `## [# ] — ` +(h2, один emoji, `[# ]`, разделитель ` — `); **(2)** поля — строки +`**Label:** value`, буллеты игнорируются; **(3)** `**Created:**` обязателен. + +Поля, которые разбирает поллер: `**Weight:**` (cheap-ok | needs-claude | +needs-human — **обязателен** для авто-взятия), `**Notify:**` (/), +`**Requirements:**`, `**Runtime allowed:**`, `**Consult policy:**`, `**Blocker:**` +(только на 🔵), `**Priority:**`/`**Due:**` (как выше). `**Owner:**/`**Claim +token:**/`**Claim expires at:**` — claim-штамп, пишет и чистит поллер; залипший +штамп на ⚪ блокирует поллер. + +**Weight — поле, решающее взятие:** без `**Weight:**` поллер паркует в 🔵 +(`no backend for weight_tier: unknown`). Обычный код → `needs-claude`; +критикал-инфра (поллер, MCP-серверы, деплой, CI, git-хуки) → `needs-human`. + +--- + +## Failure modes + +- **422 busy** на `task_claim_next` → лиз держит другой агент; не параллель, + retry позже или спроси user. +- **task_close на незавершённую** → никогда. Park (blocked/paused). +- **claim истёк (zombie)** → не бросай claimed-таску: park/close по факту. +- **notify не указан (legacy)** → без него boss не узнает о завершении. +- **weight не указан (legacy)** → поллер паркует (no backend for weight_tier). +- **update Priority/Due после создания** → сервер отклоняет; паркуй вопрос + человеку, не бампай сам. + +## What NOT to do + +- **Не выдумывай номера** — `t:N` назначает сервер (решение 20). +- **Лиз-дисциплина:** мутации — только под лизом; 422 busy = кто-то другой пишет. +- **Одна активная таска** — только одна 🔴 на проект. +- **Never close без coverage check** — evidence на каждый acceptance criterion. +- **Не закрывай незавершённое** — park, не close; не оставляй claimed-таску. +- **Не бампай priority/due после создания** — территория человека. +- **Не «решай» задачи письмом/в чате** — борд — единственный источник правды + (канон mappa-messaging: «если это не на доске — это не задача»). +- **Не полли пустую очередь** — пусто = стоп и отчёт; без демона/CronCreate. +- **Не автопилоть human-only/strict-human** через close/commit; push — только по гранту. +- **Не батчи tasks_create в один репо** — sha-lock конфликты; сериализуй. + +## Red flags — STOP + +- «Поставлю таймер проверять новые таски» → нет. Стоп на пустой очереди. +- «Спавну фонового воркера гнать доску» → нет. Один цикл, эта сессия. +- «Таска не готова, но закрою и отмечу» → никогда. Park. +- «Приоритет у таски явно P0, сам бампну» → нет. Вопрос человеку. + +--- + +## Reference + +- Делегирование (постановка на агентов): `mappa-delegation`. +- Почта (covering-письма, notify): `mappa-messaging`. +- Знание (wiki-ингест после закрытия): `mappa-knowledge`. +- Финиш сессии (handoff write): `mappa-closing-ritual`. +- Старт сессии (pull/handoff/inbox/snapshot): `mappa-session-orient`. +- Промоушен (review-umbrella): `mappa-brainstorm-promote`. +- Кросс-проектный обзор: `using-system-snapshot` (liveness) / `mcp__projects-meta__tasks_aggregate`. diff --git a/skills/task-format/SKILL.md b/skills/task-format/SKILL.md deleted file mode 100644 index 33b034c..0000000 --- a/skills/task-format/SKILL.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -name: task-format -author: ours -version: 0.4.0 -description: > - Use when creating or editing a task so it is actually claimable and routed — - not silently skipped. Primary channel: **mappa** — create via - `mcp__mappa__task_create` (схема ниже), не руками. Legacy: пока файловый - поллер (agents-task-runner) не переключён на mappa (#984), блоки в - `.tasks/STATUS.md` обязаны совпадать со строгим форматом (шапка, поля - Weight/Notify), иначе поллер молча пропускает. Triggers: «оформить таску для - поллера», «формат таски», «task block format», «make a task the poller will - pick up», «add Weight/Notify», poller / agent-runner not claiming a task. ---- - -# task-format - -Канон создания задачи — **через тул**, не рукописным блоком. Поллер (автономный -раннер) разбирает задачи строгими правилами; формат задаёт, какая таска будет -взята, отмаршрутизирована и зарепорчена, а какая молча пропущена. - -> Создаёшь задачу для **другого** проекта/агента? См. `delegate-task` — он ведёт -> через тул + письмо. Работа с бордом (claim/close/status) — `using-tasks`. - -## Primary: mappa task.create - -Создание задач в mappa (решение 14/15: мета в сервисе) — только через -`mcp__mappa__task_create`, никогда руками вставляй блоки. Тул сам назначает -per-type номер (`t:N`, решение 20) и пишет сущность. - -``` -mcp__mappa__task_create( - project: <имя проекта>, // обязателен - slug: , // обязателен, латиница - title: <одна строка>, // опционально - description: , // тело; [[refs]] → рёбра (решение 4) - status: ready | active | paused | blocked | done, // по умолчанию ready - priority: P0 | P1 | P2, // важность; отсутствует → P1 (task-priority-due) - due: yyyy-mm-dd, // дедлайн; отсутствует = нет (task-priority-due) - claim_token: <токен лиза проекта> // мутация под лизом (решение 19) -) - -**Priority/Due (task-priority-due, #1045):** задаются **только при создании** -— либо явными параметрами `priority`/`due`, либо строками в description -(`**Priority:** P0|P1|P2`, `**Due:** yyyy-mm-dd`; явные параметры переопределяют -парсинг). После создания агент приоритет и дедлайн **не меняет** — прецедент -человека структурный (update агентами отклоняется сервером). Обнаружил, что -таска на самом деле P0 → паркуй вопрос человеку, не бампай сам. -``` - -**Мутация под лизом (решение 19):** `task_create` требует `claim_token` -активного лиза проекта (берётся `mcp__mappa__task_claim_next`). Без лиза — -422 busy. (Карв-аут: чтения и инбокс-доставка лиза не требуют.) - -**Per-type номер (решение 20):** номер — канонический машинный реф `t:N` -(см. ответы — поле `ref`). Глобальный id — internal, только для addressing -(#1037). Ссылки на задачу в тексте — `[[t:N]]`, не `#<глобальный id>`. - -**Slug-правила:** короткий, lowercase, kebab-case, латиница -(`fix-nl-vds-reality-pq-dest`, не `Fix_this_TASK #1`). - -## Status emoji ↔ state - -| Emoji | State | Значение | -|---|---|---| -| ⚪ | `ready` | единственное состояние, которое поллер берёт | -| 🔴 | `active` | взято / в работе | -| 🟡 | `paused` | возобновляемо | -| 🔵 | `blocked` | ждёт (указать почему в description/where_stopped) | -| 🟢 | `done` | закрыто | - -Не путай: 🟢 — это *done*, не «готово». - -## Legacy: блок .tasks/STATUS.md (интерм до #984) - -Пока файловый поллер (agents-task-runner) не переключён на mappa-лиз (#984), -блоки в `.tasks/STATUS.md`, создаваемые руками/миграцией, обязаны совпадать со -строгим форматом — иначе поллер молча пропускает или паркует. **Это -переходный канон; новые задачи создавай через task_create.** - -```markdown -## ⚪ [#1234 my-task-slug] — One-line description. - -**Status:** ready -**Created:** 2026-08-23 -**Where I stopped:** (not started) -**Next action:** First concrete step the claiming agent runs. -**Branch:** master -**Weight:** needs-claude -**Notify:** OpeItcLoc03/workshop - - ---- -``` - -Три load-bearing правила: - -1. **Шапка точно:** `## [# ] — ` — h2, один emoji, - `[# ]` (глобальный номер, без ведущих нулей), разделитель - ` — ` (пробел + em-dash + пробел). Несовпавшая шапка = задача не видна вообще. -2. **Поля — строки `**Label:** value`.** Буллеты и проза игнорируются. -3. **`**Created:** yyyy-mm-dd` обязателен** — пишется один раз при создании. - -Номера legacy-блоков назначает сервер (`tasks_create` из счётчика -`OpeItcLoc03/agenda/task-counter`) — **никогда не выдумывай номер руками**. - -### Поля, которые поллер разбирает - -| Field | Format | Meaning | -|---|---|---| -| `**Weight:**` | `cheap-ok` \| `needs-claude` \| `needs-human` | Тир маршрутизации. **Обязателен** для авто-взятия. | -| `**Notify:**` | `/` | Инбокс-адрес для событий close/park/delivery-failure. | -| `**Requirements:**` | CSV (`needs-db, needs-secrets`) | Capability-гейт: агент должен держать ВСЕ. | -| `**Runtime allowed:**` | CSV (`claude-opus`) | Runtime-whitelist. | -| `**Consult policy:**` | `auto` \| `human-only` \| `strict-human` | Эскалация consult; default `human-only`. | -| `**Blocker:**` | CSV blocker-slug'ов | Только на 🔵; авто-unblock при 🟢 всех. | -| `**Priority:**` | `P0` \| `P1` \| `P2` | Важность (task-priority-due). Отсутствует = `P1`. Влияет на порядок выдачи `claim_next` (P0-пул первый, внутри по дедлайну). **Ставится только при создании** — после агенты не меняют. | -| `**Due:**` | `yyyy-mm-dd` | Дедлайн (task-priority-due). Просроченные (due < today, ready/active) → overdue-scan уведомляет в инбокс однократно. Отсутствует = нет дедлайна. | -| `**Next action:** / **Where I stopped:** / **Branch:**` | free text | Резюмируемость. | - -`**Owner:** / **Claim token:** / **Claim expires at:**` — claim-штамп, пишет и -чистит поллер. Не автори руками; залипший штамп на ⚪ блокирует поллер. - -**Weight — поле, решающее взятие:** без `**Weight:**` поллер берёт задачу, не -находит тир и паркует в 🔵 (`no backend for weight_tier: unknown`). Обычный код -→ `needs-claude`; критикал-инфра (поллер, MCP-серверы, деплой, CI, git-хуки) → -`needs-human` (никогда не авто). - -## Common mistakes - -| Mistake | Fix | -|---|---| -| Рукописный блок вместо `task_create` | Создавай через тул — номер/формат серверные. | -| `### Title` / буллеты вместо полей | `## [#n slug] — desc` + `**Field:** value`. | -| 🟢 для ready | 🟢 — done. Ready — ⚪. | -| Шапка `[slug]` без номера | `[#n slug]` — номер машинный ключ. | -| Выдуманный номер | Номер — только от сервера (task_create). | -| `**Created:**` отсутствует (legacy) | Добавить — обязательное поле. | -| Ссылка `#<глобальный id>` | Ссылайся `[[t:N]]` (решение 20/#1037). | -| Без `**Weight:**` (legacy) | Ставь всегда, или задача паркуется. | -| Агент бампает `**Priority:**`/`**Due:**` после создания | Нельзя — прецедент человека структурный; ставь только при создании, иначе сервер отклоняет. | -| Дефис/двоеточие вместо ` — ` в шапке | Разделитель — пробел + em-dash + пробел. | - -## Verify - -Задача корректна, когда: создана через `task_create` (или legacy-блок: шапка -`## [#n slug] — …`, emoji = `**Status:**`, `**Created:**` есть, поля — -`**Label:**` строки, есть `**Weight:**` и `**Notify:**`); slug kebab-case; -ссылки на неё — `[[t:N]]`. diff --git a/skills/task-loop/SKILL.md b/skills/task-loop/SKILL.md deleted file mode 100644 index ce207a8..0000000 --- a/skills/task-loop/SKILL.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -name: task-loop -author: ours -version: 0.1.0 -description: > - Use when the user asks you to work the task board yourself, in this - session, one task after another — «поработай очередь», «прогони доску», - «бери задачи по очереди», «работай пока не скажу стоп», «work the queue», - «drain the board», «keep working tasks until I say stop». Does NOT apply - to delegating work to another agent/project (→ delegate-task), to one - named task you already know (→ using-tasks), or to configuring the - background poller. ---- - -# task-loop - -Work the board **in this session**: claim the next ready task, do it, close it, claim the next — until the queue is empty or the user says stop. - -**Core principle:** an interactive loop, not a daemon. You stay in the chair. Empty queue → **stop and report**, never spin a wait-timer. No subprocess, no `CronCreate` (that schedules a *separate* session — exactly the daemon you're replacing), no short `ScheduleWakeup` poll — those are the unattended poller's job, not yours here. - -**REQUIRED SUB-SKILL:** `using-tasks` owns the board, the `.tasks/.lock` session lock, the `session_break` gate, and the pre-close coverage check. This skill drives the loop *through* those rules — it does not replace them. -**REQUIRED SUB-SKILL:** `project-discipline` — commit/push gate (Rule 4) and sensitive-artifact handling apply to every task you touch. - -## When to use - -**Activates:** «поработай очередь», «прогони доску», «бери задачи по очереди», «работай пока не скажу стоп», «work the queue», «drain the board», «keep working tasks until I say stop». - -**Does NOT apply:** -- Delegating work to another agent/project → `delegate-task`. -- One specific task you already named → `using-tasks` (switch/resume that task). -- Setting up / debugging the background poller or agent-runner → that is infra, not this loop. - -## The loop - -Run this cycle. One task at a time. - -```dot -digraph task_loop { - rankdir=TB; - claim [shape=box, label="tasks_claim_next\n(current project, confirm=true)"]; - empty [shape=diamond,label="task returned?"]; - stop [shape=box, label="STOP — report board drained"]; - work [shape=box, label="do the work this session"]; - done [shape=diamond,label="completed?"]; - park [shape=box, label="park: blocked (external) | paused (resumable)"]; - gate [shape=diamond,label="consult_policy = human-only/strict-human?"]; - consult [shape=box, label="STOP before close/commit — consult user"]; - close [shape=box, label="pre-close coverage check → tasks_close"]; - brk [shape=diamond,label="session_break marker on closed task?"]; - boundary[shape=box, label="STOP — print SESSION BOUNDARY"]; - - claim -> empty; - empty -> stop [label="no ready tasks"]; - empty -> work [label="yes"]; - work -> done; - done -> park [label="no"]; - done -> gate [label="yes"]; - gate -> consult [label="yes"]; - gate -> close [label="auto"]; - close -> brk; - brk -> boundary [label="yes"]; - brk -> claim [label="no"]; - park -> claim; -} -``` - -1. **Claim** the next ready task with `tasks_claim_next(claimer_identity, filter, confirm=true)`. - - `claimer_identity` = `::` (e.g. `DESKTOP-NSEF0UK:claude-opus:`). - - `filter.project` = **the current project** (qualified `/`) by default. Only widen to other projects when the user explicitly asks ("прогони все доски" / passes a project list). - - The server already excludes `weight: needs-human` and anti-self-review tasks — you will never claim those. -2. **No task returned** → the queue is drained. **STOP** and report (see *Empty queue*). Do not poll. -3. **Do the work this session.** All your tools are available. Read the task description and per-task `.md`. Set the task `active` if it isn't already. -4. **Honor the gate before the irreversible step.** Use the `consult_policy` returned by the claim: - - `auto` → full autopilot through close. - - `human-only` / `strict-human` → do the work, then **STOP before `tasks_close` / commit** and consult the user. Don't barrel through. - - **Push is never automatic** regardless of policy — `project-discipline` Rule 4 (commit freely, push only on an explicit per-session grant). -5. **Close** with the `using-tasks` pre-close coverage check, then `tasks_close(target_project, slug, confirm=true, note=…)`. -6. **session_break gate.** After the close, **before claiming the next task**, honor the `using-tasks` `session_break` check: if the closed task carries the marker → print the `🔚 SESSION BOUNDARY` line and **STOP** (do not claim next). Otherwise → back to step 1. - -## When a task can't be finished - -Never leave a claimed task hanging (its claim expires in 10 min and it returns as a zombie), and never `tasks_close` unfinished work (that lies to the board). - -- **External / unresolvable blocker** discovered mid-task (missing upstream, needs a human decision, scope change) → `tasks_update(slug, status="blocked", blocker="")`. Roll back partial work that would break the build. Then continue the loop (the blocker is isolated; the next claim won't return this task). -- **Interrupted or resumable by you** (you ran out of budget, the user stops you mid-task) → `tasks_update(slug, status="paused", where_stopped=…, next_action=…)`. - -A single failing task does not stop the loop — park it and move to the next. - -## Empty queue & stopping - -The loop ends on the **first** of: -- **Empty queue** — `tasks_claim_next` returns no ready task → stop, report what you closed/parked, and wait for the user. Do **not** `ScheduleWakeup`, `CronCreate`, or sleep-poll for new tasks. -- **Explicit user signal** — «стоп», «хватит», «отбой». Park any in-flight claimed task (paused) before stopping. -- **Budget** — `budget.remaining()` near zero → park the current task (paused) and report. - -**Long-running watch (opt-in only).** If the user explicitly says «работай пока не скажу стоп» *and* wants you to keep checking for newly-arrived tasks, use **`ScheduleWakeup`** — it re-invokes *this* session — with a **long** interval (≥1200 s). **Never `CronCreate`** even here: it starts a *separate* scheduled session, i.e. the daemon this skill exists to avoid. And never a short poll. Default is still stop-on-empty; only arm a wakeup on an explicit standing request. - -## Heartbeat - -A claim lives 10 minutes. If a single task will take longer than ~8 minutes, call `tasks_heartbeat(slug, claim_token)` periodically to keep the claim alive. Short tasks need no heartbeat. (The in-session `.tasks/.lock` is a separate 2-hour lock owned by `using-tasks` session start/end — don't manage it from the loop.) - -## What NOT to do - -- **No daemon, no `CronCreate`, no spawned claude, no subprocess** to "run the queue" — `CronCreate` starts a separate scheduled session; the whole point is you do it in *this* session. -- **No busy-poll on empty** — empty queue is a natural stop, not a wait-loop. A short `ScheduleWakeup` loop burns tokens for nothing. The only exception is the explicit long-watch opt-in above (a single ≥1200 s `ScheduleWakeup`, never `CronCreate`). -- **Don't widen scope silently** — default to the current project; claim other boards only when the user asks. -- **Don't `tasks_close` unfinished work** and **don't leave a task claimed** when blocked — park it (blocked/paused). -- **Don't skip the `session_break` gate** between tasks — a milestone/domain-switch marker means stop, even if more tasks are ready. -- **Don't autopilot through a `human-only`/`strict-human` task's close/commit**, and **never auto-push** — consult first. -- **Don't blind-retry** a task that failed for an external reason — diagnose once, record the blocker, move on. - -## Red flags — STOP - -- "I'll set a timer to check for new tasks" → no. Stop on empty; report. -- "I'll spawn a background worker to drain faster" → no. One task at a time, this session. -- "User said work-until-stop, I'll `CronCreate` a recurring run" → no. `CronCreate` is a separate scheduled session = the daemon. Long-watch uses a single long `ScheduleWakeup` on *this* session. -- "It's sensitive but consult_policy says auto, I'll just commit" → push still needs a grant; sensitive close still respects the gate. -- "The task isn't done but I'll close it and note it" → never close unfinished. Park it. diff --git a/skills/using-tasks/README.md b/skills/using-tasks/README.md deleted file mode 100644 index 95d095c..0000000 --- a/skills/using-tasks/README.md +++ /dev/null @@ -1,169 +0,0 @@ -# using-tasks - -Runtime policy for keeping compressed working context across parallel tasks -in a monorepo. The agent reads and updates `.tasks/` so every session starts -oriented and every switch costs seconds, not minutes. - -`using-tasks` governs the task board. **Канал — mappa** (решение 14/15): борд = -сущности `type=task` в сервисе (см. SKILL.md v2.0.0). Файловый `.tasks/` — легаси; -`setup-tasks` умер. - -> Renamed from `task-status-wiki` at v1.0.0. - -## When it triggers - -- User is switching between tasks, resuming a paused task, starting a new - one, or asks "where were we" / "what's the status". -- User says: "use task management system", "pause", "switch to X", - "update status". -- Any context-switching or multi-task coordination question in a code - project. -- Борд читается из mappa (`entity_search(type='task', project=…)`); - файловый `.tasks/` — легаси, ничего настраивать не нужно. - -## Structure - -``` -/ -└── .tasks/ - ├── STATUS.md ← board: one block per task, sorted by priority - └── .md ← deep context per task, one file each -``` - -Commit `.tasks/` to git — decision history is valuable, diffs show how -thinking evolved. - -## STATUS.md format - -```markdown -# Task Board -_Updated: YYYY-MM-DD_ - -## 🔴 [task-slug] — short description -**Status:** active | paused | blocked | done -**Where I stopped:** one sentence — the exact thought or action interrupted -**Next action:** one concrete step to resume immediately -**Blocker:** (only if blocked) what is preventing progress -**Branch:** git branch name - ---- -``` - -Status legend: - -| Emoji | State | Notes | -|---|---|---| -| 🔴 | Active | Currently worked on. **Only one at a time.** | -| 🟡 | Paused | In progress, resumable. | -| ⚪ | Ready | Defined, not started. | -| 🟢 | Done | Kept until merged. | -| 🔵 | Blocked | Waiting on external input. | - -## Per-task file format (`.md`) - -Sections, in order: **Goal** (one paragraph — what this achieves and why), -**Key files** (`path/to/file.ts:42` style — specific lines when relevant), -**Decisions log** (reverse-chronological, append-only — past entries are -immutable), **Open questions**, **Completed steps**, **Notes** (temporary -hypotheses, links). - -## Operations - -### Session start - -1. Check the mappa board: `entity_search(type='task', project=<имя>)`. - Файлового `.tasks/STATUS.md` больше нет — setup-tasks умер. -2. Read `STATUS.md`. -3. If user names a task, read its `.md`. -4. Confirm in one sentence: "We're in the middle of X, next step is Y." -5. Ask if the plan is still correct before doing anything. -6. If `_Updated` is more than 3 days old, flag it and ask the user to - confirm current state. - -### Session end / pause / switch - -1. Update `STATUS.md`: set the current task to 🟡, refresh "Where I stopped" - and "Next action". -2. Append non-obvious decisions to `.md` Decisions log. -3. Move finished items to "Completed steps". -4. Commit: `git add .tasks/ && git commit -m "chore: update task status []"`. - -### Task switch - -1. Run session-end ops for the current task. -2. Read the target `.md`. -3. Set the target to 🔴 in `STATUS.md` (demote previous active to 🟡). -4. Confirm orientation before starting work. - -### New task - -1. Ask: slug, goal, known key files, branch. -2. Create `.md` with Goal and Key files populated. -3. Add a ⚪ block to `STATUS.md`. -4. Create / checkout the branch if missing. - -### Task completion - -1. **Pre-close coverage check** — list acceptance criteria, locate - evidence (tests, smoke-test artefacts, manual checklist ticks, design - doc refs). Missing evidence → ask the user before closing; never auto-close. -2. Resolve or drop all open questions. -3. Set status to 🟢 in `STATUS.md`. -4. Append a final summary line to the Decisions log. -5. Remind the user to delete the branch after merge. - -### Post-commit task closure prompt - -After a `feat:` / `fix:` commit the agent prompts: -"эта работа закрывает таску ``?". Slug candidates: commit-message -scope, current branch, most recent `Where I stopped`. If yes → run the -coverage check above. Skips `chore:` / `meta:` / `docs:` commits. - -Forces a fresh-while-fresh decision, instead of letting shipped code sit -under a stale ⚪ block. - -### Recommendations / "what's next" trigger - -When the user asks «что дальше», «срочные», «куда копаем», "what next", -"status", or on session-start — recommend in this order: - -1. **Local cwd-project board** ranked 🔴 → 🟡 → ⚪. Cite slugs. -2. **One footnote line** if relevant: `Cross-project: N 🔴 in other repos - (см. mcp__projects-meta__tasks_aggregate).` Only if N>0 and no local 🔴. - -Explicit "по всем проектам" / "across all projects" flips the order. -Pairs with `using-projects-meta`'s local-first rule (which covers reads; -this one covers recommendations). - -## Rules - -- **Never lose "Where I stopped".** Most critical field. If unclear, ask - before ending the session. -- **One sentence per `STATUS.md` field.** Compress, don't write prose. -- **Key files must be specific** — not "auth module" but - `packages/auth/src/useAuth.ts:87`. -- **Decisions log is append-only.** Past entries are immutable. -- **Commit after every session end.** `git log` is the history of thinking. -- **Always confirm orientation at session start.** State understanding - before acting. -- **One active task at a time** — only one 🔴 in `STATUS.md`. -- **Never close without coverage check.** See "### Task completion" - step 1. -- **Local-first recommendations.** cwd-project first; cross-project at - most one footnote line. - -## Install - -From the repo root: - -```bash -bash scripts/install.sh using-tasks -``` - -Works on Windows under git-bash, Linux, macOS. - -## See also - -- mappa — сервис-хост борда (`task_create`/`task_claim_next`/`task_close`, - per-type `t:N`). -- [`project-bootstrap`](../project-bootstrap/) — mappa-режим для новых проектов. diff --git a/skills/using-tasks/SKILL.md b/skills/using-tasks/SKILL.md deleted file mode 100644 index 324142c..0000000 --- a/skills/using-tasks/SKILL.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -name: using-tasks -author: ours -version: 2.0.0 -description: > - Policy skill for working with the project task board in Mappa (решения 14/15: - мета в сервисе). Use whenever switching between tasks, resuming a paused task, - starting a new task, asking «where were we», says «use task management system», - «pause», «switch to X», «what's the status», «update status», or tracking - progress across parallel workstreams. Board = сущности `type=task` в mappa - (чтение — карв-аут лиза; мутации — под лизом проекта, решение 19). Файловый - `.tasks/` — легаси; `setup-tasks` умер (нечего настраивать). ---- - -# using-tasks - -> Policy для поддержания сжатого рабочего контекста параллельных тасок. -> Борд проекта — сущности mappa: каждая таска `t:N` (per-type номер, решение 20) -> со статусом `ready|active|paused|blocked|done`, телом, owner'ом и рёбрами -> ([[refs]] → parent_of/ref, решения 4/6). Чтение — карв-аут лиза (решение 19); -> **любая мутация — под лизом проекта**. - -## MCP-поверхность - -| Операция | Тул | Примечание | -|---|---|---| -| Взять следующую ready-таску | `mcp__mappa__task_claim_next(project, owner)` | атомарно: лиз + таска; → `{ok, token, task}` | -| Продлить лиз | `mcp__mappa__task_heartbeat(project, claim_token)` | долгие таски | -| Создать таску | `mcp__mappa__task_create(project, slug, title?, description?, status?, claim_token)` | под лизом | -| Закрыть таску | `mcp__mappa__task_close(project, id, claim_token)` | под лизом | -| Прочитать таску | `mcp__mappa__entity_get(id)` | id internal из search/claim | -| Список борда | `mcp__mappa__entity_search(q, type='task', project=<имя>, limit)` | все статусы | -| Дерево parent_of | `mcp__mappa__graph_tree(root, depth?, fields?, limit?)` | зонтики/иерархия (решение 6) | -| Связанные сущности | `mcp__mappa__graph_neighbors/backlinks(id)` | рефы к таске | -| Уведомление при закрытии | `mcp__mappa__inbox_send(project=, from=<своя>, subject, body)` | письмо комиссионеру | - -**Лиз = лок на запись (решение 19).** Одна строка leases на проект: если другой -агент держит лиз — `task_claim_next` вернёт **422 busy**. Это серверный аналог -старого `.tasks/.lock`: проверять «а не поллер ли работает» руками не нужно — -сам claim скажет. Чтения лиза не требуют. - -**Рефы и id (#1037).** Таски наружу несут `ref: "t:N"` первым полем, `num` -следом, глобальный `id` — internal (последним, для addressing в тулах). -Ссылайся на таску `[[t:N]]` (в body → рёбра автоматически), никогда -`#<глобальный id>`. - -## Статусы (эмодзи для презентации) - -| Эмодзи | Статус | Значение | -|---|---|---| -| ⚪ | `ready` | не начата, полностью определена | -| 🔴 | `active` | в работе (обычно одна) | -| 🟡 | `paused` | в процессе, возобновляема | -| 🔵 | `blocked` | ждёт внешнего входа | -| 🟢 | `done` | закрыта | - -## Операции агента - -### Ориентация (session start) - -1. **Инбокс-свип** — `mcp__mappa__inbox_monitor(project=<имя>)`: непрочитанные - письма могут менять план. Обработай каждое по `inter-session-messaging`. -2. **Борд** — `mcp__mappa__entity_search(q='', type='task', project=<имя>, limit=50)`: - отсортируй по статусу (🔴 → 🟡 → ⚪), по одной строке на таску, цитируй slug. -3. Если user назвал таску — `entity_get(id)` по её рефу/номеру. -4. Подтверди одним предложением: «Мы в середине X, следующий шаг — Y». -5. Спроси, верен ли план, перед действиями. - -### Переключение / пауза / конец сессии - -1. Текущая 🔴 → `task_close` если завершена (см. закрытие), иначе пометь - `status=paused` через update-механику (owner остаётся; «where stopped» — - в body или handoff). -2. **Инбокс-свип** на границе тасок (`inbox_monitor`). -3. Возьми следующую: `task_claim_next` (лиз + таска). Прежняя остаётся 🟡. -4. Подтверди ориентацию перед стартом. - -> Примечание про «Where I stopped»: у mappa-таски нет отдельного поля — держи -> место остановки в `description` (последний абзац) или, для сессионного -> контекста, в **handoff-сущности** (`session-handoff`: summary/open_treks). -> Перед концом сессии обязательно запиши handoff — это аналог -> «Never lose Where I stopped». - -### Создание таски - -1. **Через тул, не руками** (решение 20): сначала лиз (`task_claim_next`) → - `task_create(project, slug, title, description, status='ready', claim_token)`. - Номер `t:N` назначает сервер — не выдумывай. -2. Slug: kebab-case, латиница. Description: markdown, `[[refs]]` на связанное. -3. Закрыть лиз не нужно — экспирится по TTL; мутации идут одним циклом. - -### Закрытие таски - -1. **Pre-close coverage check.** Собери acceptance criteria из description. - Для каждого — evidence: тест в диффе, артефакт, ссылка на дизайн. - Нет evidence на критерий → спроси user'а «закрывать или подождать coverage'а». -2. Resolve/drop открытые вопросы. -3. `task_close(project, id, claim_token)` → статус `done`. -4. **Notify-письмо (кросс-проектные таски).** Если таска пришла из другого - проекта (в description/meta есть `from:`/`notify:`) — `inbox_send` - комиссионеру: `project=`, `subject="[event: closed] "`, - body = итог (сделано, acceptance, ссылки). Живая сессия пишет сама. -5. Дополни summary-строку в handoff/вики при наличии. - -### Рекомендации / «что дальше» - -User спросил «что дальше», «status», «куда копаем» — рекомендую в порядке: - -1. **Локальный борд текущего проекта** (cwd): `entity_search(type='task', - project=<имя>)` — 🔴 → 🟡 → ⚪, по строке на таску, цитируй slug. -2. Одна footnote-строка если кросс-проектно релевантно: `Cross-project: N 🔴 - active (см. mcp__projects-meta__tasks_aggregate).` Только если N>0 и в cwd - нет активной 🔴. - -Кросс-проектные ургенты — информация, не драйвер «что делать здесь». - -## Правила - -- **Лиз-дисциплина.** Мутации — только под лизом; 422 busy = кто-то другой - пишет, не параллель. -- **Never lose Where I stopped** — критичное поле: в description + handoff. -- **Одна активная таска** — только одна 🔴 на проект. -- **Не выдумывай номера** — `t:N` назначает сервер. -- **Never close без coverage check** — evidence на каждый acceptance criterion, - иначе спросить. -- **Notify-письмо при закрытии** кросс-проектных тасок — статус 🟢 ≠ комиссионер - узнал. -- **Чтения — карв-аут.** `entity_search`/`entity_get`/`graph_*` не требуют лиза - и не блокируются чужим лизом. -- **Локально-первая рекомендация** — борд cwd первым; кросс-проект — футонота. -- **Ссылайся `[[t:N]]`**, не глобальным id (#1037). - -## Legacy (переходное) - -Файловый `.tasks/` (STATUS.md + per-task файлы) — легаси-канал, живёт пока -миграция/поллер не доедут. Не смешивай: новые таски — через mappa task_create; -старые борды читай напрямую (`.tasks/STATUS.md`), если они ещё в файлах. -`setup-tasks` умер — файловые борды больше не настраиваются.