From c5ebde174d7f8f7a7bcdfdf4d0743aa7d33aa29b Mon Sep 17 00:00:00 2001 From: vitya Date: Mon, 24 Aug 2026 16:45:58 +0300 Subject: [PATCH] =?UTF-8?q?feat(task-format):=20v0.3.0=20=E2=80=94=20prima?= =?UTF-8?q?ry=20mappa=20task.create=20schema,=20legacy=20STATUS.md=20inter?= =?UTF-8?q?im=20(#983)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Канон создания — через mcp__mappa__task_create (per-type t:N, мутация под лизом). Legacy-блоки .tasks/STATUS.md — интерм до переключения поллера (#984). --- skills/task-format/SKILL.md | 167 +++++++++++++++++++++--------------- 1 file changed, 97 insertions(+), 70 deletions(-) diff --git a/skills/task-format/SKILL.md b/skills/task-format/SKILL.md index f5222cc..f5879b3 100644 --- a/skills/task-format/SKILL.md +++ b/skills/task-format/SKILL.md @@ -1,27 +1,76 @@ --- name: task-format author: ours -version: 0.2.0 +version: 0.3.0 description: > - Use when writing or editing a task block in a `.tasks/STATUS.md` board that an - autonomous task-runner ("poller") will read — so the task is actually claimed, - routed, and reported instead of silently skipped. Covers the exact block header, - the status emoji, and the `**Weight:**` / `**Notify:**` / `**Requirements:**` - fields the poller parses. Triggers: «оформить таску для поллера», «формат таски», - «task block format», «make a task the poller will pick up», «add Weight/Notify», - poller / agent-runner not claiming a task you wrote by hand. + 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 -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: , // обязателен, латиница + title: <одна строка>, // опционально + description: , // тело; [[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 -## ⚪ [#1234 my-task-slug] — One-line description of the work. +## ⚪ [#1234 my-task-slug] — One-line description. **Status:** ready **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:** `## [# ] — ` - - `## ` (h2, two hashes) — **not** `### `, not a bullet. - - One status **emoji**, then `[# ]` 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. - - **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. - - Slug: short, lowercase, kebab-case, Latin. - - A header that doesn't match is **not seen as a task at all**. +1. **Шапка точно:** `## [# ] — ` — h2, один emoji, + `[# ]` (глобальный номер, без ведущих нулей), разделитель + ` — ` (пробел + em-dash + пробел). Несовпавшая шапка = задача не видна вообще. +2. **Поля — строки `**Label:** value`.** Буллеты и проза игнорируются. +3. **`**Created:** yyyy-mm-dd` обязателен** — пишется один раз при создании. -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-#####-.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 | |---|---|---| -| `**Weight:**` | `cheap-ok` \| `needs-claude` \| `needs-human` | Routing tier. **Required for autonomous pickup** — see below. | -| `**Notify:**` | `/` | Inbox target. Poller writes to that project's `.agents/inbox/` on close / park / delivery-failure. Omit → no report; the steering loop never closes. | -| `**Requirements:**` | CSV, e.g. `needs-db, needs-secrets` | Hard capability gate. The agent must hold **all** listed capabilities or the task is skipped. | -| `**Runtime allowed:**` | CSV, e.g. `claude-opus` | Runtime whitelist. If set, only a listed runtime may claim. | -| `**Consult policy:**` | `auto` \| `human-only` \| `strict-human` | How a mid-run `consult` escalates. Default when absent: `human-only`. | -| `**Blocker:**` | CSV of blocker slugs | Only on 🔵 blocked. Auto-unblock flips the task to ⚪ when every blocker is 🟢. | -| `**Next action:** / **Where I stopped:** / **Branch:**` | free text | Core resumability fields. | +| `**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 при 🟢 всех. | +| `**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: - -- `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) +## Common mistakes | Mistake | Fix | |---|---| -| `### Title` or a `- **id:** …` bullet list | Use the exact `## [#n slug] — desc` h2 header + `**Field:**` lines. | -| 🟢 for a ready task | 🟢 is *done*. Ready is ⚪. | -| Header `[slug]` without a number | Header is `[#n slug]` — the number is the machine key. | -| `**Created:**` missing | Add `**Created:** yyyy-mm-dd` — mandatory field. | -| Inventing a number by hand | Numbers come only from `tasks_create` (counter). Never invent/reuse. | -| File named `2026-06-05-19-slug.md` (no leading zeros) | File is `yyyy-mm-dd-#####-slug.md`, number 5 digits: `00019`. | -| Inventing `risk: low`, `tier: L`, `priority`, `claimable-by` | The poller routes on `**Weight:**` with three fixed values only. | -| Notification written as prose / "Done-signal" | Use a real `**Notify:** /` field line. | -| Omitting Weight on a task you want auto-run | Always set Weight, or the task parks. | -| Hyphen or colon instead of ` — ` in the header | The separator is space + em-dash + space. | +| Рукописный блок вместо `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) | Ставь всегда, или задача паркуется. | +| Дефис/двоеточие вместо ` — ` в шапке | Разделитель — пробел + em-dash + пробел. | ## Verify -After editing, the block is correct when: header is `## [#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-блок: шапка +`## [#n slug] — …`, emoji = `**Status:**`, `**Created:**` есть, поля — +`**Label:**` строки, есть `**Weight:**` и `**Notify:**`); slug kebab-case; +ссылки на неё — `[[t:N]]`.