feat(task-format): v0.3.0 — primary mappa task.create schema, legacy STATUS.md interim (#983)

Канон создания — через mcp__mappa__task_create (per-type t:N, мутация под
лизом). Legacy-блоки .tasks/STATUS.md — интерм до переключения поллера (#984).
This commit is contained in:
2026-08-24 16:45:58 +03:00
parent 21023f1bae
commit c5ebde174d

View File

@@ -1,27 +1,76 @@
--- ---
name: task-format name: task-format
author: ours author: ours
version: 0.2.0 version: 0.3.0
description: > description: >
Use when writing or editing a task block in a `.tasks/STATUS.md` board that an Use when creating or editing a task so it is actually claimable and routed —
autonomous task-runner ("poller") will read — so the task is actually claimed, not silently skipped. Primary channel: **mappa** — create via
routed, and reported instead of silently skipped. Covers the exact block header, `mcp__mappa__task_create` (схема ниже), не руками. Legacy: пока файловый
the status emoji, and the `**Weight:**` / `**Notify:**` / `**Requirements:**` поллер (agents-task-runner) не переключён на mappa (#984), блоки в
fields the poller parses. Triggers: «оформить таску для поллера», «формат таски», `.tasks/STATUS.md` обязаны совпадать со строгим форматом (шапка, поля
«task block format», «make a task the poller will pick up», «add Weight/Notify», Weight/Notify), иначе поллер молча пропускает. Triggers: «оформить таску для
poller / agent-runner not claiming a task you wrote by hand. поллера», «формат таски», «task block format», «make a task the poller will
pick up», «add Weight/Notify», poller / agent-runner not claiming a task.
--- ---
# task-format # task-format
The autonomous poller parses `.tasks/STATUS.md` line-by-line with **strict regexes**. A block runs only if its header and fields match exactly. Get the format wrong and the poller does not error — it silently skips the block, or claims it and then parks it. This is the canonical field reference. Канон создания задачи — **через тул**, не рукописным блоком. Поллер (автономный
раннер) разбирает задачи строгими правилами; формат задаёт, какая таска будет
взята, отмаршрутизирована и зарепорчена, а какая молча пропущена.
> Authoring a task for **another** project/agent via `mcp__projects-meta__tasks_create`? Use `delegate-task` — it drives the tool, which emits this format for you. This skill is the format itself: for **hand-edited** STATUS.md blocks and for understanding what the poller reads. For board working policy (claim/close/status), see `using-tasks`. > Создаёшь задачу для **другого** проекта/агента? См. `delegate-task` — он ведёт
> через тул + письмо. Работа с бордом (claim/close/status) — `using-tasks`.
## Canonical block (copy this) ## 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
claim_token: <токен лиза проекта> // мутация под лизом (решение 19)
)
```
**Мутация под лизом (решение 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 ```markdown
## ⚪ [#1234 my-task-slug] — One-line description of the work. ## ⚪ [#1234 my-task-slug] — One-line description.
**Status:** ready **Status:** ready
**Created:** 2026-08-23 **Created:** 2026-08-23
@@ -35,76 +84,54 @@ The autonomous poller parses `.tasks/STATUS.md` line-by-line with **strict regex
--- ---
``` ```
## The two load-bearing rules Три load-bearing правила:
1. **Header must match exactly:** `## <emoji> [#<n> <slug>] — <description>` 1. **Шапка точно:** `## <emoji> [#<n> <slug>] — <description>` — h2, один emoji,
- `## ` (h2, two hashes) — **not** `### `, not a bullet. `[#<n> <slug>]` (глобальный номер, без ведущих нулей), разделитель
- One status **emoji**, then `[#<n> <slug>]` in square brackets — **global task number** (`#1234`, no leading zeros) + slug — then ` — ` (space, em-dash `—`, space), then the description. A `-` hyphen or `:` will not match. ` — ` (пробел + em-dash + пробел). Несовпавшая шапка = задача не видна вообще.
- **Number is the machine key.** Global, unique across the whole federation, encodes creation order. References (`#452` in letters, blocker fields, decision trails) point at the number. The slug is the human-readable part only. 2. **Поля — строки `**Label:** value`.** Буллеты и проза игнорируются.
- Slug: short, lowercase, kebab-case, Latin. 3. **`**Created:** yyyy-mm-dd` обязателен** — пишется один раз при создании.
- A header that doesn't match is **not seen as a task at all**.
2. **Fields are `**Label:** value` lines** — bold label, colon, space, value. Bullet-list fields (`- **weight:** …`) and prose ("notify workshop when done") are **ignored** — the poller never reads them. Номера legacy-блоков назначает сервер (`tasks_create` из счётчика
`OpeItcLoc03/agenda/task-counter`) — **никогда не выдумывай номер руками**.
3. **`**Created:** yyyy-mm-dd` is mandatory** — the creation date. Written once at task creation, never edited after. ### Поля, которые поллер разбирает
## Numbering
- **Numbers are assigned by the server** (`mcp__projects-meta__tasks_create`) from the counter in `OpeItcLoc03/agenda/task-counter` — never invent or reuse a number by hand.
- The **file name** is `yyyy-mm-dd-#####-<slug>.md` — number **5 digits with leading zeros, no `#`**: `2026-06-05-00019-fix-nl-vds-reality-pq-dest.md`. Leading zeros make folder sort = numeric up to 99999. No `#` in the filename (it would break markdown links and Gitea URLs).
- In the **header and text references** the number is written **without** leading zeros: `[#19 slug]`.
## Status emoji ↔ state
| Emoji | State | |
|---|---|---|
| ⚪ | **ready** | the only state the poller claims |
| 🔴 | active | claimed / in flight |
| 🟡 | paused | resumable |
| 🔵 | blocked | waiting on a `**Blocker:**` |
| 🟢 | done | kept until merged |
`**Status:**` mirrors the emoji in words. ⚪ → `ready`. **Do not** use 🟢 for "ready" — 🟢 is *done*.
## Fields the poller parses
| Field | Format | Meaning | | Field | Format | Meaning |
|---|---|---| |---|---|---|
| `**Weight:**` | `cheap-ok` \| `needs-claude` \| `needs-human` | Routing tier. **Required for autonomous pickup** — see below. | | `**Weight:**` | `cheap-ok` \| `needs-claude` \| `needs-human` | Тир маршрутизации. **Обязателен** для авто-взятия. |
| `**Notify:**` | `<owner>/<repo>` | Inbox target. Poller writes to that project's `.agents/inbox/` on close / park / delivery-failure. Omit → no report; the steering loop never closes. | | `**Notify:**` | `<owner>/<repo>` | Инбокс-адрес для событий close/park/delivery-failure. |
| `**Requirements:**` | CSV, e.g. `needs-db, needs-secrets` | Hard capability gate. The agent must hold **all** listed capabilities or the task is skipped. | | `**Requirements:**` | CSV (`needs-db, needs-secrets`) | Capability-гейт: агент должен держать ВСЕ. |
| `**Runtime allowed:**` | CSV, e.g. `claude-opus` | Runtime whitelist. If set, only a listed runtime may claim. | | `**Runtime allowed:**` | CSV (`claude-opus`) | Runtime-whitelist. |
| `**Consult policy:**` | `auto` \| `human-only` \| `strict-human` | How a mid-run `consult` escalates. Default when absent: `human-only`. | | `**Consult policy:**` | `auto` \| `human-only` \| `strict-human` | Эскалация consult; default `human-only`. |
| `**Blocker:**` | CSV of blocker slugs | Only on 🔵 blocked. Auto-unblock flips the task to ⚪ when every blocker is 🟢. | | `**Blocker:**` | CSV blocker-slug'ов | Только на 🔵; авто-unblock при 🟢 всех. |
| `**Next action:** / **Where I stopped:** / **Branch:**` | free text | Core resumability fields. | | `**Next action:** / **Where I stopped:** / **Branch:**` | free text | Резюмируемость. |
`**Owner:** / **Claim token:** / **Claim expires at:**` are the **claim stamp** — the poller writes and clears them. Never author them by hand; a stale stamp on a ⚪ task blocks the poller. `**Owner:** / **Claim token:** / **Claim expires at:**` — claim-штамп, пишет и
чистит поллер. Не автори руками; залипший штамп на ⚪ блокирует поллер.
## Weight — the field that decides pickup **Weight — поле, решающее взятие:** без `**Weight:**` поллер берёт задачу, не
находит тир и паркует в 🔵 (`no backend for weight_tier: unknown`). Обычный код
`needs-claude`; критикал-инфра (поллер, MCP-серверы, деплой, CI, git-хуки) →
`needs-human` (никогда не авто).
The poller routes each claimed task to a backend by its weight tier: ## Common mistakes
- `cheap-ok` — routine work, a cheap/weak model is fine.
- `needs-claude` — needs a capable model (refactors, anything where discipline matters, review).
- `needs-human`**never** runs autonomously. The claim gate excludes it and the runner refuses to spawn. Use for anything touching critical infra: the poller/agent-runner itself, MCP servers, claim/close/heartbeat, deploy, CI/CD, git hooks.
**No `**Weight:**` line → no backend tier matches → the poller claims the task, finds no route, and parks it to 🔵 blocked (`no backend for weight_tier: unknown`).** So a task you want run **must** carry a Weight. If in doubt and the work is ordinary code, use `needs-claude`.
## Common mistakes (from baseline failures)
| Mistake | Fix | | Mistake | Fix |
|---|---| |---|---|
| `### Title` or a `- **id:**` bullet list | Use the exact `## <emoji> [#n slug] — desc` h2 header + `**Field:**` lines. | | Рукописный блок вместо `task_create` | Создавай через тул — номер/формат серверные. |
| 🟢 for a ready task | 🟢 is *done*. Ready is ⚪. | | `### Title` / буллеты вместо полей | `## <emoji> [#n slug] — desc` + `**Field:** value`. |
| Header `[slug]` without a number | Header is `[#n slug]` — the number is the machine key. | | 🟢 для ready | 🟢 — done. Ready — ⚪. |
| `**Created:**` missing | Add `**Created:** yyyy-mm-dd` — mandatory field. | | Шапка `[slug]` без номера | `[#n slug]` — номер машинный ключ. |
| Inventing a number by hand | Numbers come only from `tasks_create` (counter). Never invent/reuse. | | Выдуманный номер | Номер — только от сервера (task_create). |
| File named `2026-06-05-19-slug.md` (no leading zeros) | File is `yyyy-mm-dd-#####-slug.md`, number 5 digits: `00019`. | | `**Created:**` отсутствует (legacy) | Добавить — обязательное поле. |
| Inventing `risk: low`, `tier: L`, `priority`, `claimable-by` | The poller routes on `**Weight:**` with three fixed values only. | | Ссылка `#<глобальный id>` | Ссылайся `[[t:N]]` (решение 20/#1037). |
| Notification written as prose / "Done-signal" | Use a real `**Notify:** <owner>/<repo>` field line. | | Без `**Weight:**` (legacy) | Ставь всегда, или задача паркуется. |
| Omitting Weight on a task you want auto-run | Always set Weight, or the task parks. | | Дефис/двоеточие вместо ` — ` в шапке | Разделитель — пробел + em-dash + пробел. |
| Hyphen or colon instead of `` in the header | The separator is space + em-dash + space. |
## Verify ## Verify
After editing, the block is correct when: header is `## <emoji> [#n slug] — …`, the emoji matches `**Status:**`, `**Created:** yyyy-mm-dd` is present, every machine-read field is a `**Label:**` line (not a bullet), and a task meant for the poller has both `**Weight:**` (not `needs-human` unless intended) and `**Notify:**`. Задача корректна, когда: создана через `task_create` (или legacy-блок: шапка
`## <emoji> [#n slug] — …`, emoji = `**Status:**`, `**Created:**` есть, поля —
`**Label:**` строки, есть `**Weight:**` и `**Notify:**`); slug kebab-case;
ссылки на неё — `[[t:N]]`.