Task Lifecycle
In Backlog.md, every task is a standalone Markdown file that goes through a complete status flow from idea to final archive.
Status Flow
The full flow from creation to completion is:
Draft → To Do → In Progress → Done → Archived / Completed
| Status | Description |
|---|---|
| Draft | Draft state uses an independent ID space (e.g., draft-1) and does not consume formal task numbers |
| To Do | Default status for newly created tasks, waiting to start |
| In Progress | Marked manually when work starts, or updated automatically by an AI agent |
| Done | Work is complete; the task still remains in backlog/tasks/ |
| Archived | After running backlog task archive, moved to backlog/archive/tasks/; soft delete |
| Completed | After running backlog cleanup, Done tasks are moved to backlog/completed/ |
State Machine
The table above shows the default status list. The actual status list for a project is declared in backlog/config.yml under statuses, and supports a semantic object form:
| Field | Description |
|---|---|
name |
Status name (column label) |
category |
One of six categories: initial / active / wip / blocked / done / dropped, replacing the old "last position is terminal" convention |
exit |
Terminal-state exit action (e.g., archive) |
display |
When false, the board hides this column (tasks in it are hidden too) |
next |
Array of transition edges; each edge can declare when / requires / evidence / ai permissions |
Key points:
- Newly initialized projects use the built-in seven-column default state machine (To Do → Planning → Plan Review → In Progress → In Review → Done, plus the archival terminal state Dropped). The CLI
configcommand only hasget/set/listsubcommands; to restore the default state machine, click the Default button in the Web settings state-machine editor—the button only loads the default machine into the editor, and you still need to save for it to take effect - The default machine includes finalization gates:
In Progress → In Reviewrequires the task file to be finalized per task-finalization, andIn Review → Donerequires acceptance per task-finalization. New projects have this out of the box, no manual configuration needed - The state machine is declarative, not enforced: out-of-bounds transitions do not error, but the CLI/MCP guide (
backlog instructions overview) renders the full state table, categories, transition edges, and a "stop for human review" checklist, so AI agents work according to the declared machine - Legacy string-array configurations remain compatible; the settings page provides a visual state-machine editor for maintaining the object form
- For full semantics, see the wiki concept page State Machine Semantics
Task File Structure
Each task file begins with YAML frontmatter for structured metadata; the body records the task description, acceptance criteria, implementation plan, and other information.
---
id: back-10
title: "Task Title"
status: "In Progress"
assignee: ["@user"]
reporter: "@user"
created_date: "2026-05-06"
updated_date: "2026-05-06"
completed_date: "2026-05-06"
labels: ["feature", "backend"]
priority: high
milestone: "M1 - CLI"
dependencies: ["back-1", "back-2"]
references: ["https://docs.example.com", "src/api.ts"]
docs: ["doc-1"]
ordinal: 1000
type: feature
dueDate: "2026-05-20"
plannedStart: "2026-05-10"
plannedEnd: "2026-05-18"
actual_start: "2026-05-10 09:00"
actual_end: "2026-05-15 18:30"
parentTaskId: "back-4"
---
Core Field Reference
| Field | Description | Example |
|---|---|---|
id |
Unique task identifier; custom prefix supported | back-10, proj-42 |
title |
Task title, single-line text | "Implement user login" |
status |
Current status; must be in the project's config.statuses list |
"To Do", "In Progress" |
assignee |
List of assignees in @username format |
["@alice", "@bob"] |
reporter |
Creator | "@alice" |
priority |
Priority; optional high, medium, low |
high |
milestone |
ID or title of the assigned milestone | "M1 - CLI" |
dependencies |
List of IDs of tasks this task depends on | ["back-1", "back-2"] |
ordinal |
Custom sort weight; smaller values appear first | 1000 |
type |
Task type, e.g. bug, feature, enhancement, docs |
feature |
dueDate |
Due date (ISO format, date-only) | "2026-05-20" |
plannedStart |
Planned start date (ISO format, date-only) | "2026-05-10" |
plannedEnd |
Planned end date (ISO format, date-only) | "2026-05-18" |
actual_start |
Actual start time (UTC datetime) | "2026-05-10 09:00" |
actual_end |
Actual end time (UTC datetime) | "2026-05-15 18:30" |
parentTaskId |
Parent task ID; when present, this task is a subtask | "back-4" |
labels |
Label list | ["backend", "api"] |
references |
External reference links or file paths | ["src/api.ts"] |
docs |
Associated document IDs | ["doc-5"] |
Automatic Actual-Time Population
actualStart and actualEnd track when a task actually started and finished. The system auto-populates them under certain conditions:
- When a task status changes from any status to In Progress, if
actualStartis empty, it is set to the current datetime - When a task status changes to Done (or another terminal status), if
actualEndis empty, it is set to the current datetime - Creating a task with
--status "In Progress"or--status "Done"also triggers auto-population - Auto-population only runs when the field is empty; you can manually override it at any time
Changing Status
Via CLI
# Mark as in progress
backlog task edit <id> --status "In Progress"
# Mark as done (sets the terminal status, usually Done)
backlog task edit <id> --status "Done"
# Archive the task
backlog task archive <id>
Via TUI Board
Run backlog board to launch the terminal board; select a task card and use arrow keys or shortcuts to move it between status columns.
Via Web UI
Run backlog browser to launch the browser interface; drag and drop task cards to the target status column in the board view.
Via AI Agent (MCP)
AI agents can directly call the update_task tool to change task status without human intervention.
Duplicate Task ID Detection and Repair
Under normal circumstances, task IDs are guaranteed unique at creation time. However, cross-branch merges, zero-padding equivalence (back-1 vs back-01), external imports, or manual edits can produce duplicate task IDs, causing tasks to silently collapse in views, search, and editing.
Use backlog doctor to detect and repair duplicate IDs:
# Preview conflicts (lists conflict groups, file paths, planned renames, references needing human review)
backlog doctor
# Confirm the fix and discard .bak backups (finalize)
backlog doctor --commit
# Roll back the fix (restore .bak backups)
backlog doctor --rollback
Repair principles: only rename task files and the id in frontmatter, preserving content; renames and frontmatter updates are atomic; ambiguous structures are fail-closed and references are not guessed; operations are reversible (.bak backups are created), and both --commit and --rollback require human confirmation.
Ordinal Changes Do Not Affect updated_date
When only adjusting task ordinals (e.g., board reordering, bulk sorting), the task updated_date is not refreshed, avoiding meaningless Git diff noise. updated_date is updated only when task content or metadata actually changes.