tix-tracker 0.12.0

A terminal issue tracker: markdown + YAML frontmatter issues with a kanban TUI and CLI
Documentation
# Relationships

Four kinds, and the difference is not cosmetic — only two of them affect the board:

| `--type` | Meaning | Blocks the target? |
| --- | --- | --- |
| `blocks` | this issue blocks the target | **yes** |
| `blocked_by` | the inverse view of the same edge | **yes** (stored canonically as `blocks`) |
| `duplicates` | the target restates this issue | no |
| `related` | a non-directional association | no |

`blocks` is directional and reads left to right: `tix link 12 34 --type blocks`
means "12 blocks 34", so 34 is blocked. A `related` edge is order-normalised by
canonical issue id and stored once, in the canonical source's file — so an issue's
own `relationships` field is deliberately partial. `tix link list` and the derived
views read the whole graph, so both endpoints see it.

Endpoints are stored as canonical ids. Numbers appear only in commands and
rendered labels:

```yaml
relationships:
- id: rel_01JQ8Z4W2M6N7P9R3S5T7V9X1
  from: B2C3D4E5
  to: A1B2C3D4
  kind: blocks
  display: blocks #34 Refactor store
```

`tix link 12 34` accepts the human aliases and writes the two ids. Raw consumers
must use ids; `tix link list`, the TUI, and MCP's rendered text retain the
number aliases. Run `tix migrate issue-graph` once for older files that still
store numeric endpoints.

```console
$ tix link 12 34 --type blocks
Linked #12 blocks #34 (rel_01JQ8Z4W2M6N7P9R3S5T7V9X1)

$ tix view 34 --show relationships
...
## Relationships
- #12 --blocks--> #34  Refactor store  [rel_01JQ8Z4W2M6N7P9R3S5T7V9X1]

## Dependency chain
No dependency chain for #34

## Blocked
- blocked: Blocked by #12 Fix the parser
```

**Blocked state.** An issue with an open inbound `blocks` edge is *blocked*. That
is visible in `tix list --columns blocked --show relationships`, in
`tix view --show relationships`, and as a marker on the TUI card.

**The blocked-move guard.** Moving a blocked issue into the board's completion
column is refused unless you confirm it:

```console
$ tix move 34 done
warning: blocked: Blocked by #12 Fix the parser
tix: invalid input: blocked: Blocked by #12 Fix the parser — moving to 'done' with
open blockers requires an explicit confirmation; re-run with --yes to record the
decision

$ tix move 34 done --yes --commit abc1234
Acknowledged blocked move to done
```

Note that `tix move <n> done` also needs a commit hash. In a git repository it
auto-captures `HEAD`; outside one you must pass `--commit` or `--commit auto`, so
the refusal above is about the blockers and the commit is a separate requirement.

`tix edit --status` is a move too and answers the same way. Confirming records a
`blocked_move_acknowledged` entry in the issue's `## History`, so the decision is
auditable rather than implicit. The TUI asks before it writes, and the MCP
`move_issue` tool takes `yes`.

## ⚠️ Breaking change: the `links:` frontmatter key is gone

The generic `links: [12]` field has been **removed** and replaced by the typed
`relationships` field above.

- **There is no migration, and no compatibility layer.** A file that still carries
  `links:` parses, but the value is **never read** as relationship data — it is not
  converted to `related` or to anything else.
- `tix lint` reports such a file as `retired_links_key` and tells you what to do.
- The key disappears on the next write of that issue.
- `tix create --links`, `tix edit --links`, and the MCP `links` argument are
  **rejected**, not ignored. An integration that used to pass one now gets an
  explicit error naming `tix link` / the `link_issue` tool, rather than a success
  response and silently lost relationships.

To convert, read the old list and re-create each edge:

```console
$ tix link 12 34 --type related     # was: links: [34]
$ tix link 34 35 --type blocks      # was: links: [35] on 34
```

An **empty** `links: []` is not reported — it has nothing to lose, and flagging it
would make `tix lint` reject every file written before this change.

Migrating a whole repository at once:

```bash
# report which files still carry the retired key
tix lint | grep retired_links_key
```

For the one-parent decomposition tree — a different concept — see
[parent issues](parent-issues.md).