Tasks and states
What a project and a task are, which lane and run-state combinations are valid, and how epics, drafts, and archiving fit in. For every field, see Shared files.
Projects
A project is a unit of work with a name and an immutable ProjectId, a 32-character lowercase hexadecimal string generated at creation. Each project owns exactly one board; there is no cross-project board and no moving or copying tasks between projects.
- A name is 1 to 50 Unicode scalar values after trimming, on one line, and unique by exact, case-sensitive match. Project lists are sorted by name.
- Rename and
initkeep the ProjectId. A deleted ProjectId is never reused, so a project re-created with the same name is a different project. - Task IDs, lane positions, and EPIC-IDs are scoped to a project. The target project is never inferred from omission, the working folder, or the web selection.
nextTaskIdstarts at 1 and only increases, even across deletion andinit. A number reserved by a failed creation stays unused.initkeeps the ID, name, andnextTaskId, and empties the project's tasks and epics. Deleting a project removes its whole folder and touches no other project.
Change detection uses three values. version is computed from one project's source files and has no order. catalogVersion does the same for the project list. A cursor (f1:<ProjectId>:<version>) is what wait uses; it follows the same ProjectId across renames and never transfers to another project.
Lanes and run states
A task's lane says where the work is; its run state says what the agent is doing about it. Not every combination is valid:
| Assignee | Lane | Valid run states |
|---|---|---|
| ai | todo | idle, pending |
| ai | doing | idle, running, pending |
| ai | done | idle only |
| human | any | idle only |
- Running is self-reported, not liveness monitoring. It is never reset automatically, and agents do not change it just because a session started or paused.
- Pending means the agent is waiting for a person's decision; it may continue other tasks meanwhile.
- Invalid combinations are never saved. A draft task is Idle or Pending in any lane.
How operations move a task between states:
- Create puts the task in Todo, Idle, at the end of the lane, and records a creation entry. Without a body, the product writes an empty
acceptanceand an empty body; a supplied body must pass frontmatter validation. - Lane move requires
actor;reasonis optional. The task goes to the end of the target lane. A real move resets the run state to Idle, withdraws any open request (a withdrawal is not an answer), appends history, and updatestaskStatusChangedAt. Moving to the same lane changes nothing. - Run state change requires
actorand keeps the lane. AI Todo allows Idle↔Pending; AI Doing allows changes among Idle, Running, and Pending. Re-reporting the same state is not a change. - Edit changes only the title, body, and acceptance conditions; the assignee never changes. CLI
--desc/--desc-filetake the whole file but keep the history of the latest storedTASK.md.epic edit --document-filereplaces the wholeEPIC.mdtext. The web UI sendsbodyandacceptance, applied to the latest file under the lock. - Epic membership sets or clears
epicId; only real changes append history. People can change it on draft and archived tasks. - Delete removes the task folder. The web UI deletes only archived tasks; the CLI asks for terminal confirmation.
Ordinary updates are last-write-wins: there is no content check or edit lock. Only answer matching, AI writes to drafts, writes to archived tasks, and bulk-archive targets are validated against the latest task.json under the write lock.
Epics and priority
An epic is a management unit that groups tasks and sets their work order. Its details (EPIC.md) are Markdown notes on its goal, scope, and decisions. A task belongs to at most one epic. The task's epicId is the only record of membership; the epic keeps no list of its tasks.
| Field | Rule |
|---|---|
id | EPIC-ID: 1 to 64 characters matching [A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*. Lowercase input is uppercased. Immutable. |
name | 1 to 100 characters after trimming, one line. |
color | #RRGGBB, uppercased. Random at creation when omitted. |
isDraft | Marks an epic that is still being prepared; member tasks are not affected. |
document, body | The whole EPIC.md text, frontmatter included (0 to 100,000 characters), and the body without frontmatter. |
priority, priorityError | Member task IDs in work order, and whether reading them failed. |
- Tasks store only
epicId; the label color and name are resolved when read. - An epic referenced by any task, archived ones included, cannot be deleted (
epic_in_use). The web UI deletes an epic from the epic editor throughDELETE .../epics/{epicId}; the CLI usesepic rm. - A new project starts with the default epics
BUGandENHANCEMENT. They are ordinary epics: they can be edited and deleted.defaultEpicsSeededinproject.jsonis set once the project has been offered them, so a deleted default epic is not created again.serveoffers them once to a project that does not have the flag yet. - Epics have no managed acceptance conditions. Reference conditions are ordinary Markdown in the body; the API rejects
acceptanceinput for epics. priorityis a list of task IDs in theEPIC.mdfrontmatter, for examplepriority: [24, 26, 25]. Duplicates or invalid types are save errors. IDs that are no longer members are hidden and dropped on the next save; unlisted members follow in creation order. Changing priority does not count as editing a Done task. Lane positions never carry priority.
Drafts
A draft is a task a person is still writing.
- People toggle
isDraftin the web UI. Only Idle or Pending tasks can become drafts; Running is refused. A real change appends history but notupdatedAt. - CLI
edit,mv,state, andhistory addcheckisDraftunder the write lock and fail withtask_is_draft. Reads,add, and people's web operations are not affected. Drafts never expire. - Web editing accepts only draft tasks. With
finalize, the body, title,isDraft=false, and a history entry are committed as one pair. - The product cannot stop direct edits of a draft's
TASK.md; the README and the agent skill tell agents not to.
Archive
- Archiving keeps the lane,
isDraft,epicId, and position; resets the run state to Idle; withdraws the request; and updatesupdatedAt. The lane andtaskStatusChangedAtdo not change. Web archive and restore record the fixed reasonsArchived by user.andRestored by user. - Restoring places the task at the end of its original lane.
- Normal snapshots,
ls, and the hook return unarchived tasks only;show IDalso shows archived ones. Writes to archived tasks fail withtask_archived, but their images remain readable. The archive list is sorted byarchivedAt, newest first.
Ordering and time
- On the desktop board and in the CLI, Todo and Doing sort by ascending position and Done by descending position. The mobile Done list sorts by
taskStatusChangedAt, newest first. Completion order is never inferred from history. APItaskscome in ID order; the UI sorts them for display. Epics sort by EPIC-ID. - Stored and JSON times are UTC strings in exactly
YYYY-MM-DDTHH:MM:SSZ; offsets (even+00:00) and fractional seconds are rejected. The CLI displays local time of the machine, the UI that of the browser, asMM/DD HH:mm.

