GTD Task Management

The GTD pack manages work as task notes. A task has a lifecycle, a priority, and an optional assignee; it can also be connected to the rest of the knowledge graph. Use it to capture work, decide what is ready, record work in progress, and retain the outcome.

Calls go through request using the function-call DSL. For the enclosing call format and batching rules, see the request tool rustdoc.

Lifecycle

The normal path is:

inbox -> next -> active -> done
                          \
                           -> cancelled

inbox is untriaged work. Move work to next when it is ready to be picked up, then to active when work starts. waiting holds work blocked by something outside the task, and someday keeps work that is deliberately deferred.

The pack validates each requested transition with its lifecycle rules. A task can move among the non-terminal states only where that rule permits it. done and cancelled are terminal: create a new task if work needs to be reopened.

Capture and assign work

Create a task with gtd.assign. It defaults to status="inbox" and priority="p2"; p0 is the highest priority. The optional assignee is an opaque identifier used to route and filter work. Use one stable identifier for each queue.

request(ops="gtd.assign(title=\"Triage documentation feedback\", assignee=\"docs-maintainer\")")

The response includes the task identifier needed by later operations. A task can also have a description, context entity, due/start/end dates, tags, and dependencies.

Choose the next task

Use gtd.next to read the actionable queue. It considers only next and active tasks, sorts them by priority (p0 first), and can filter by exact assignee. It defaults to limit=10 and silently clamps limit to 1–200. If more than 20,000 actionable tasks match, it returns an error; narrow the query (for example with the exact assignee filter) and retry.

By default it omits tasks with unfinished or structurally broken dependencies. Pass include_blocked=true to include those candidates after ready work for triage. Both gtd.next and gtd.tasks annotate tasks with dependency_state, actionable, and blocked_by diagnostics.

request(ops="gtd.next(assignee=\"docs-maintainer\", limit=10)")

Use gtd.tasks when reviewing work by status, assignee, or priority. Both gtd.tasks and gtd.next accept an assignee filter. Without a status filter, gtd.tasks shows non-terminal work; pass a terminal status when reviewing completed or cancelled tasks. It defaults to limit=50, offset=0, and silently clamps limit to 1–200.

Start and finish work

Use gtd.transition for an explicit lifecycle change. This chained request creates a ready task and starts it, using the identifier returned by the first operation:

request(ops="gtd.assign(title=\"Review the task guide\", assignee=\"docs-maintainer\", status=\"next\") | gtd.transition(id=$prev.id, status=\"active\", note=\"started review\")")

gtd.transition validates the lifecycle with can_transition before writing. A repeated transition to the current status is a no-op. gtd.complete uses the same lifecycle table for a terminal transition, records completed_at, and can mark any non-terminal task done (the default) or cancelled.

Successful state changes include audit_persisted. A value of false means the task state committed but the best-effort lifecycle-audit append failed; alert or reconcile it rather than assuming the audit row exists.

When gtd.transition is a no-op, branch on transitioned: when it is false, the base fields are transitioned, id, full_id, from, to, and note. On canonical dispatch, supplying a transition note also adds note_recorded and, if that guarded note write succeeds, audit_persisted. Atomic v1 uses a guarded no-effect assertion for same-status plans and does not persist a supplied note; use canonical dispatch when that note event matters.

Dependencies

Pass task identifiers in depends_on when creating a task to express blockers. The GTD pack adds a depends_on endpoint rule for task-to-task edges; other note or entity types are not valid dependency targets. gtd.next omits a task until every listed dependency is done. A dependency with blocked_by[].state of cancelled, soft_deleted, missing, invalid, different_namespace, or wrong_kind makes the task broken; an unfinished live task makes it blocked with a state of pending. Dependency writes reject direct and transitive cycles on both generic task-property updates and graph links.

Gotchas

  • An assignee is a routing field, not an automatic personal queue. Always pass your assignee to gtd.next or gtd.tasks; a task assigned to a different identifier is not work to take without coordination.
  • done and cancelled cannot transition again. Capture follow-up work as a new task instead of trying to reopen a terminal one.
  • gtd.complete may finish any non-terminal task directly. It still rejects a task that is already done or cancelled.

See also


Raw markdown for this page: /md/tasks.md