nool task boardWhy it matters
A task tracked in Nool is causally linked to the knots that closed it. "Done" means a specific, inspectable change landed — not just that someone updated a status field.
The lifecycle
Every task moves through Nool's core states. Acceptance criteria are checked at InReview (QA), not guessed at the end, and a task is VerifiedDone only once the knot it landed has been verified. Teams can lay their own stages over these with `[tasks.lifecycle]` (below).
- Open: unassigned, visible in the inbox.
- Claimed: picked up, not yet started.
- InProgress: active implementation work (Blocked while it waits on something).
- InReview (QA): acceptance criteria are checked here.
- Done: finished, tied to the knot that landed it.
- VerifiedDone: the landed knot passed the checks its criteria and paths require.
- Cancelled: dropped; it stays in the history.
nool task pick --id <id>
nool task start --id <id>
nool task qa --id <id>
nool task finish --id <id> --landed-knot <knot> --solidify
nool task verify-done --id <id> --landed-knot <knot> --solidifyYour own task stages
`[tasks.lifecycle]` in `nool.toml` lays your team's own stages over the core states, the way a Jira workflow does. Each stage maps to one core phase: `draft` (Open), `active` (Claimed, InProgress, Blocked), `landed` (InReview, Done), `verified` (VerifiedDone) or `terminal` (Cancelled). Transitions list the legal moves and the guards each one needs. Guards only add conditions: a task can never be moved to a stage whose phase differs from its real state, so no configuration lets work skip QA or verification. The definition is versioned with `nool.toml` (land it on its own, with `--justification`), and every move records which definition allowed it.
- `requires_linked_knot`: the move names a knot with `--linked-knot`.
- `requires_evidence` (`min_count`): the move names that many evidence knots with `--evidence`.
- `requires_role`: the signing key must hold the role through a grant (`nool admin team add`). Passing `--role` alone is refused.
- `wasm`: a policy decides, named by its file in `policies/`. `nool admin plugin build` writes underscores (`security_signoff_guard.wasm`), so use that name. A guard whose policy is missing refuses the move.
[tasks.lifecycle]
states = [
{ id = "triage", phase = "draft", label = "Triage" },
{ id = "building", phase = "active", label = "Building" },
{ id = "code_review", phase = "landed", label = "Code review" },
{ id = "security_signoff", phase = "landed", label = "Security sign-off" },
{ id = "shipped", phase = "verified", label = "Shipped" },
{ id = "wont_do", phase = "terminal", label = "Won't do" },
]
transitions = [
{ from = "", to = "triage" },
{ from = "triage", to = "building" },
{ from = "building", to = "code_review", guards = [{ kind = "requires_linked_knot" }] },
{ from = "code_review", to = "security_signoff", guards = [{ kind = "requires_role", role = "approver" },
{ kind = "requires_evidence", min_count = 1 }] },
{ from = "security_signoff", to = "shipped", guards = [{ kind = "wasm", policy = "security_signoff_guard" }] },
{ from = "triage", to = "wont_do" },
{ from = "building", to = "wont_do" },
{ from = "code_review", to = "wont_do" },
{ from = "security_signoff", to = "wont_do" },
{ from = "shipped", to = "wont_do" },
]Move tasks through your stages
Move a task with `nool task flow move`, alongside the core commands that change its real state: `task pick` or `task start` puts it in the active phase, `task qa` in the landed phase, and `task verify-done` in the verified phase. `nool task flow check` lints the definition and exits non-zero on a duplicate or unmapped stage, a transition to an unknown stage, an unreachable stage, or a stage with no path to a terminal one. That is why the example gives every stage a move to `wont_do`. An empty `from` means the first move only, not "from any stage".
- `nool task board` shows your stages as its columns.
- A refused move names the guard that failed, or says that the stage's phase does not match the task's real state.
- In `nool code`, a session bound to a task is finished only when your lifecycle lets the task move to QA. A refusal fails the completion check with the reason, and the agent tries again.
- `nool task show` lists each move with the definition digest and the `nool.toml` knot that allowed it.
nool task flow check
nool task flow show
nool task flow move --id <task> --to triage --solidify
nool task flow move --id <task> --to code_review --linked-knot <knot> --solidify
nool task flow move --id <task> --to security_signoff --role approver --evidence <knot> --solidify
nool task boardPick up tracked work
Find unassigned work or resume what you already own before starting something new.
nool task inbox
nool task mineAcceptance criteria
Criteria give QA something concrete to check, so a task's definition of done does not live only in someone's memory. Moving a task by hand is never blocked by them, but `nool code --task <id>` joins them to the completion check, and a headless `nool code --exec --task` refuses a task whose criteria are still draft or empty: review them first. A criterion with no check (`manual` or `pending`) is a wish: `nool task start` warns when none of a task's criteria has one, the criteria inbox lists such tasks, and `nool code --exec --task` refuses them unless `[tasks] allow_manual_criteria = true`. Finishing a task needs the knot that landed the work (`--landed-knot`).
nool task criteria set --id <id>
nool task criteria review --id <id>Keep a task in its lane: rails
Rails are paths a task's work may not touch, such as the tests that define done or a contract other teams rely on. While the task is InProgress, a proposal bound to it that changes a rail is refused at the seal with exit 2 (`TASK_RAILS`), naming each path, its rail and the task. A proposal is bound to every InProgress task assigned to its author and to each task named with `nool propose --task`; a `nool code` session on a task binds itself, and its writes to a rail are refused before they run. To move a rail anyway, a trusted reviewer other than the author attests `rail-amended` on the task, and the author proposes again.
- While a task has rails, policy bundles (`policies/`, `policy-bundles/`), rulesets (`rules/`) and CI definitions (`.github/workflows/`, `.gitlab-ci.yml`) are rails too.
- `--rails ""` clears a task's rails; edit rails on their own, not with --name, --desc or --priority.
- Naming another task never takes a proposal off its author's own rails.
- The reviewer's key must be trusted by the landed `[attestation]` config; an amendment covers the rails as they were when it was recorded.
- The DSL predicate `task_rails_untouched` carries the check to a task's completion. Where rails were not computed (push, ingest, doctor) it is unverifiable, never a pass.
- Knots that carry rails need Nool 7.24.0 or later to read.
nool task create --name "Fix the parser" --rails tests/,contracts/ --solidify
nool task edit --id <task-id> --rails tests/ --solidify
nool propose --path src/parser.rs --task <task-id> --intent "Fix the parser"
nool attest record --target <task-id> --checker rails --assertion rail-amended --verdict pass