← Skills

spec

spec

When a sizeable task has arrived as a sentence and has to become work somebody can finish — the eight spec fields, with deliverables as ROWS a machine can turn into child tasks. Use when the user or an agent says "spec this", "write the spec", "break this into deliverables", "what are the child tasks", "this task has no proof", or when a FEATURE/SCHEMA-tier task reaches the board carrying prose notes. For deciding the SHAPE of a change, see architecture-review. For sizing it, the sizer answers first. For asking about the holes a spec already knows it has, see interview.

Spec

You turn a sentence into work somebody can finish. The output is eight fields,
in order, and the sixth is a JSON array — not a list, not bullets, an array.

Why the shape matters more than the prose. A spec that arrives only as prose
is a status field. Rows spawn child tasks (tasks:subtask writes each one with
its containment edge to the parent); bullets spawn nothing. Measured
2026-09-03: eleven tasks were created with long, specific prose notes, and not
one field of those notes was machine-read — the board handed back all ten
children at once, ready, with nothing to say when any of them was done.

The output — exactly this, in this order

Every field is one line beginning <Label>: at the START of a line. A sentence
that merely mentions a proof is not a Proof: row; the parser
(one.ie/web/src/lib/factory/spec-gate.ts) anchors on the label and nothing
else.

Working on: <the big picture this sits inside>
Who it's for: <the actor who receives the output> so they can <what it enables>
Intent: <what changes in the world, in the task's own terms>
Why: <what it costs to NOT do this>
Definition of done: <the observable state after, written as a claim>
Deliverables:
[
  {"title": "<one thing that will exist>",
   "notes": "<the goal of this child, written for whoever claims it — files it touches, what done looks like>",
   "files": ["<repo-relative path>"],
   "blockedBy": ["<the title of a sibling that must land first>"]}
]
Tests: <what could actually break, and what that would look like>
Proof: <one command; its exit code is the verdict>

The eight fields, and why each is there

Field What it is Why
Working on The big picture this sits inside a task with no context gets built literally, and literal is how you get a correct answer to the wrong question
Who it's for The actor who receives the output, and what it enables this is the line that says when to stop. Without it, "done" is wherever the doer got bored
Intent The goal in the task's own terms the title is a label; this is what the label points at, and they drift fast
Why What it costs to not do this the cheapest cycle is the one nobody runs. If the cost of doing nothing is hard to write, that is information
Definition of done The observable state after, as a claim a claim can be checked. An activity ("refactor X") can only be declared over
Deliverables One ROW per thing that will exist a deliverable that creates nothing underneath it was an opinion with an ID
Tests Written by whoever does the work, at the moment they do it the doer is the only one who knows which line could quietly go wrong
Proof One command. Exit code is the verdict everything above is a claim by the author. This is the one row that is not

Hard rules

  • Deliverables: is a JSON array or the spec is refused. Bullets, a
    numbered list, a table, or one row of prose all read as ZERO rows downstream —
    the fan-out over $step.spec.deliverables refuses a value that is not an
    array and the run fails. That is deliberate: a spec that produced no rows must
    not look like a spec that produced some.
  • Every row carries a title and a notes. A child created with an empty
    body is claimable-but-unbuildable — the window notes exists to close.
  • blockedBy names a SIBLING'S TITLE, never an id. Nothing here knows the
    ids of tasks that do not exist yet. The titles are how a human or a later step
    reconstructs the order; a row with no prerequisite carries [].
  • Write no label-shaped line inside a value. A line beginning Tests: inside
    a notes string ends the deliverables field where it stands.
  • The proof must be able to lose. A command that cannot go red is decoration
    with a green tick. If the honest answer is that no command can judge this,
    write Proof: not applicable, because <reason> — a known unknown the board can
    name is worth more than a box ticked to satisfy a validator.
  • Say when a field does not apply, and why. not applicable, because … is an
    answer. A sentence written to fill a form is not.
  • Name the gaps rather than inventing answers. If the sentence is too thin to
    yield a Definition of done, say so and stop. A spec built on a guessed goal
    costs more than the turn spent asking.

Out of scope

  • Deciding the shape of the change — that is architecture-review, before this.
  • Writing the code, or the tests themselves — the doer writes both, at the moment
    they do the work.
  • Sizing. The sizer (factory:size) answers first, from paths; a sentence never
    sizes a diff.
  • Creating the child tasks. This emits the rows; the workflow's fan-out step
    writes them with tasks:subtask, one call per row.