# tix — a terminal issue tracker
**tix** is a kanban-style issue tracker that lives entirely in your repository:
issues are plain **Markdown + YAML frontmatter** files. There is no database, no
server, and no proprietary format — you get a terminal UI (TUI), a full CLI, and
optional GitLab/Linear sync in one Rust binary.

> **Heavily AI assisted.** This project was designed, specified, and built
> end-to-end with AI agents under a spec-kitty-SPEC style governed workflow
> (spec → plan → tasks → implement → review → merge): all 6 work packages, 27
> functional requirements, and 33 subtasks, each passing real gate checks
> (`cargo test`, `clippy -D warnings`, `cargo fmt`) before merge. The mission
> trail lives in `kitty-specs/issue-tracker-tui-01M27PTN/`; the integration
> surfaces are documented in
> [`docs/spec-kitty-integration.md`](docs/spec-kitty-integration.md),
> [`docs/openspec-integration.md`](docs/openspec-integration.md) and
> [`docs/mcp.md`](docs/mcp.md). `tix init-agents` writes an AI-agent usage
> section into `AGENTS.md`, so other agents can operate this tracker
> autonomously.
## Install
The crate is published to crates.io as **`tix-tracker`** (the binary is still
called `tix`). See [docs/packaging.md](docs/packaging.md) for the full
maintainer workflow (crates.io account, publishing, binary releases).
```bash
cargo install tix-tracker # build from source via crates.io
# or, with prebuilt binaries (fast, no Rust toolchain needed):
cargo install cargo-binstall --locked # one-time, if you don't have it
cargo binstall tix-tracker
```
Local development installs (same binary) work too:
```bash
cargo install --path .
```
Requires a Rust toolchain (edition 2024, MSRV 1.85). The only runtime
dependency is your favorite editor for `tix edit`.
## Quickstart
```bash
tix init # create the default tix.toml (columns, issues_dir)
tix create --title "First issue" --priority high --labels docs
tix status # board summary: column -> count
tix list # all issues in a table
tix list --columns title,status # choose and order displayed columns
tix # open the kanban TUI
```
## CLI
| `tix init` | Create a default `tix.toml` (and add `*.tixbak` / `*.md.bak` to `.gitignore`) |
| `tix create` | New issue (title/body/status/priority/assignee/labels/estimate/files) |
| `tix new` | The same, in the TUI: opens the board with the create-issue form already open |
| `tix list` | Table of issues, optional `--status` filter, `--columns` selection and `--with-archived` scope |
| `tix view <issue>` | Full issue (frontmatter + body) |
| `tix status` | Board summary: count per column + total |
| `tix search <query>` | Substring-search issue titles and bodies (case-insensitive; `--with-archived` includes archived issues) |
| `tix lint` | Validate issue frontmatter and report diagnostics |
| `tix render` | Render the current board once without entering the TUI |
| `tix clean` | Remove the backup files `tix` writes beside an issue before it rewrites one — `*.tixbak` and `*.md.bak`; confirms each file unless `-f`/`--force` |
| `tix edit <issue>` | Edit fields via flags, or full file via `$EDITOR` (`--files`) |
| `tix move <issue> <column>` | Move between columns; `done` records a commit hash (auto-captured from `HEAD`, or `--commit auto`/`<hash>`) |
| `tix link <a> <b> --type <kind>` | Add a **typed** relationship — `blocks`, `blocked_by`, `duplicates`, or `related` (required) |
| `tix link list` / `tix link edit <id>` / `tix link remove <id>` | Inspect, retarget/re-kind, and remove relationships by their stable id |
| `tix unlink <a> <b> --type <kind>` | Remove a relationship of that kind |
| `tix chain <issue>` | Print the transitive `blocks` chain an issue holds up |
| `tix archive <issue>` / `tix restore <issue>` | Hide an issue from the default views, or bring it back — by dot-prefixing its filename ([details](docs/for-users/archiving.md)) |
| `tix bulk edit\|link\|unlink` | Batch over a selection; **preview is the default**, `--apply` writes ([details](docs/for-users/batch-editing.md)) |
| `tix cycle ...` / `tix milestone ...` | Create, list, edit, rename, and delete planning items; creating a cycle warns when its dates overlap another |
| `tix workflow categories \| show \| transitions` | Print the status-category vocabulary, how this board resolves each column, and which transitions are permitted |
| `tix delete <issue> --yes` | Remove an issue file |
| `tix export --target gitlab\|linear` | Push local issues to a remote tracker ([details](docs/for-users/external-sync.md)) |
| `tix import --target gitlab\|linear` | Pull open issues from a remote tracker |
| `tix import --target speckit` | Mirror a local GitHub Spec Kit project as labeled issues and subissues; idempotent |
| `tix init-agents` | Write/refresh the AI usage section in `AGENTS.md` |
An issue can be referenced by number, filename fragment, or title fragment.
`tix init-agents` detects `.kittify/`, `openspec/` and `.specify/` independently
and writes the corresponding tracking blocks into `AGENTS.md`. When it sees them,
it also prints the matching detection lines to stdout so scripts can tell which
blocks were emitted.
## TUI
Launch with `tix` (no arguments) from the repository root; `tix new` starts the
same session with the create-issue form already open. The complete, configurable
key reference is [`docs/key-bindings.md`](docs/key-bindings.md); the list here is
only a default overview.
Six top-level modes share one shell with a vertical navigation tree on the left
(clickable limbs per board, cycle, milestone and template). A mode's function
key switches to it only when the active mode does not bind that key itself, so
`F2` inside a form is still the picker.
| New Issue | `F1` | the create-issue form, with an explicit Triage/Todo target | [new issue](docs/for-users/new-issue.md) |
| Triage | `F2` | the triage inbox | [triage](docs/for-users/triage.md) |
| Board | `F3` | the kanban board | [board keys](docs/key-bindings.md#board) |
| Cycles | `F4` | cycles grouped current / future / archived, with statistics | [cycles](docs/for-users/cycles.md) |
| Milestones | `F5` | the milestone registry with per-milestone progress | [config](docs/for-users/config.md) |
| Config | `F12` | dashboards, cycles, milestones, types, and attributes in one surface | [config](docs/for-users/config.md) |
Board highlights: arrows and `h`/`j`/`k` navigate, `PgUp`/`PgDn` page a column,
`Enter` opens an issue, `n`/`F1` creates, `Shift+C` clones, `u` toggles the
sub-issue tree, `e` edits in `$EDITOR`, `v` views read-only, `d` deletes, `m`
manages cycles and milestones, `/` searches the live board, `?` opens searchable
help, `q`/`Esc` quits. In the issue detail view, `n`/`E`/`d` add, re-kind and
remove typed relationships, and `Shift+P` sets, changes or clears the parent —
all through the same service the CLI and MCP use, so a relationship created in
the TUI is byte-identical to one created with `tix link`.
The TUI is mouse-aware (click, double-click, drag, right-click, scroll, hover)
and never sacrifices keyboard operation. Editor round trips are conflict-safe: a
file changed by another writer is never clobbered by a stray keypress — see the
[edit-conflict and edit-repair modals](docs/key-bindings.md#modal-management-modes).
## Storage format
Issues are files under `docs/issues/…` with YAML frontmatter and a Markdown
body. `tix` re-renders the frontmatter in its own style on write (custom keys are
preserved, `## History` verbatim), and the layout, `related_issues`, and custom
frontmatter keys are all configurable. See
[storage format](docs/for-users/storage.md).
## Relationships and parents
Four typed relationship kinds (`blocks`, `blocked_by`, `duplicates`, `related`)
replace the retired `links:` key; only `blocks` drives the blocked-move guard. An
issue has at most one parent — a decomposition tree, not an ordering edge. See
[relationships](docs/for-users/relationships.md) and
[parent issues](docs/for-users/parent-issues.md).
## Batch editing
`tix bulk edit|link|unlink` over a selection: preview is the default, `--apply`
writes, and each item reports its own outcome with no rollback. See
[batch editing](docs/for-users/batch-editing.md).
## Archiving
`tix archive`/`tix restore` dot-prefix an issue's filename to hide it from the
default views without deleting it; the number is never recycled. See
[archiving](docs/for-users/archiving.md).
## Workflow status categories
Map board columns onto the global six-word vocabulary (`backlog` … `canceled`).
Declaring a `category_map` opts the board into the transition policy; an unmapped
column falls back to `unstarted`. See
[workflow status categories](docs/for-users/workflow-categories.md).
## Triage inbox
An opt-in inbox, declared by a `[triage]` section in `tix.toml`, holds unreviewed
work before it joins the normal workflow. Every decision is one History event,
and the CLI, the TUI (**F2**) and MCP read one snapshot through the same service.
See [triage](docs/for-users/triage.md) and the design reference
[`docs/triage.md`](docs/triage.md).
## External sync
`tix export/import` targets GitLab (through `glab`) and Linear (through
`linear-cli`), plus a local `tix import --target speckit`. Repeated runs are
idempotent. See [external sync](docs/for-users/external-sync.md).
## Configuration
`tix.toml` holds the issues directory, `[export]` targets, keybindings and legacy
tables; boards live in `docs/boards/<name>.md`. The full key reference is in
[configuration](docs/for-users/configuration.md), the TUI editing surface in
[config mode](docs/for-users/config.md), and the metadata stores in
[navigation](docs/for-users/navigation.md#project-metadata-stores).
## Documentation
Beyond the guides linked above, `docs/for-users/` also holds
[navigation](docs/for-users/navigation.md) (mode shell and metadata stores),
[new issue](docs/for-users/new-issue.md), [cycles](docs/for-users/cycles.md)
and [config mode](docs/for-users/config.md), plus
[key bindings](docs/key-bindings.md) and [MCP](docs/mcp.md).
## Version
Current version: **0.7.0**. See [CHANGELOG.md](CHANGELOG.md).
## License
MIT OR Apache-2.0.