feat(task-format): new skill v0.1.0 — poller task-block format reference

Public reference for the on-disk .tasks/STATUS.md block format the autonomous
poller parses: header regex, status emoji, and the **Weight:** / **Notify:** /
**Requirements:** fields. Ships with factory where the internal wiki and MCP
source can't reach. Distinct from delegate-task (MCP-tool delegation) and
using-tasks (board mechanics).

Authored via superpowers:writing-skills TDD:
- RED: 3 baseline subagents w/o skill — 2/3 used ###/bullet headers the parser
  cannot recognize as a task, 2/3 omitted **Weight:** (invented risk/tier/
  claimable-by), 2/3 put notify in prose, 1/3 used 🟢 for a ready task.
- GREEN: 2 fresh subagents w/ skill — both parser-valid, incl. correct
  **Weight:** needs-human for the critical-infra scenario.
- REFACTOR: no new format loopholes.

Ground truth verified vs live source (status-md.ts parser, claim.ts gate,
fleet-router.js routing): missing Weight finds no backend tier -> poller parks
to blocked, so Weight is operatively required for pickup.

Closes [create-task-format-for-poller-skill]. Install to ~/.claude/skills +
hermes mapping deferred as follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 12:21:24 +03:00
parent 76c86a793f
commit a71ed9bf07
5 changed files with 149 additions and 16 deletions

View File

@@ -1,5 +1,5 @@
# Task Board
_Updated: 2026-06-09 — using-markitdown-cli-rewrite-review done (VERDICT PASS; SKILL.md без `mcp__markitdown__`, CLI-примеры совпадают с `markitdown 0.1.6 --help`, version 1.0.0→1.0.1 PATCH, dist консистентен; 1 informational finding — docker-контейнер респаунится из out-of-scope `~/.claude.json` MCP-регистрации → follow-up `using-markitdown-mcp-deregister` needs-human). Ранее: skill-using-system-snapshot-review done (VERDICT PASS 3/3; live tool-contract verify + 9-way fresh-context trigger test, 8 clean; 3 informational findings, none blocking — incl. missing deployment scaffold: skill not installed / not in hermes-mapping / no baseline tasks). Ранее: using-tasks-status-read-perf done (using-tasks 1.2.0→1.3.0; done-task archival rule fixes STATUS.md bloat; literal `tasks_get_status`-for-orientation swap NOT done — tool can't enumerate the board, documented). Ранее: session-break-using-tasks done (using-tasks 1.1.0→1.2.0; `session_break` marker — stop after close before claim-next). Ранее: delegate-task-review done (VERDICT PASS; smoke-test 6/6 fresh subagents, no blocking findings, 3 informational notes). Ранее: delegate-task-test-trigger done (pos 5/5, neg 2/3; FP на «создать задачу себе» → follow-up delegate-task-description-fp-fix, shipped v0.2.1). Ранее (2026-06-08): откат churn'а от агент-раннера (always-on dry-run): 5 тасок (using-yt-tools-rate-limit-guard, archive-roundtrip-test, skills-grouping-revisit, hermes-converter-ci, tdd-criteria-precommit-hook) спуриозно claimed/blocked из-за workspace-divergence бага раннера → возвращены в ⚪ ready. yt-tools re-scoped на plugin-репо `OpeItcLoc03/yt-tools` (исходный stub deprecated)._
_Updated: 2026-06-11 — task-format skill v0.1.0 created (TDD via writing-skills; RED 3-fail → GREEN 2-pass). Ранее: using-markitdown-cli-rewrite-review done (VERDICT PASS; SKILL.md без `mcp__markitdown__`, CLI-примеры совпадают с `markitdown 0.1.6 --help`, version 1.0.0→1.0.1 PATCH, dist консистентен; 1 informational finding — docker-контейнер респаунится из out-of-scope `~/.claude.json` MCP-регистрации → follow-up `using-markitdown-mcp-deregister` needs-human). Ранее: skill-using-system-snapshot-review done (VERDICT PASS 3/3; live tool-contract verify + 9-way fresh-context trigger test, 8 clean; 3 informational findings, none blocking — incl. missing deployment scaffold: skill not installed / not in hermes-mapping / no baseline tasks). Ранее: using-tasks-status-read-perf done (using-tasks 1.2.0→1.3.0; done-task archival rule fixes STATUS.md bloat; literal `tasks_get_status`-for-orientation swap NOT done — tool can't enumerate the board, documented). Ранее: session-break-using-tasks done (using-tasks 1.1.0→1.2.0; `session_break` marker — stop after close before claim-next). Ранее: delegate-task-review done (VERDICT PASS; smoke-test 6/6 fresh subagents, no blocking findings, 3 informational notes). Ранее: delegate-task-test-trigger done (pos 5/5, neg 2/3; FP на «создать задачу себе» → follow-up delegate-task-description-fp-fix, shipped v0.2.1). Ранее (2026-06-08): откат churn'а от агент-раннера (always-on dry-run): 5 тасок (using-yt-tools-rate-limit-guard, archive-roundtrip-test, skills-grouping-revisit, hermes-converter-ci, tdd-criteria-precommit-hook) спуриозно claimed/blocked из-за workspace-divergence бага раннера → возвращены в ⚪ ready. yt-tools re-scoped на plugin-репо `OpeItcLoc03/yt-tools` (исходный stub deprecated)._
<!--
Canonical layout. One block per task. Per-task deep context lives in
@@ -951,23 +951,16 @@ No `consult` was needed; nothing irreversible or cross-cutting. Files changed: `
**Источник:** finding из `using-markitdown-cli-rewrite-review` (2026-06-09). Импл-таска `using-markitdown-cli-rewrite` удалила существовавшие контейнеры корректно, но оставила MCP-регистрацию (out of scope, явно флагнуто в `.wiki/concepts/using-markitdown-cli-migration.md` §Out of scope). На ревью контейнер `boring_spence` уже респаунился.
**Weight:** needs-human — правка user-global `~/.claude.json` + keep-or-drop решение: после rewrite скил советует CLI, но MCP-тул `mcp__markitdown__convert_to_markdown` ещё зарегистрирован. Подтвердить с владельцем что MCP больше не нужен, затем удалить запись + `docker rm -f $(docker ps -aq --filter "ancestor=markitdown-mcp:latest")` + (опц.) `docker rmi markitdown-mcp:latest`.
<<<<<<< HEAD
**Status:** done
**Where I stopped:** Confirmed by owner: MCP not needed. Removed mcpServers.markitdown from ~/.claude.json, docker rm containers, docker rmi markitdown-mcp:latest (1.52GB freed).
**Next action:** (none — kept until merged)
=======
**Status:** blocked — parked for human via `consult` (halt; `consult_policy=human-only`, decided_by=human-required). Deep context + resume brief: `.tasks/using-markitdown-mcp-deregister.md`.
**Where I stopped:** Подтвердил фактическое состояние (mcpServers.markitdown в `~/.claude.json`; контейнер `kind_cohen` респаунился Up ~1m; образ `markitdown-mcp:latest` 1.52GB). Перед мутацией user-global конфига вызвал `consult` → halt. Конфиг/контейнеры/образ НЕ тронуты.
**Next action:** Дождаться ответа владельца: нужен ли ещё MCP-тул `mcp__markitdown__convert_to_markdown`? Нет → удалить `mcpServers.markitdown` из `~/.claude.json` + `docker rm -f $(docker ps -aq --filter "ancestor=markitdown-mcp:latest")` + опц. `docker rmi markitdown-mcp:latest`. Да → закрыть wontfix (критерий #2 = "removed at impl time", respawn by design).
**Blocker:** human keep-or-drop decision (consult parked, human-only policy) — see `.tasks/using-markitdown-mcp-deregister.md`.
>>>>>>> 1bc7615 (meta(tasks): park [using-markitdown-mcp-deregister] for human (consult halt))
**Branch:** n/a
<!-- created-by: DESKTOP-NSEF0UK:claude-opus:11584 / from: using-markitdown-cli-rewrite-review finding / 2026-06-09 -->
<!-- closed-by: OpeItcLoc03@DESKTOP-NSEF0UK / 2026-06-09T18:00:53.166Z / note: Confirmed by owner: MCP not needed. Removed mcpServers.markitdown from ~/.claude.json, docker rm containers, docker rmi markitdown-mcp:latest (1.52GB freed). -->
---
## 🔴 [create-task-format-for-poller-skill] — Создать скил `task-format` в `claude-skills/skills/` по TDD-процессу (`superpowers:writing-skills`).
## 🟢 [create-task-format-for-poller-skill] — Создать скил `task-format` в `claude-skills/skills/` по TDD-процессу (`superpowers:writing-skills`).
**Weight:** needs-claude
@@ -1001,14 +994,12 @@ No `consult` was needed; nothing irreversible or cross-cutting. Files changed: `
**Источники:** `agenda/concepts/task-format-agent-poller` + `OpeItcLoc03/common/.wiki/concepts/agents-task-runner-ops.md`
**Status:** active
**Where I stopped:** (not started)
**Next action:** Прочитать `agenda/concepts/task-format-agent-poller`. Запустить baseline-субагент без скила — зафиксировать нарушения (Weight/Notify).
**Branch:** n/a
**Status:** done
**Where I stopped:** Skill shipped — `skills/task-format/SKILL.md` v0.1.0 + `.wiki/concepts/task-format-design.md`. TDD per writing-skills: RED (3 baseline subagents — 2/3 used `###`/bullet headers the parser can't recognize, 2/3 omitted Weight, 2/3 notify-in-prose, 1/3 🟢-for-ready) → GREEN (2 fresh subagents, both parser-valid incl. correct `needs-human` for critical-infra) → REFACTOR clean. Ground truth verified vs `status-md.ts` + `claim.ts` + `fleet-router.js` (the `agenda/concepts/task-format-agent-poller` source named in next-action doesn't exist on disk; used the live parser/router source instead — strictly more authoritative).
**Next action:** (none — kept until merged)
**Branch:** master
**Notify:** OpeItcLoc03/workshop
**Owner:** DESKTOP-NSEF0UK:claude-opus:30508
**Claim token:** 43a6ad53-b957-4467-9018-bc4b418406f1
**Claim expires at:** 2026-06-11T09:29:06.009Z
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-06-11T08:39:18.657Z -->
<!-- closed-by: DESKTOP-NSEF0UK:claude-opus / 2026-06-11 / note: closed by inspection — TDD evidence (RED 3-fail / GREEN 2-pass subagent runs) is the acceptance coverage for a markdown skill; install to ~/.claude/skills + hermes mapping deferred as a follow-up (mirrors using-system-snapshot deployment-scaffold note) -->
---

View File

@@ -0,0 +1,45 @@
---
title: task-format skill — design
type: concept
updated: 2026-06-11
---
# task-format skill — design
## Why it exists
The autonomous poller (agents-task-runner) reads each project's `.tasks/STATUS.md` and decides what to claim, how to route it, and whom to notify. Those decisions hang on a handful of fields — most critically `**Weight:**` and `**Notify:**`. The formatting rules for those fields lived only in internal sources: the parser (`projects-meta-mcp/src/lib/status-md.ts`), the writer (`status-md-writer.ts`), and the ops runbook (`.common/.wiki/concepts/agents-task-runner-ops.md`).
The wiki is internal; **skills ship with `factory` to external users**. An external operator pointing the poller at their own board has no access to the wiki or the MCP source — so the on-disk task-block format had no public, copy-pasteable reference. `task-format` is that reference.
## Scope — and why it's a separate skill
Three adjacent skills, deliberately not merged:
- **`delegate-task`** — workflow for creating a task for *another* project/agent via `mcp__projects-meta__tasks_create`. The tool emits the field format for you; the skill is the pre-flight gate + body template.
- **`using-tasks`** — policy for *working* an existing board (claim / switch / close / per-task files).
- **`task-format`** (this skill) — the **byte-level field format** the poller parses, for *hand-edited* STATUS.md blocks and for understanding what `tasks_create` produces.
A hand-edit scenario triggers none of the other two: `delegate-task` is about the MCP tool, `using-tasks` is about board mechanics, neither documents the exact header regex / Weight vocabulary / Notify line. Hence a focused reference skill.
## Ground truth (sources of record)
- Header regex `TASK_HEADER = /^##\s+(\S+)\s+\[([^\]]+)\]\s+—\s+(.+)$/u` and all `**Field:**` regexes — `status-md.ts`.
- Canonical field order and the writer — `status-md-writer.ts` (`formatTaskBlock`).
- Claim gate: only `weight === 'needs-human'` is excluded at claim; capability/runtime gates — `claim.ts` `selectClaimableTask`.
- **Missing-Weight behavior:** the claim gate does *not* reject a weightless task, but the fleet router (`fleet-router.js` `resolveBackend`) finds no backend for an `undefined` tier, so the poller parks it to 🔵 blocked (`no backend for weight_tier: unknown`) and inboxes Notify. Net effect — confirmed by source, not folklore — a task without Weight does not run. The skill states this as the operative rule.
- Notify resolution + inbox write — `crossProjectAgentPoller.js` `makeInboxWriter`.
## TDD record (per `superpowers:writing-skills`)
**RED** — 3 baseline subagents, no skill, asked to author a poller-claimable STATUS.md block (ordinary work ×2, critical-infra ×1). Failures: 2/3 used `### `/bullet-list headers the parser cannot recognize as a task at all; 2/3 omitted `**Weight:**` entirely (invented `risk: low`, `tier: L`, `claimable-by`); 2/3 put the notification in prose instead of a `**Notify:**` field; 1/3 used 🟢 (done) for a ready task. The one partial success only got Weight/Notify right because it *read the board* and found the spec — a crib an external user lacks.
**GREEN** — 2 fresh subagents with the skill loaded, same scenarios. Both produced parser-valid blocks: correct `## ⚪ [slug] —` header, `**Field:**` lines, `**Weight:**` + `**Notify:**`. The critical-infra agent correctly chose `**Weight:** needs-human` in canonical vocabulary (baseline had invented `tier: L` / `auto: ❌`).
**REFACTOR** — no new format loopholes surfaced; the skill maps every documented RED failure to a Common-mistakes row.
## Decisions
- **Version 0.1.0** — new skill; project-discipline Rule 3 first-version clause (matches `delegate-task` starting at 0.x).
- **Reference skill, ~900 words** — exceeds the <500 word target for frequently-loaded skills, justified: it loads only when authoring/editing a task block, and a field reference needs the full table to be useful.
- The `needs-human` critical-infra list mirrors `delegate-task` pre-flight Q0 and the ops runbook's "Critical-infra защита" — kept consistent on purpose.

View File

@@ -48,6 +48,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
- [using-tasks-status-archival.md](concepts/using-tasks-status-archival.md) — `using-tasks` v1.3.0 done-task archival rule (≥10 🟢 → `.tasks/archive/YYYY-MM.md`) fixes STATUS.md bloat; documents why `tasks_get_status` (single-task, by slug) / `tasks_aggregate` (cross-project cache) can't replace the orientation board-read, so the literal task instruction was not followed
- [delegate-task-negative-trigger-fp.md](concepts/delegate-task-negative-trigger-fp.md) — `delegate-task` v0.2.1 FP fix: «создать задачу себе» stem-matched the «создать задачу на агента» positive trigger; abstract "does NOT apply when doing the work yourself" carve-out loses to literal stem-match under the 1%-rule → made the negative literal + routed (→ using-tasks). Verified pos 5/5, neg 4/5 (was 0/5)
- [using-markitdown-cli-migration.md](concepts/using-markitdown-cli-migration.md) — `using-markitdown` v1.0.0→v1.0.1 (PATCH): rewrote from the Docker-based `mcp__markitdown__convert_to_markdown` MCP tool to the native `markitdown` CLI (0.1.6, on PATH); dropped the host→container `file://` mount caveat; container decommission is by image ancestor (`--filter ancestor=markitdown-mcp:latest`), not by the non-existent name `markitdown-mcp`
- [task-format-design.md](concepts/task-format-design.md) — new `task-format` skill v0.1.0: public reference for the on-disk `.tasks/STATUS.md` block format the poller parses (header regex, status emoji, `**Weight:**` / `**Notify:**` / `**Requirements:**`); ships with `factory` where the internal wiki/MCP-source can't reach; distinct from [[delegate-task]] (MCP-tool delegation) and [[using-tasks]] (board mechanics); RED 3-baseline / GREEN 2-verify per writing-skills; ground truth = `status-md.ts` + `claim.ts` + `fleet-router.js`
## Packages

View File

@@ -74,4 +74,5 @@ Parseable: `grep "^## \[" .wiki/log.md | tail -20`.
## [2026-06-09] decision | using-tasks-session-break — `using-tasks` 1.1.0→1.2.0 (MINOR): added the `session_break` marker. Task author sets `session_break: true | "<hint>"` in task frontmatter (mirrored as `**Session break:**` on the local board); after the task closes 🟢, before `tasks_claim_next`, an autonomous agent prints the verbatim line `🔚 SESSION BOUNDARY — [slug] закрыта. Рекомендую завершить текущую сессию. Следующий трек: [value | "см. STATUS.md"]` and stops instead of chaining the next task. Absent → behaviour unchanged. Enforced in Task completion step 6 + Rules bullet + format docs. Marker not heuristic: the stop-point is an authoring choice, not a runner guess.
## [2026-06-09] review | using-tasks-status-archival v1.3.0 — VERDICT PASS 3/3 (using-tasks-status-read-perf-review). Criterion «ориентация через `tasks_get_status`, не Read» is satisfied by a **validated deviation**, not a literal swap: re-verified against the live tool schema that `tasks_get_status(target_project, slug)→{status, found}` takes a required slug and returns ONE task — it cannot enumerate the board, so it cannot drive orientation; the implementer correctly rejected the impossible instruction and fixed the real problem (bloat→archival). No regression: orientation still reads local STATUS.md (Session start §2) and the «what's next» flow still reads the board — change is purely additive. Archival rule clear & complete (≥10 threshold, two trigger points, monthly append-only archive, verbatim blocks, dedicated commit, cross-referenced). One informational non-blocking note: this repo's own STATUS.md (>10 🟢) would itself trip the rule — dogfooding tracked separately as tasks-board-cleanup-2026-05. No follow-up tasks. Verdict appended to concepts/using-tasks-status-archival.md.
## [2026-06-09] decision | delegate-task-review-weight — `delegate-task` 0.2.2→0.2.3 (PATCH): Step 5 (paired `<slug>-review` task) now sets an explicit `weight`, inherited from the impl-task with a `needs-claude` floor (impl `needs-human`→review `needs-human`; `needs-claude`→`needs-claude`; `cheap-ok`→`needs-claude`). Root cause of commit `c0af151` ("add Weight: needs-claude to 4 review tasks — reconciler was skipping them"): the authoring skill omitted `weight` on review tasks, making them invisible to fleet routing. Floor (not pure inheritance) chosen to stay internally consistent with the skill's own "What NOT to do" bullet that forbids `cheap-ok` for review tasks — a `cheap-ok` impl would otherwise propagate a forbidden `cheap-ok` review. Added a What-NOT-to-do bullet against weightless review tasks. Concept page concepts/delegate-task-review-weight.md + index. TDD N/A (markdown policy artifact).
## [2026-06-11] decision | task-format — new skill v0.1.0: public reference for the `.tasks/STATUS.md` task-block format the autonomous poller parses. Motivation: the field rules (`**Weight:**` capability/cost tier, `**Notify:** <owner>/<repo>` inbox target, header regex, status emoji) lived only in internal sources (`projects-meta-mcp/src/lib/status-md.ts` parser + `status-md-writer.ts` + `.common/.wiki/concepts/agents-task-runner-ops.md`); skills ship with `factory` to external users, the wiki/MCP-source don't. Scope kept distinct from delegate-task (creates tasks for others via `tasks_create`, the tool emits the format) and using-tasks (board claim/close mechanics) — task-format is the byte-level field reference for hand-edited blocks. Ground truth verified against source: header `/^##\s+(\S+)\s+\[([^\]]+)\]\s+—\s+(.+)$/u`; Weight ∈ {cheap-ok, needs-claude, needs-human}; claim gate excludes only `needs-human` (`claim.ts`), but a *missing* Weight finds no backend tier (`fleet-router.js` resolveBackend) → poller parks to 🔵 blocked, so Weight is operatively required for pickup. TDD per writing-skills: RED = 3 baseline subagents w/o skill (2/3 used `###`/bullet headers the parser can't recognize, 2/3 omitted Weight inventing `risk`/`tier`/`claimable-by`, 2/3 put notify in prose, 1/3 used 🟢 for ready); GREEN = 2 fresh subagents w/ skill, both parser-valid incl. correct `needs-human` for the critical-infra scenario; REFACTOR = no new loopholes. Reference skill ~900 words (loads only when authoring a task block). Concept page concepts/task-format-design.md + index. Not yet installed to `~/.claude/skills/` or added to hermes mapping — deferred follow-up (mirrors using-system-snapshot deployment-scaffold note).
## [2026-06-09] decision | using-markitdown-cli-migration — `using-markitdown` 1.0.0→1.0.1 (PATCH): rewrote the skill from the Docker-based `mcp__markitdown__convert_to_markdown` MCP tool to the native `markitdown` CLI (v0.1.6, on PATH). Tool block now `markitdown <path|url>` → stdout (or `-o file`); removed the whole "Docker-mount caveat (READ FIRST)" section (host→container `file://` translation + `[Errno 2] /c:/Users/...` symptom are gone — CLI sees the full host FS). Updated the ingest pattern (use `-o` straight into `.wiki/raw/`), the gotchas table (`command not found` → check `markitdown --version`, install `pip install markitdown[all]`; dropped the MCP "tool not available / ToolSearch" row), and the contrast-table header (CLI, not MCP). Description frontmatter (the WHEN-to-use triggers) left unchanged. Container decommission: the task's literal `docker stop/rm markitdown-mcp` had no target — no container is named that; the MCP spawns anonymously-named containers from `markitdown-mcp:latest` per session (3 had piled up). Removed all by image ancestor (`docker rm -f $(docker ps -aq --filter "ancestor=markitdown-mcp:latest")`), verified none remain. Left the `mcpServers.markitdown` entry in `~/.claude.json` untouched (out of scope; a container will respawn next session until it's deregistered — flagged as a follow-up). Concept page concepts/using-markitdown-cli-migration.md + index. TDD N/A (markdown skill).

View File

@@ -0,0 +1,95 @@
---
name: task-format
version: 0.1.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.
---
# 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`.
## Canonical block (copy this)
```markdown
## ⚪ [my-task-slug] — One-line description of the work.
**Status:** ready
**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-06-11 -->
---
```
## The two load-bearing rules
1. **Header must match exactly:** `## <emoji> [<slug>] — <description>`
- `## ` (h2, two hashes) — **not** `### `, not a bullet.
- One status **emoji**, then `[slug]` in square brackets, then ` — ` (space, em-dash `—`, space), then the description. A `-` hyphen or `:` will not match.
- Slug: short, lowercase, kebab-case, Latin.
- 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.
## 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:**` | `<owner>/<repo>` | Inbox target. Poller writes to that project's `.claude-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. |
`**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.
## Weight — the field that decides pickup
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)
| Mistake | Fix |
|---|---|
| `### Title` or a `- **id:**` bullet list | Use the exact `## <emoji> [slug] — desc` h2 header + `**Field:**` lines. |
| 🟢 for a ready task | 🟢 is *done*. Ready is ⚪. |
| 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:** <owner>/<repo>` 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. |
## Verify
After editing, the block is correct when: header is `## <emoji> [slug] — …`, the emoji matches `**Status:**`, 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:**`.