Skip to content

config.yaml reference

/ticket:init generates this file interactively — see its flow for how each section gets filled in. This page is the field-by-field shape, drawn from two representative generated configs (examples/fs-labels-inbox, a filesystem project, and examples/gh-native-proj, a GitHub project with a linked board).

version: 1

ticket_id:
  prefix: TE          # your ID prefix, e.g. "TE-001"
  padding: 3
  start: 1

lifecycle:
  stages:              # ordered; each has roles + a backend-specific location
    - key: backlog
      label: "Backlog"
      roles: [pickable]
      filesystem: { folder: backlog }        # OR:
      github:     { label: "status:backlog" } # (mutually exclusive per backend)

backend:
  type: filesystem | github
  filesystem:
    root: proj
    filename: "{id}-{slug}.md"
    transition: git_mv
    commit_per_transition: true
  github:
    repo: owner/repo
    type_label_prefix: "type:"
    priority_label_prefix: "prio:"
    effort_label_prefix: "effort:"
    risk_label_prefix: "risk:"
    type_map: {}       # optional — maps to native org issue types

types:                  # per ticket type, required body sections
  feature: { required_body_sections: [why, acceptance_criteria, ux_surface, architecture_notes, research, out_of_scope] }
  bug:     { required_body_sections: [repro_steps, expected, actual, suspected_cause, regression_test, architecture_notes] }
  tech:    { required_body_sections: [goal, approach, verification] }
  spike:   { required_body_sections: [question, time_budget, approach] }

effort:
  allowed:          [S, M, L, XL]
  pickable_allowed: [S, M]   # anything bigger gets split at creation time

claim:
  stale_after: 24h

milestones:
  strategy: auto | labels | none   # "auto" resolves to trackers (fs) or native (github)
  labels:   { prefix: "milestone:" }   # if strategy: labels
  trackers: { ... }                    # if strategy: auto on filesystem

projects:                # github backend only
  enabled: true
  number: 1
  owner: example
  owner_type: org | user
  status_field: "Status"
  status_map:   { pickable: "Backlog", in_progress: "In progress", review: "In review", terminal: "Done" }
  field_map:    { priority: "Priority", effort: "Effort", risk: "Risk" }

git:                      # branch-per-ticket workflow (defaults shown)
  branch_workflow: enabled   # enabled | disabled
  branch_prefix: "ticket/"   # branch names: <prefix><id>-<slug>
  merge_strategy: merge      # merge | squash | ff_only
  pr_integration: none       # none | github (github backend only)

commits:                 # one message template per event, {id}/{title}/etc. interpolated
  new: "ticket: new {id} {title}"
  # ... capture, capture_update, refine, claim, abandon, update, review, reject,
  #     done, fold, wontfix, milestone_flip

research:                 # optional — the research agents init generated (or you registered);
  agents:                 #   omitted = ticket creation reads sources inline
    - name: perf-expert
      consult: "the work could affect latency, memory, or throughput"

review:
  agents: [code-reviewer, test-adequacy-reviewer]   # blocking checkers in the pick loop (+ any generated `checker`)
  plan_advisors: []   # optional — extra agents alongside the fixed `challenger` at the plan gate (generated `advisor`s)
  advisors: []         # optional — extra agents alongside the fixed `code-challenger`/`code-simplifier` every round

nfr:                      # optional — the profile `nfr-analyst` judges against
  dimensions: [performance, security]        # omit the key to consider all eight
  budgets:                                   # your numbers; cited instead of a generic standard
    performance: "p95 under 200ms on the API surface"

references:                # all nullable — init fills them from what it found in the repository
  architecture:   null
  conventions:    null
  roadmap:        null
  template:       proj/TICKET_TEMPLATE.md
  project_readme: null

verification:              # init fills these from the commands you let it check (or record)
  test_commands:      []   #   typecheck, lint, test — cheapest first
  build_command:      null
  pre_close_command:  null # init never guesses a release gate
  max_loop_rounds:    3

Types

Every ticket has a type (feature, bug, tech, spike by default — extensible). Each type declares the body sections /ticket:new requires before it will commit:

Type Required body sections
feature why, acceptance_criteria, ux_surface, architecture_notes, research, out_of_scope
bug repro_steps, expected, actual, suspected_cause, regression_test, architecture_notes
tech goal, approach, verification
spike question, time_budget, approach

Every ticket also carries ## Decisions & assumptions, regardless of type — see Aligned by design.

Effort

effort.allowed is the full size scale; effort.pickable_allowed is the subset allowed to land in the pickable stage. Anything /ticket:new sizes above that ceiling gets silently split into a dependency-ordered slate instead of committed as one oversized ticket.

Roles

Every command resolves roles, not stage names, so your stage naming is free-form. See Workflow overview § Stages and roles for exactly which commands change behavior when inbox or review is absent.

Role Required? Meaning
inbox optional Captured-but-unreconciled work; enables /ticket:refine
pickable required The backlog /ticket:pick claims from
in_progress required Where claimed tickets live during implementation
review optional Enables /ticket:review and /ticket:reject; changes where /ticket:pick and /ticket:close hand off
terminal required Closed tickets — shipped, wontfix, or duplicate

Backend field storage

Filesystem GitHub
Ticket body Markdown file, YAML frontmatter Issue body, no frontmatter
depends_on / related / milestone Machine-owned .ledger.yaml Native issue dependencies / native or label milestone
Stage Folder location (git mv on transition) Workflow label
Priority / Effort / Risk Frontmatter Project v2 board fields, or labels as fallback
Claim Frontmatter (claimed_by, claimed_at) Assignment event
Type Frontmatter Label, or native org issue type if type_map configured

Milestones

milestones.strategy (resolved by ticket-engine, enacted by milestone-sync):

Strategy Backend Storage
auto → trackers filesystem Tracker files under the ticket root
auto → native github Native GitHub milestones
labels either milestone: prefixed label
none either Milestones disabled entirely

Git branch workflow

git.branch_workflow (resolved by ticket-engine § Git branch workflow): when enabled (the default), /ticket:pick creates a branch right after claiming and does all implementation work there; /ticket:close merges it into the base branch — per merge_strategy, and via a GitHub PR instead of a local merge when pr_integration: github — before closing. Ticket state itself (claim, review, close) always commits to the base branch, on both backends, regardless of this setting — only the implementation commits move to the ticket's branch.

Key Values Meaning
branch_workflow enabled (default) / disabled Whether pick/close manage a per-ticket branch at all
branch_prefix any string, default ticket/ Branch names look like <prefix><id>-<slug>
merge_strategy merge (default) / squash / ff_only How /ticket:close folds the branch into base
pr_integration none (default) / github github backend only — open/merge a PR instead of a local merge

Agents

Key What it lists Default
research.agents Research agents /ticket:new and /ticket:refine dispatch, each with a one-line consult hint that routes it Absent — sources are read inline
review.agents Blocking checkers every /ticket:pick loop round [code-reviewer, test-adequacy-reviewer]
review.plan_advisors Advisory agents at the Plan gate, beside the fixed challenger Empty
review.advisors Advisory agents every loop round, beside the fixed code-challenger and code-simplifier Empty

Every name must resolve to an agent file in the bundle's agents/ directory — the engine refuses the config otherwise, and the commands skip a listed agent whose file goes missing with a warning. /ticket:init fills these lists: one research agent per source it designed with you, and a generated checker or advisor only when its research gave a concrete reason. See Generated agents.

Setup manifest

/ticket:init writes <bundle>/setup/manifest.yaml beside config.yaml and commits it with the config. Unlike the config it is machine-owned — you don't edit it; init rewrites it on every update — and it is validated by te manifest validate. It records where everything in the config came from:

Block Holds
environment The orient-phase probe: web_search, web_fetch, subagents, git, gh — each verified or unavailable, never assumed
facts What init read in the repository — language, framework, datastore, commands, docs… — each with the source file it came from, detected or asked (you corrected it)
decisions Every config-relevant answer with its provenance: asked (you chose), detected (from the repository), default (you skipped; the recommended option was taken)
commands Each candidate test/lint/typecheck/build command: verified, failing, unavailable, unverified or skipped, with the baseline when it ran
research When the stack was researched, and per subject the queries run, sources cited, and done / thin status; the notes live in setup/research/<subject>.md
bundle The template repository the bundle came from and the commit it matches (unknown until an update settles it) — the base for refreshing the bundle in update mode
assistants Which assistants the setup serves — served or pending-bundle (its bundle isn't installed yet)
agents Each generated agent: its kind, the research subjects that fed it, and the hash of every generated and user region — how update mode tells a region you edited from one it may regenerate

See also

  • /ticket:init — how the config and the setup manifest are produced, and update mode

  • /ticket:init — the interactive flow that produces this file

  • Example projects — 21 fully generated configs covering every valid combination