diff --git a/.tasks/STATUS.md b/.tasks/STATUS.md index 1e8c611..b499aa7 100644 --- a/.tasks/STATUS.md +++ b/.tasks/STATUS.md @@ -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)._ --- -## 🔴 [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 + --- diff --git a/.wiki/concepts/task-format-design.md b/.wiki/concepts/task-format-design.md new file mode 100644 index 0000000..27f3c44 --- /dev/null +++ b/.wiki/concepts/task-format-design.md @@ -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. diff --git a/.wiki/index.md b/.wiki/index.md index 270c324..b2a6396 100644 --- a/.wiki/index.md +++ b/.wiki/index.md @@ -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 diff --git a/.wiki/log.md b/.wiki/log.md index 9549246..d80f73a 100644 --- a/.wiki/log.md +++ b/.wiki/log.md @@ -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 | ""` 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 `-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:** /` 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 ` → 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). diff --git a/skills/task-format/SKILL.md b/skills/task-format/SKILL.md new file mode 100644 index 0000000..6a922a2 --- /dev/null +++ b/skills/task-format/SKILL.md @@ -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 + + +--- +``` + +## The two load-bearing rules + +1. **Header must match exactly:** `## [] — ` + - `## ` (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:**` | `/` | 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 `## [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:** /` 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 `## [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:**`.