Introduction

OverviewArchitectureAgent Experience

The product

This repository

Structure

Usage

Other

Concepts

Tasks

The Task record, the task DAG, and the state machine every status change passes through

Not built yet. There is no Task table. packages/database still ships the single stub model inherited from the template this repository forked, and no service layer validates the transitions below. This page describes the intended shape, taken from spec/01-domain-model.md.

A Task is the unit of intent: one thing a human or an agent wants done. It is the most important table in the system. Everything else in the domain either points at a Task or is produced by working one.

Record conventions

These apply to every entity in the domain, not only Tasks.

ConventionRule
IDsULID primary keys, prefixed per entity (tsk_01J…), lexicographically sortable. No sequential integers are ever exposed.
SlugsEvery user-visible entity carries a stable slug, unique per workspace. /tasks/tsk_01J… and /tasks/fix-login-redirect both resolve.
TenancyEvery row carries workspaceId. No cross-workspace read is possible, including for agent tokens.
VersioningEvery mutable row carries version int, bumped on write and surfaced as an ETag. A write may pass If-Match; a mismatch is 409 conflict_version, never a silent overwrite.
ProvenancecreatedByType (user, agent, system) and createdById, plus the same pair for updatedBy. Nothing is anonymous.
Soft deletearchivedAt. Rows are never hard deleted, because agents must be able to read history.
TimestampsUTC, ISO-8601 on the wire.

Project

A Project groups Tasks. It links to a GitHub repository (owner/name), a default branch, a board, and a docs root. Routing and filtering both read it: an agent asking for work in one repository filters by project.

Task fields

FieldNotes
titleOne line, imperative.
briefMarkdown. The full agent-readable statement of work.
acceptanceCriteria[]Checkable assertions. A task cannot reach done with any unchecked.
statusSee the state machine below.
priorityp0, p1, p2, p3. Claiming picks the highest-priority ready task.
projectId, parentTaskIdPlacement in the tree.
dependsOn[]Edges of the task DAG.
assignedAgentId, requestedByUserIdWho works it, who wants it.
labels[]Mirror of the board labels.
externalRefs[]{kind: github_issue | github_pr | url, ref}.
leaseId, leaseExpiresAtSee approvals and leasing.
contextRefs[]Documents and Artifacts the agent must read before starting.

The task DAG

Tasks relate in two independent ways, and both matter to scheduling.

  • parentTaskId builds a tree: an epic and the tasks that decompose it. It answers "what is this part of".
  • dependsOn[] builds a DAG: task B cannot start until task A is done. It answers "what has to happen first".

A task with unsatisfied dependencies is not ready, so a claim will not hand it out no matter how high its priority. Priority orders the ready set; the DAG decides what is in that set.

External references

externalRefs[] is how a Task stays attached to the world outside the record. Each entry is a kind and a reference: a GitHub issue, a GitHub pull request, or a plain URL. The state machine reads these. Moving to in_review requires an externalRef of kind github_pr, which is the mechanism that stops a task being marked reviewable when no pull request exists.

Task state machine

Statuses mirror the repository's kanban review pipeline exactly, so the board column, the label, the GitHub Project card and the database enum can never disagree.

FromToGuard
backlogtodonone
todoin_progresslive lease and an active Run
in_progressin_reviewan externalRef of kind github_pr
in_reviewchanges_requestednone
changes_requestedin_progresslive lease and an active Run
in_reviewready_to_mergethe acting identity must differ from the one that set in_review
ready_to_mergedoneevery acceptance criterion checked
any active statusblockednone
blockedthe status it leftnone
any statuscancellednone

Active status means anything other than done and cancelled.

Enforcement

These rules are designed to live in the service layer, not in the UI, so every door enforces them identically.

  • Transitions are validated against the table above. An illegal transition returns 422 invalid_transition, and the response body lists the legal ones.
  • ready_to_merge cannot be set by whoever set in_review. The implementer never promotes its own work.
  • done requires every acceptance criterion checked. An agent that verified nothing cannot close a task.
  • Every transition writes an Event in the same transaction. No exceptions.

Comments and blocking

Comments are a threaded human and agent conversation scoped to a Task. Agents post progress notes and questions there. A question posted with blocking: true and left unanswered moves the task to blocked, which is how a runner stops without pretending it finished.

Schedules

A Schedule is a recurring task template: a cron expression plus a Task payload to instantiate. It creates Tasks; it is not a status a Task can be in.