Fabric
You're on the list! We'll be in touch when we launch.
Please enter a valid email address.
Something went wrong. Please try again.

Tickets

A ticket in Fabric is a version-controlled record: structured fields (title, status, assignee, priority, labels) plus a markdown body. Creating or editing a ticket records ops in the operation log, so a ticket carries its full history the same way any other content does: nothing is overwritten, only appended.

The fields and the body merge independently. If one person changes a ticket’s status while another edits its description at the same time, both edits land: the status is a last-writer-wins field and the body is collaborative text, so they never clobber each other. And because a ticket is ordinary content in the log, it time-travels like everything else. The hub also keeps a fast read model behind the list and detail views, so filtering and sorting stay quick even as the log grows.

Keys

Every ticket gets a human key, TIX-1, TIX-2, and so on, minted in order the moment you create it. Keys are unique within your workspace and never reused, so two tickets can never collide. You refer to a ticket by its key everywhere: the detail page lives at /tickets/TIX-12, and the CLI takes the key as its argument.

Fields

FieldMeaning
TitleA short summary. Required.
StatusWhere the work stands. The available statuses come from your workflow (see below); a new ticket with no status takes the first one.
AssigneeWho owns it. Optional.
PriorityA number; higher sorts first in the list.
LabelsFree-form tags for grouping and filtering.
DescriptionThe markdown body.

Structured body

The body is markdown, and the ticket page renders a few ## sections as their own labeled blocks so a ticket reads as a structured record instead of one wall of prose. Write any of:

## Intent
Why this work exists, written before you start.

## Acceptance criteria
- [ ] the observable outcome that means "done"
- [ ] another one

## What changed
The reviewer-facing summary, filled in at propose time.

## Learnings
- A finding worth keeping for next time.

## Open questions
- [ ] an uncertainty to resolve during review
- [x] a resolved one (checked)

Acceptance criteria and Open questions are task lists (- [ ]), so the page shows how many items are done and how many questions are still open; checking an open question off marks it resolved. Every other heading still renders normally, so the convention is additive: a plain freeform body looks exactly as it did. Because these sections live in the body, appending a new subsection (for example a ### TIX-12 block under ## What changed per change) merges cleanly across concurrent edits.

Workflow states

The set of statuses a ticket can have is your workflow, and it is version-controlled like everything else. Each state has a name (the status you pick on a ticket), a category it rolls up to, a badge color, and a sort order. The four categories are fixed: backlog, started, completed, and canceled. Categories are what the board groups by and what the category filter uses, so renaming a state never loses the coarse “where in the flow” signal.

With no configuration you get a sensible default flow:

StateCategoryColor
backlogbackloggray
todobacklogblue
in_progressstartedyellow
in_reviewstartedpurple
donecompletedgreen
canceledcanceledred

To customize it, add a .fabric/workflow.toml file to your repo. It is one [[state]] block per state:

[[state]]
name = "triage"
category = "backlog"
color = "gray"
sort_order = 0

[[state]]
name = "building"
category = "started"
color = "yellow"
sort_order = 10

[[state]]
name = "shipped"
category = "completed"
color = "green"
sort_order = 20

[[state]]
name = "wont_do"
category = "canceled"
color = "red"
sort_order = 30

Each state needs a non-blank, unique name, a category that is one of the four above, and a color from the badge palette (gray, brown, orange, yellow, green, blue, purple, pink, red). sort_order orders the pickers and board columns ascending. States are read from your trunk, so a change that edits workflow.toml only takes effect once it lands.

Edit workflow.toml the same way you edit any file: through the Files view in the web app or with the fabric CLI. If the file is missing or malformed, Fabric falls back to the default flow rather than breaking the ticket views. Creating or editing a ticket to a status that is not in your workflow is rejected, so the pickers only ever offer configured states.

Relationships and sub-issues

Tickets can point at each other. Four typed relations live in the ticket’s fields, so they are version-controlled like every other field:

RelationMeaning
blocksTickets this one blocks (a list of keys).
blocked_byTickets that block this one.
relatedLoosely connected tickets.
parentA single parent key. Setting it makes this ticket a sub-issue of the parent.

Every target is a ticket key (TIX-2) in the same workspace. A relation to a ticket that does not exist, or one in another workspace, is rejected when you save, and a ticket cannot block, relate to, or parent itself.

You only declare an edge on one side. The inverse shows automatically on the other ticket, so you never keep two tickets in sync by hand:

You set on AShows on B
blocks: [B]Blocked by: A
blocked_by: [B]Blocks: A
related: [B]Related: A (related is symmetric)
parent: BA appears under B’s Sub-issues

If both sides happen to declare the same edge (A sets blocks: [B] and B sets blocked_by: [A]), it still shows once. Declaring on either side is enough.

The detail page shows all of this grouped: Parent and Sub-issues for the hierarchy, Blocks / Blocked by / Related for the typed links (forward and inverse merged), and Referenced by for tickets that link to this one without any typed relation to it. Each entry links to the target with its current status.

Relations are backed by [[wikilinks]]. When you set a relation, Fabric keeps a [[tickets/<id>]] reference for the target in a managed block at the end of the ticket body, so the engine’s link graph sees the edge. That block is regenerated from the typed fields on every save and is hidden in the UI, so you never edit it by hand: change the relation, not the link. That inbound link graph is also what powers the automatic inverse relations above: Fabric reads each inbound ticket’s typed edges to work out which direction to show them. “Referenced by” is what remains, tickets that link here without any typed relation.

In the web app

Open Tickets in the sidebar for the list. Filter by status, category, or assignee, and click a row to open the ticket. The detail page renders the description as markdown, with the structured sections shown as their own labeled blocks. With write access you get a New ticket button and an Edit button; without it the views are read-only.

Switch to the Board view for a grouped layout: one column per category (backlog, in progress, done, canceled), with each ticket as a card. Cards are ordered by priority, then by most recently updated. The List and Board toggle sits next to the New ticket button.

Both views update live: when anyone in your workspace creates or edits a ticket, every open list and board refreshes on its own, no reload needed.

Comments

Every ticket has a comment thread at the bottom of its detail page. Click New comment to start a discussion, reply to keep a thread together, and add emoji reactions. Type @ to mention a teammate: the mentioned person gets a notification. Resolve a comment once it is handled (you have a short window to undo if you resolve one by mistake).

Comments post live: when anyone comments on a ticket you have open, the thread updates on its own, no reload needed. Posting a comment needs write access; without it you can still read the thread.

Work tickets from the terminal with fabric ticket:

fabric ticket create "Fix the login redirect"
fabric ticket create "Flaky checkout test" --status todo --priority 2 --labels bug,checkout
fabric ticket list
fabric ticket list --status todo --assignee alice
fabric ticket show TIX-12
fabric ticket edit TIX-12 --status done
fabric ticket edit TIX-12 --title "New title" --body "Updated description"
fabric ticket create "Ship the API" --blocks TIX-2,TIX-5 --parent TIX-1
fabric ticket edit TIX-12 --related TIX-4 --blocked-by TIX-9

create takes the title as its one argument and mints the key for you. On edit, only the flags you pass change; the rest are left as they were, so fabric ticket edit TIX-12 --status done touches nothing but the status. Pass --labels "" to clear labels.

Set relations with --blocks, --blocked-by, and --related (each a comma-separated list of keys) and --parent (a single key). On edit each relation flag REPLACES that whole relation with what you pass, so --blocks TIX-2,TIX-5 sets exactly those two and --related "" clears the related list. show prints every non-empty relation, including the sub-issues and the tickets that reference this one. Add --json to any command for machine-readable output, so an agent can read a ticket, act on it, and update it without the web UI.