Skip to content

How It Works

The board column is a contract boundary

Everything trkr does hangs off one idea: off-board is human territory, on-board is daemon territory.

  • Off-board: intake, classification, grilling, spec-writing. A ticket only boards when it is "agent-sufficient" — a clear spec with independently checkable acceptance criteria and no open questions.
  • On-board: the daemon owns the pipeline, with three human touchpoints. You start a ticket by dragging it out of the inert Backlog column into its first stage's working column (every preset's first stage is manual); from there every transition is automatic. Mid-pipeline the only touchpoint is the trkr:blocked label (pull-based — you come to it). At the end, the ticket lands in Done with your review requested on the PR — you merge.

Anatomy of a ticket

A ticket is a GitHub issue on a Projects v2 board with two single-select fields:

  • Status — the built-in field; its options are trkr's columns.
  • Workflow — a trkr-managed field naming which stage pipeline this ticket walks (feature, bugfix, chore, …). Workflows are per-ticket, not per-repo.

Dependencies between tickets use GitHub's native blocked_by issue dependencies. The daemon's frontier query is simply "open blocker count == 0".

The stage loop

Each workflow is an ordered list of stages. A stage declares three columns: from (waiting), during (working), to (success). The daemon:

  1. Finds a ticket sitting in a stage's from column with no open blockers. (manual stages — every preset's first — are the exception: the daemon waits for a human to move the ticket into the stage's during column instead.)
  2. Moves it to during and spawns a fresh agent session in the ticket's git worktree (.trkr/worktrees/<issue>), with the stage's prompt.
  3. On success — including passing the stage's hard gate, a mechanical check that the stage's artifacts actually exist — moves it to to.

Sessions carry no memory between stages. The issue thread and committed artifacts (docs/tickets/<n>-<slug>/) are the only state — except on retry turns, where the stage prompt also carries the ticket's failure history (below).

Turns and blocking

A turn is one full walk of the verification loop. A ticket gets one turn counter across all gates, and 3 turns max (configurable via max_turns). Gate failures with actionable findings kick the ticket back for another turn; the third failure applies the trkr:blocked label and stops. A human fixes the impasse and runs trkr unblock <issue>, which clears the turn counter and restarts the workflow.

Retry turns are guarded so the loop converges instead of thrashing:

  • Error memory — every retry turn's stage prompt includes a "Prior failed turns" section with the findings from each earlier turn, plus an instruction to change only what the findings demand. Sessions can't repeat a fix that already bounced.
  • Progress metric — the failing-findings count must fall between turns. If the same stage's gate bounces two consecutive turns with no improvement, the ticket blocks immediately (a turn.plateau event in the trace) rather than burning its remaining turns.
  • Fresh start on the final turn — the last turn's prompt tells the session to stop patching and regenerate the affected code from the spec if earlier patches kept failing.

Hand-off

Every workflow terminates in the review stage. When it passes (a committed review.md with VERDICT: CLEAR), trkr requests your review on the open PR — falling back to an @mention when GitHub refuses a self-request on a solo repo — records the CI check state in the trace, moves the ticket to Done, and removes the ticket's worktree. trkr never merges; the PR waits for you. If every linked PR is later closed without merging, the daemon labels the ticket trkr:blocked.