Single source of truth for task status. Flat, one line per task. Only unshipped work lives here (📋 designed · 💭 idea · ⏳ partial · 🛠 in-progress). Shipped work moves to CHANGELOG.md; design rationale lives in IMPROVEMENTS.md.
What this is. A CLI that owns writes to a project's roadmap, changelog, improvements and strategy files, so the format is a schema at the point of insertion instead of a convention an author is asked to remember — shipped as a Claude Code plugin, because the author to constrain is usually an agent.
The one law. A field limit enforced only by a reviewer is a limit discovered after the prose is written.
addrefuses an over-length field;lintrefuses a file that drifted anyway. The tool validates — it never writes prose.An entry here is one sentence: what + why +
→pointer — ≤320 characters, symptom in bold (what does not work), never a solution name. This file is the tool's own conformance fixture: iflintcannot pass it,lintis wrong.How to pick work: the lowest-numbered task whose
depsare all shipped.
Deliberately not built — check this list before proposing work:
- No web UI and no server. Files and a CLI. The store is the repository.
- No model and no prompts. The tool validates and renders; it never writes the symptom or the rationale. A generator would reintroduce exactly the prose drift this exists to stop.
- No enforced id scheme beyond
<prefix><n>. Non-contiguous, retired-never-reused is a property of real backlogs, not a defect to normalize. - No dates or quarters. A marker is maturity, not a schedule.
- No backlog in an issue tracker (Jira, Linear, GitHub Issues.) A backlog that lives
in a service is one an agent cannot
Grep; a one-way report about this tool, sent explicitly, moves nothing out of the files. - No multi-line task line. A task whose text wraps across paragraphs, with its deps
on a
↳line of their own, is a second grammar; reading only the first line would ship a truncated why and orphan the rest. - No supported Python API. The CLI, the MCP tools and the plugin are the surface; a
boundary held by a test inside the package is not one, so nothing ships
py.typedand a rename still breaks nobody. - No effort or size field. Nothing can verify a letter,
pick's every tier is a fact, and what an agent pays is context — median to p90, files vary 1.4× against lines 2.7×, so the letter prices the axis nobody pays.