Appearance
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.