TODO Format Contract
Agent-created todo Format Contract
Section titled “Agent-created todo Format Contract”A todo issue is a human action item an agent hands back when it hits a
human-only blocker (a decision timeout, an escalation, a missing credential).
For the Human Operator to act on it without reading any session log, every
agent-emitted todo must be self-contained. This is the contract that makes
that guarantee — and the basis for the groom compliance check (#777) and the
downstream completed lifecycle (#775, see Work Tracking → TODO lifecycle).
Validator (single source of truth): ~/.claude/scripts/warp-drive/todo-contract.js
— check one issue or audit every open todo. groom and warp-drive both call it
so the rule lives in exactly one place.
The contract
Section titled “The contract”Every agent-emitted todo body MUST contain:
| # | Element | Requirement |
|---|---|---|
| 1 | Summary | A one-sentence statement of what is blocked and why, as the first line of the body. |
| 2 | Instructions | Numbered, self-contained steps the human can follow without external context (1. / 2. / …). |
| 3 | Issue link | At least one explicit #NN reference. Use Blocked by #NN when the todo gates a specific issue, so downstream tooling knows what to resume. |
And the issue MUST carry:
| Element | Requirement |
|---|---|
| Assignee | --assignee paulirv (the Human Operator) so it surfaces in todo + assignee:@me discovery (#778). |
| Priority | One of p1-critical / p2-high / p3-medium / p4-low. |
| Label | todo (plus warp-drive when filed by the loop). |
Canonical shape
Section titled “Canonical shape”gh issue create \ --title "TODO: {what's needed}" \ --label todo,warp-drive \ --assignee paulirv \ --body "$(cat <<'EOF'{One sentence: what is blocked and why.}
## Instructions1. {Self-contained step.}2. {Self-contained step.}
Blocked by #NNEOF)"Add a priority label at creation (or immediately after): --label todo,warp-drive,p2-high.
Non-conformance → needs-clarification
Section titled “Non-conformance → needs-clarification”A todo that is missing instructions or an issue link is not actionable. The
groom reconciliation pass adds the needs-clarification label to such todos
rather than treating them as ready work.
A needs-clarification todo is:
- excluded from “ready to complete” — it is not a candidate for the
completeddone-signal until it conforms, and downstream tooling (#779) must skip it; and - re-entered into a clarification loop — warp-drive’s next run surfaces
needs-clarificationtodos so the gap (missing steps or link) is filled, after which the label is removed and the todo rejoins the normal flow.
This keeps an under-specified handback from masquerading as an actionable item or as a resolvable blocker.
Exempting a todo from the stale sweep
Section titled “Exempting a todo from the stale sweep”The groom stale sweep (todo-consume.js stale, groom §5d)
flags a todo whose linked issues are all closed, on the reasoning that the work
it gated is gone. That is a proxy, and it is wrong whenever an issue closes for a
reason unrelated to the human action still pending — the todo is then a live action
item flagged as dead work.
Mark such a todo with a not-stale marker anywhere in its body:
<!-- not-stale: 2026-08-17 outage is still live; #466 closed for unrelated reasons -->planStale() tests for the marker before the linked-issue-state test and before
the stale label check, and reports the todo as pinned-not-stale. The sweep prints
an EXEMPT #NN line naming the date and reason, so an exemption is visible in the
sweep output rather than a silent skip.
Shape: <!-- not-stale: YYYY-MM-DD reason --> — an ISO date, then a
one-line reason. Both are for the human reading the body later; the parser is
deliberately permissive, so a malformed or undated marker still exempts the todo. A
safety valve must not be disarmed by a typo.
When to use it. This is a deliberate, dated operator override, not a convenience — it suppresses a signal designed to stop dead todos accumulating. Use it when the human action is genuinely still required and the link-state heuristic cannot see that. Record why, and date it, so a later reader can judge whether the override still holds.
Why a marker and not a label. It is body-resident, so it survives label churn:
removing the stale label by hand does not restore re-flag eligibility, which was
the defect in #1663. It also
matches the convention the warp-drive scripts already use — <!-- approved-at … -->,
<!-- gated: … -->, <!-- flightplan … -->.
The sweep remains surface-only either way: it flags for a human to close, and closes nothing itself.
What the sweep could not check
Section titled “What the sweep could not check”A ref the sweep failed to read is not a ref it read and found open. Conflating the two is #1724: during the 2026-08-17 API wobble nine lookups returned HTTP 503, each collapsed silently into “not stale”, and the sweep signed off with “no stale todos — every open todo has at least one open linked issue”. It had not read most of the refs it was speaking for.
The sweep is forge health’s first consumer, and now reports what it could not establish:
- A todo whose refs could not all be read prints as
UNCHECKED #NN, naming the unreadable refs, distinct from a todo that was read and found to have open links. - Such a todo is never flagged stale — including when the readable subset is all closed. The old code flagged that case, which is a false positive, not merely a silent one: the unread ref could be wide open.
- The closing line states how many todos could not be fully checked instead of
asserting every link is open, and names the forge condition when it is not
operational. - An incomplete sweep exits
3— “there is something for a human to look at” — just as a flagged todo does.
An empty result may only be reported as an empty result when the lookups behind it succeeded.
Relationship to the completed lifecycle
Section titled “Relationship to the completed lifecycle”The format contract governs a todo’s birth; the completed label governs its
death. A conforming todo, once the human performs the action, gets completed
(the canonical done-signal) and downstream work resumes. A todo closed without
completed is cancelled/moot. See CLAUDE.md → Work Tracking → TODO lifecycle.