# Triage

**Every cycle starts at Triage.** Before a roadmap is drawn, before a task exists, before any agent touches a repository, the request is judged on what it actually is: how well understood it is, how costly a wrong answer would be, and how much it should jump the queue.

## When this matters to you

- A cycle you asked for came back `canceled`, and you want the reason it was refused.
- A cycle parked for approval on a project where you never turned approvals on.
- Two cycles were ready at the same time and one dispatched first.

## Where Triage sits

```text
request ──▶ Triage ──┬──▶ draft ──▶ planning ──▶ executing ──▶ …
                     │
                     └──▶ canceled
```

Whatever proposed the work — the dashboard chat, `POST /v1/api/cycles`, a Linear delegation, or the project's own founding brief — none of them create a cycle directly. They all raise a *proposal*, and the roadmap planner is the single place a cycle row comes into existence. It creates every one at status `triage` and triages it immediately.

No agent has a path around that, including the orchestrator: a plan cannot be submitted for a cycle that is still in triage.

```text
Cycle "…" is still in triage. The Triage Agent decides whether it goes
forward; a plan cannot skip that gate.
```

## What the Triage Agent decides

The agent reads the request's title, body, and the project it belongs to, and returns four judgements plus a written rationale.

| It judges | Meaning | Values |
| --- | --- | --- |
| Complexity | How well understood the change is before work starts | `simple` · `ambiguous` · `systemic` |
| Risk | How costly a wrong answer would be | `low` · `medium` · `high` |
| Urgency | How much this should jump the queue ahead of work already waiting | `urgent` · `high` · `normal` · `low` |
| Decision | Whether this becomes a cycle at all | `forward` · `cancel` |

Urgency is judged from what the work *is* — something user-facing is broken, or other queued work is blocked on it — and explicitly not from how urgently the request happens to be worded.
**What the agent is never asked for:** The agent never names a lane and never invents a priority number. It supplies the two risk axes and an urgency tier; everything downstream of them is computed by code. That split is the point: an LLM judges the work, and versioned rules decide what happens to it.

## Lanes are derived, not chosen

Complexity and risk resolve to one of nine **lanes** through a versioned rule set, `hlix-web-v1`:

| | Risk `low` | Risk `medium` | Risk `high` |
| --- | --- | --- | --- |
| **`simple`** | `auto` | `fast-review` | `stop` |
| **`ambiguous`** | `plan-gate` | `architecture-review` | `design-review` |
| **`systemic`** | `experiment` | `split-work` | `manual-lane` |

The lane lands on the cycle as `lane`, and the rule-set version that resolved it is recorded on the transition — so a lane can always be explained by the rules in force when it was assigned, not by the rules in force when you read it.

**Four lanes change behaviour today.** `stop`, `design-review`, `architecture-review`, and `manual-lane` force a human approval before the cycle dispatches, whether or not the project opted into approvals — see [Review & QA gates](/concepts/review-gates/#lanes-that-demand-a-human). The remaining five are recorded as classification and carry no distinct mechanism of their own: `plan-gate` is already satisfied by the planning pass every cycle makes, and `auto`, `fast-review`, `experiment`, and `split-work` are metadata you can read, filter, and audit on.

## Urgency becomes a priority

| Urgency | `priority` |
| --- | --- |
| `urgent` | `300` |
| `high` | `200` |
| `normal` | `100` |
| `low` | `0` |

`priority` is a plain integer on the cycle, not a named level, with 100-wide gaps so a later adjustment has room to land between tiers. It orders three things:

- **Dispatch.** Ready cycles are launched highest priority first. This is an *order*, not a cap — every ready cycle in the wave still launches on that pass, and equal priorities keep their roadmap order.
- **Reading cycles back.** `GET /v1/api/cycles?orderBy=priority` sorts by priority, then newest first; the dashboard's cycles grid offers the same sort. The only other accepted value is `createdAt`, which is the default.
- **Planning.** The roadmap planner is shown the priorities already on the board when it sequences and links the new work it proposes. It cannot change an existing cycle's priority.

## What gets recorded

A forward moves the cycle to `draft`; a cancel moves it to `canceled`. Either way, two records are written.

**The cycle's stage history** gains an entry — this is the governed transition, and it is the same machinery every later status move uses:

```json
{
  "from": "triage",
  "to": "draft",
  "at": "2026-08-12T09:41:07.220Z",
  "actor": { "type": "agent", "id": "triage-agent" },
  "ruleSetVersion": "hlix-web-v1",
  "reason": "Adds a currency column and a backfill; the schema change is understood and reversible."
}
```

**An audit row** is written as `cycle.triaged` or `cycle.canceled`, attributed to the Triage Agent, carrying the rationale as its reason and the lane, priority, and raw tiers as metadata.

`lane`, `priority`, `stageHistory`, and `revision` are all fields on the cycle itself and are part of the [published contract](/api/reference/cycles/). The complexity and risk tiers behind the lane are deliberately **not**: they exist only in the audit record, which is restricted to workspace `owner` and `admin`.

### Reading a decision back

Ask the project's orchestrator in chat — *"why was this cycle canceled?"* — and it will return the decision, its rationale, the lane, and the rule-set version. Owners and admins additionally get the complexity and risk judgement behind the lane. The same material is in the [audit log](/concepts/review-gates/#what-gets-recorded), filtered to that cycle.

## When the Triage Agent cannot answer

Triage fails **open**. If the model call errors, the cycle is forwarded rather than stranded, with a rationale saying exactly that, and it lands in the `architecture-review` lane — which forces the human gate. A triage outage costs you an approval, never a lost request.

That posture is chosen per signal, not globally. An unreadable *lane* does not gate on its own, because most cycles without one are simply older than the column. An unreadable *project* approval flag does gate, because an operator toggle whose state is unknown must be read as the safer answer.

## Choosing the model that triages

Triage is its own orchestration role. Set the model for it under **Settings → AI models**, on the row labelled **Triage**, or over the API:

```bash
curl -sS -X PUT "$HLIX_BASE_URL/v1/api/model-config/triage" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
  -H 'content-type: application/json' \
  -d '{"modelIdentifier":"'"$MODEL_IDENTIFIER"'","temperature":0}'
```

`modelIdentifier` is required; `temperature` and `maxTokens` are optional. `DELETE` on the same path clears the override and returns the role to the deployment's default. Writes are restricted to `owner` and `admin`.

## If a cycle is not where you expect

- **A cycle reads `canceled` and you did not cancel it.** Triage refused it. The rationale is the `reason` on its last stage-history entry, and on the `cycle.canceled` audit row.
- **A cycle parked for approval on a project with the gate off.** Its lane forces one. The pending request carries the lane in its `context`. See [Approvals](/running/approvals/).
- **`{"proposed":true,"adopted":false}` and no cycle appeared.** A proposal is not a cycle; the orchestrator did not fold it into the roadmap on that pass. See [Cycles](/running/cycles/#proposing-a-cycle).
- **Two cycles dispatched in an order you did not expect.** Compare their `priority` values, not their creation times. A `normal` cycle created first still goes after an `urgent` one.
- **A cycle has no `lane`.** It was created before triage ran on it, or triage has not completed yet. A null lane never forces a gate on its own.

## Where to go next

| If you want to… | Read |
| --- | --- |
| See which lanes stop a dispatch | [Review & QA gates](/concepts/review-gates/#lanes-that-demand-a-human) |
| Resolve the request a lane opened | [Approvals](/running/approvals/) |
| Read a cycle's stage history over the API | [Cycles](/running/cycles/#stage-history) |
| Watch how work actually flows through the stages | [Delivery metrics](/running/metrics/) |

## Next steps

[Review & QA gates](/concepts/review-gates/)
  [Cycles](/running/cycles/)
  [Delivery metrics](/running/metrics/)
  [Agents & orchestration](/concepts/agents/)