Skip to content

A Task is one unit of work with a hook-enforced contract — declaring which files it will touch before it runs, and blocked from finishing if disk state doesn't match.

Primitive

Task

The artifact

A row in task-list.json. Contract-shaped.

planner-workflows/add-oauth2/task-list.json

{"task_id": "P1-T1","subject": "Add OAuth2Provider type","assigned_to": "builder-product","layer": "schema",← dispatches verification"required_reads": ["AGENT_SYSTEM.md"],← gate: can't write until read"files_expected": [← contract with Stop hook{"path": "src/auth/oauth2.ts","op": "create","symbolsRequired": ["OAuth2Provider"]} ],"status": "pending"}

Subject + description alone is a request. layer + required_reads + files_expected is what turns a request into a contract.

What Stop actually checks

filesExpected → disk verification.

create

File exists on disk — presence check

modify

File exists AND ledger has ≥1 Write/Edit entry for it — agent actually touched it

delete

File does NOT exist on disk — removal check

symbolsRequired

grep -q SYMBOL FILE passes — the agent didn't skip it

symbolsForbidden

grep -q SYMBOL FILE fails — the agent didn't re-add it

Every op is a deterministic yes/no question. If the agent's self-report disagrees with the hook's check, the agent loses.

The description contract

Seven sections. Under 800 chars → rejected.

01READ FIRST

What to read before touching anything.

02CURRENT STATE

What exists now. What the agent will find.

03WORK ITEMS

Exact changes. File paths. Function names.

04ACCEPTANCE CRITERIA

Observable, binary. Pass/fail, not subjective.

05VERIFICATION

Commands to run. Expected output.

06OUTPUT LOCATION

Where the artifact lands. Exact path.

07TASK MANAGEMENT

task_update.py commands at start and completion.

⚠ Hook-enforced: if description < 800 chars, the task is blocked at creation.

The layer field is not metadata

Layer determines enforcement + companions.

schema

migration journal check

validator only

service

complexity_checker, async_checker

validator + silent-failure-hunter

route

async_checker

validator + test-creator

component

react_query_checker

validator + ui-tester

test

none (tests ARE the check)

validator only

Wrong layer means wrong commands fire, wrong companions spawn. Layer determines enforcement. It's a contract field, not a tag.

Size limit

Max 3 files per task. Past that — split.

scope anti-pattern

"This task touches 7 files but they're all related"

Related isn't a defense. When a task touches more than 3 files, the scope becomes ambiguous, the Stop hook verification becomes unreliable (more variables = more false negatives), and the agent can't hold the full change in its working context. Split it. 3 files max is not a guideline — it's the calibration point where agent-attention-budget and verification-reliability both still work.

The discipline

Self-reported completion is a claim. Disk state is proof.

The Task declares its files, its symbols, its layer. The hook reads disk at Stop. If the claim doesn't match reality, the task is blocked. Phantom edits become impossible; scope creep surfaces at completion, not review; and every "done" is verifiable. The contract is what separates a Task from a todo.