tasks
CLI reference

Configuration

The .tasks/config.yml schema — statuses, roles, transitions, and the default phase scope.

Explanatory, not normative

The authoritative definition is specification › configuration. This page is the practical walkthrough.

.tasks/config.yml is optional. With no file at all, the CLI behaves as though you had written:

version: 1
statuses: [PENDING, IN_PROGRESS, DONE]
roles:
  ready: PENDING
  claimed: IN_PROGRESS
  done: DONE

tasks init scaffolds a commented version of this so the options are discoverable without leaving the repo.

Schema

.tasks/config.yml
version: 1 # config schema version

active_phase: auth-rework # optional; default scope for `list` and `ready`

statuses: [TODO, DOING, REVIEW, SHIPPED] # optional; minimum 2 entries

roles: # optional; defaults to first / second / last
  ready: TODO
  claimed: DOING
  done: SHIPPED

transitions: # optional; REPLACES the default step rule
  - [TODO, DOING]
  - [DOING, REVIEW]
  - [REVIEW, SHIPPED]
  - [SHIPPED, DOING]

Prop

Type

Unknown keys are rejected. A typo like status: fails the load with exit 2 rather than being silently ignored.

active_phase

Sets the default scope for tasks list and tasks ready:

active_phase: auth-rework

--phase overrides it; --all ignores it entirely. Resolution order is --phase--allactive_phase → the whole tree.

A missing task is usually a scope

If a task you expect is absent from list or ready, retry with --all before concluding it does not exist.

statuses and roles

Statuses are fully renameable because commands bind to roles, not literals:

RoleUsed byDefault
readyWhat tasks ready looks for, and where tasks release returns a taskfirst status
claimedWhat tasks claim moves tosecond status
doneWhat satisfies another task's depends_onlast status

A minimum of two statuses is required. Beyond that the list is free — see custom statuses for worked examples.

transitions

Omit it, and the default rule applies: step forward or back by exactly one position in statuses, uniformly.

Provide it, and that rule is replaced entirely — not layered onto. Every legal move, including every backward one, must be listed:

transitions:
  - [TODO, DOING] # claim
  - [DOING, TODO] # release
  - [DOING, REVIEW]
  - [REVIEW, DOING] # changes requested
  - [REVIEW, SHIPPED]
  - [SHIPPED, DOING] # reopen

Forgetting [DOING, TODO] here would leave tasks release permanently failing with exit 4. If you write transitions, walk the whole graph.

Validation

The config is validated on load, and a bad one fails the command you ran with exit 2 rather than surfacing later as a mysterious conflict:

  • Every name in roles must be a real status.
  • Every name in transitions must be a real status.
  • roles.ready → roles.claimed must be a legal transition. A config where it is not would make tasks claim unusable by construction, so it is refused outright.
config.yml: the transition TODO -> REVIEW (roles.ready -> roles.claimed) is not legal,
so `tasks claim` could never succeed. Add it to `transitions` or adjust `roles`.

Changing config on a live tree

Renaming a status does not rewrite existing task files. Tasks still carrying the old name become unknown-status findings in tasks validate, which --fix cannot repair — it is not mechanically safe to guess what the old name should map to.

The safe order is:

Add the new status names alongside the old ones and ship that.
Move each task onto a new status with tasks status.

Remove the old names from statuses once tasks validate is clean.

For a small tree, a search-and-replace across .tasks/**/*.md followed by tasks validate is faster and perfectly legitimate — the frontmatter is only machine-owned, not machine-only.

On this page