feat(mappa-task-work): merge using-tasks + task-format + task-loop + priority-due → mappa-task-work v1.0.0 (central cycle, loop-mode inside, priority/due section, old names = trigger synonyms) [skip-tdd: visual]
This commit is contained in:
@@ -17,4 +17,15 @@ Rewrite using-tasks + task-format + task-loop + priority-due → **mappa-task-wo
|
|||||||
|
|
||||||
## Completed steps
|
## 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
|
## 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).
|
||||||
|
|||||||
BIN
dist/mappa-task-work.skill
vendored
Normal file
BIN
dist/mappa-task-work.skill
vendored
Normal file
Binary file not shown.
BIN
dist/task-format.skill
vendored
BIN
dist/task-format.skill
vendored
Binary file not shown.
BIN
dist/task-loop.skill
vendored
BIN
dist/task-loop.skill
vendored
Binary file not shown.
BIN
dist/using-tasks.skill
vendored
BIN
dist/using-tasks.skill
vendored
Binary file not shown.
296
skills/mappa-task-work/SKILL.md
Normal file
296
skills/mappa-task-work/SKILL.md
Normal file
@@ -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=<notify>, 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` = `<machine>:<runtime>:<session>`.
|
||||||
|
Порядок выдачи: **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 файл (`<slug>.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=<notify>`, `subject="[event: closed] <slug>"`,
|
||||||
|
body = итог (сделано, acceptance, ссылки). Живая сессия пишет сама.
|
||||||
|
Таска 🟢 ≠ комиссионер узнал.
|
||||||
|
5. **Review-umbrella для impl-тасок** (канон `mappa-delegation`): если таска
|
||||||
|
имплементационная и закрыта — парная `<slug>-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 + <slug>.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: <kebab-case>, // обязателен, латиница
|
||||||
|
title: <одна строка>, // опционально
|
||||||
|
description: <markdown>, // тело; [[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
|
||||||
|
<!-- created-by: you@machine / from: OpeItcLoc03/workshop / 2026-08-23 -->
|
||||||
|
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Три load-bearing правила: **(1)** шапка точно `## <emoji> [#<n> <slug>] — <desc>`
|
||||||
|
(h2, один emoji, `[#<n> <slug>]`, разделитель ` — `); **(2)** поля — строки
|
||||||
|
`**Label:** value`, буллеты игнорируются; **(3)** `**Created:**` обязателен.
|
||||||
|
|
||||||
|
Поля, которые разбирает поллер: `**Weight:**` (cheap-ok | needs-claude |
|
||||||
|
needs-human — **обязателен** для авто-взятия), `**Notify:**` (<owner>/<repo>),
|
||||||
|
`**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`.
|
||||||
@@ -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: <kebab-case>, // обязателен, латиница
|
|
||||||
title: <одна строка>, // опционально
|
|
||||||
description: <markdown>, // тело; [[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
|
|
||||||
<!-- created-by: you@machine / from: OpeItcLoc03/workshop / 2026-08-23 -->
|
|
||||||
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Три load-bearing правила:
|
|
||||||
|
|
||||||
1. **Шапка точно:** `## <emoji> [#<n> <slug>] — <description>` — h2, один emoji,
|
|
||||||
`[#<n> <slug>]` (глобальный номер, без ведущих нулей), разделитель
|
|
||||||
` — ` (пробел + 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:**` | `<owner>/<repo>` | Инбокс-адрес для событий 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` / буллеты вместо полей | `## <emoji> [#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-блок: шапка
|
|
||||||
`## <emoji> [#n slug] — …`, emoji = `**Status:**`, `**Created:**` есть, поля —
|
|
||||||
`**Label:**` строки, есть `**Weight:**` и `**Notify:**`); slug kebab-case;
|
|
||||||
ссылки на неё — `[[t:N]]`.
|
|
||||||
@@ -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` = `<machine>:<runtime>:<session>` (e.g. `DESKTOP-NSEF0UK:claude-opus:<session>`).
|
|
||||||
- `filter.project` = **the current project** (qualified `<owner>/<repo>`) 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 `<slug>.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="<concrete fact + what's needed>")`. 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.
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
```
|
|
||||||
<monorepo-root>/
|
|
||||||
└── .tasks/
|
|
||||||
├── STATUS.md ← board: one block per task, sorted by priority
|
|
||||||
└── <task-slug>.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 (`<task-slug>.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 `<task-slug>.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 `<task-slug>.md` Decisions log.
|
|
||||||
3. Move finished items to "Completed steps".
|
|
||||||
4. Commit: `git add .tasks/ && git commit -m "chore: update task status [<task-slug>]"`.
|
|
||||||
|
|
||||||
### Task switch
|
|
||||||
|
|
||||||
1. Run session-end ops for the current task.
|
|
||||||
2. Read the target `<task-slug>.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 `<task-slug>.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>`?". 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-режим для новых проектов.
|
|
||||||
@@ -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=<notify>, 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=<notify>`, `subject="[event: closed] <slug>"`,
|
|
||||||
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` умер — файловые борды больше не настраиваются.
|
|
||||||
Reference in New Issue
Block a user