# AGENTS.md
## Project
tkt — Git-native ticket CLI. Manages `.tickets/` frontmatter-driven work tracking with atomic git operations, race detection, and dependency-graph frontier computation.
Single Rust binary. Originally ported from a Python implementation (now removed). Same interface, same contract.
## Workspace Layout
```
src/
├── main.rs — entry point + ErrorKind enum + DomainError struct
├── cli.rs — clap derive commands + dispatch + JSON envelope helpers
├── color.rs — color/symbol support (NO_COLOR, --color, TKT_ASCII)
├── config.rs — unified config cascade (user + project + env)
├── telemetry.rs — consent, session tracking, JSONL sink, rotation
├── mutation.rs — MutationContext (push-gated lifecycle for existing-ticket mutations)
├── renumber.rs — RenumberPlan (pure ID remapping: plan + apply)
├── audit.rs — pure audit rules (injectable deps, no I/O)
├── core/
│ ├── mod.rs — re-exports
│ ├── ticket.rs — TicketFile (raw editor + typed mutations) + Ticket (typed domain)
│ └── validate.rs — input validation (slugs, free text, IDs, enums)
├── commands/ — one file per subcommand (new, close, claim, edit, lint, doctor, etc.)
├── findings.rs — validation rules, Finding struct, output formatting
├── transaction.rs — GitTransaction (allocation: fetch→scan→commit→push→retry)
└── git.rs — git subprocess wrapper (fetch, commit, push, remote scanning)
tests/
├── integration.rs — integration tests (tempdir repos, race scenarios, telemetry, debug)
└── parity/ — historical Python parity comparison harness
skills/tkt/ — agentskills.io skill (deployed via symlink to ~/.kiro/skills/tkt)
steering/ — always-on steering files (deployed as copy to ~/.kiro/steering/)
plugin.json — Agent Plugins v1.0.0 manifest
.memory/CONTEXT.md — project glossary
.tickets/ — tkt's own tickets (dogfooding)
.references/ — cloned reference repos (gitignored): clispec, axocli, octo-cli
TELEMETRY.md — transparency document for telemetry collection
```
## Commands
```bash
cargo build # debug build
cargo build --release # release build (stripped, LTO)
cargo install --path . # deploy to PATH (shows git hash in --version)
cargo test # all tests
cargo test -- --nocapture # with output
cargo clippy # lint (must be 0 warnings)
cargo fmt # format (must produce no diff)
```
### Verification gate (run before every commit)
```bash
cargo fmt && cargo clippy --all-targets && cargo test
```
### Deploy (run after pulling or making changes)
```bash
cargo build --release && cargo install --path . && bash tools/deploy-skills.sh
```
All three gate checks must pass with zero warnings before presenting work as done.
## tkt CLI (the product)
```bash
tkt --version # print version
tkt ready [--json] # frontier: open + deps done + env match
tkt new <slug> --title "..." [--spec S] [--blocked-by NN,NN] [--priority P] [--env E] [--status S]
tkt batch <slug[:title]>... [--spec S] [--blocked-by IDS] [--priority P] [--env E]
tkt claim <id> # status→in_progress, pushed
tkt close <id> [--note "..."] [--resolution "..."] [--ac N,N] [--check-all] [--force]
tkt edit <id> [--title T] [--blocked-by IDS] [--priority P|''] [--env E|''] [--spec S|''] [--status S] [--ac N,N]
tkt renumber <old> <new> [--file NAME] # birth-window only
tkt query [--status S] [--priority P] # full corpus as JSON Lines (filterable)
tkt blocked # open tickets with unsatisfied deps
tkt capabilities # machine-readable JSON feature manifest
tkt rebase [--dry-run] # resolve ID collisions with upstream
tkt audit [--strict] [--brief] # closure quality check
tkt sync-plan --check [--strict] [--brief] [plan] # report drift
tkt sync-plan --fix [--strict] [--brief] [plan] # fix derivable columns
tkt validate [--strict] [--brief] # contract + cycle + decay findings
tkt lint [--check] [IDs...] # normalize frontmatter style
tkt doctor [<path>] [--strict] # health check (single or cross-project)
tkt init [--target T] [--all] # scaffold project + agent instructions
tkt config [--set K=V] [--get K] [--unset K] [--list] [--show] # user + project config
tkt telemetry [--enable|--disable|--status|--show|--clear] # manage local telemetry
```
### Global flags
| `-q` / `--quiet` | Suppress confirmations, emit only essential data |
| `-o json` / `--output=json` | Structured JSON output (success to stdout, errors to stderr) |
| `--dry-run` | Preview mutations without writing |
| `--color=always\|never\|auto` | Control ANSI color output (default: auto) |
### Priority levels
`urgent` > `high` > `medium` (default) > `low`. Frontier sorts by priority bucket then ID.
### Status values
`backlog` (parked, excluded from frontier) → `open` → `in_progress` → `done`
### Configuration
- **User config**: `~/.config/tkt/config.toml` — debug mode, format preferences
- **Project config**: `.tickets/config.toml` — committed to repo, shared by contributors
- `[close]` require_resolution, require_checked_acs
- `[validate]` strict
- `[ready]` default_env
- `[priority]` warn_unknown
- `[new]` default_priority
- `[push]` enabled (set false for local-only repos)
### Environment variables
| `TKT_DEBUG=1\|json` | Debug output to stderr |
| `TKT_ASCII=1` | ASCII-only symbols (✓→[ok], ✗→[err], ⚠→[warn]) |
| `NO_COLOR=1` | Disable ANSI color |
| `CREW_ENV` | Filter frontier by env (corp/personal) |
| `DO_NOT_TRACK=1` | Disable telemetry |
| `TKT_NO_USER_CONFIG=1` | Skip user config file (for testing — prevents ambient config leaking into child processes) |
## Architecture Decisions
- **Shell out to git** (not libgit2): full SSH/HTTPS auth compat, matches gh CLI pattern, simplest v1
- **TicketFile + Ticket split**: TicketFile owns raw frontmatter for surgical edits; Ticket provides typed, validated fields (Status enum, zero-cost &str access). Mutations go through `.file`, reads use typed fields directly.
- **Custom frontmatter parser**: line-based key:value parsing with raw preservation. Supports YAML double-quoted scalar escaping (encode on write, decode on read). Not a full YAML parser — deliberately supports a narrow, round-trip-safe subset.
- **No async**: all operations are sequential (fetch → scan → write → commit → push)
- **Local-only telemetry**: opt-in JSONL file sink, per-project segmentation, session-aware rotation, never blocks CLI
- **LazyLock regex statics**: fixed patterns compiled once via `std::sync::LazyLock`
- **No color crate**: raw ANSI codes + `std::io::IsTerminal` — zero additional dependencies
- **Structured errors**: `DomainError { kind: ErrorKind, message, hint }` with 8-variant `ErrorKind` enum. `domain_bail!(Kind, "msg")` or `domain_bail!(Kind, "msg", hint: "fix")` or `domain_bail!("msg")` (defaults to Validation). JSON envelope emitted to stderr when `-o json`.
- **Facade re-exports**: only re-export types from `core/mod.rs` that callers name directly; types returned by methods but never named (e.g., `AcStats`) stay unexported from the facade to avoid unused-import warnings
## Contract
- Files are the database: `.tickets/{NN}-{slug}.md` with YAML frontmatter
- Tool never manages specification prose (body is user-owned; close appends a Resolution section)
- Push-to-claim: pushed commit = claimed id (race detection on push rejection)
- Exit codes: 0=success, 1=domain failure (not found, conflict, drift), 2=operational crash (I/O, git, parse)
- Output: JSON by default for validate/sync-plan; human by default for ready/new/claim/close/edit (use --json for ready)
- Spike branches: closing from `spike/*` auto-appends branch name to resolution
- Worktree-aware: works from git worktrees (`.tickets/` is part of the checked-out tree)
## Constraints
- Do NOT change the frontmatter contract without updating frontier-work steering
- Do NOT add dependencies beyond what's in Cargo.toml without justification
- Do NOT use libgit2/gix for v1 — shell out to git binary
- Do NOT suggest releasing with open tickets — all tickets ship first, or the user explicitly defers them
- Maintain CLI compatibility (same commands, flags, output)
- `cargo clippy` must produce 0 warnings; `cargo fmt --check` must produce no diff
- Integration tests MUST set `DO_NOT_TRACK=1` on child processes (prevents ambient env pollution)
- Unit tests must NOT assert specific consent state (result depends on ambient env vars)
- Windows: `std::fs::rename` cannot overwrite — always delete destination before rename
- Codex review dispatch: `codex exec --dangerously-bypass-approvals-and-sandbox` (bwrap namespace restriction on this machine; `codex review --base <SHA>` cannot combine --base with custom prompt)
- cargo-dist binary name is `dist` (not `cargo dist`) — `cargo dist --version` will fail; use `dist --version`
- New mutation commands MUST route push through a push-gated path (GitTransaction respects `push.enabled`; direct `git::push_with_retry` calls must check `pcfg.push_enabled` first)