backlog · git:20260813.ecfd6fb · 2026-08-13 · sha256 1ebf75df8573eefe

backlog git:20260813.ecfd6fbA

Immutable. This exact content is served forever at /api/v1/blob/1ebf75df8573eefe.

---
name: backlog
description: "Manage the backlog — plan, track, navigate phases and epics. Use when planning phases, viewing roadmaps, or restructuring work."
effort: medium
model: sonnet
keywords: [tasks, planning, roadmap, milestones, phases, tracking, priority]
task_strategies: [feature, refactor]
argument-hint: "[status|add|start|done|next|roadmap|plan|triage|tags|context|theme|sync] [args]"
group: brana
allowed-tools:
  - Read
  - Write
  - Edit
  - Glob
  - Grep
  - Bash
  - AskUserQuestion
  - Task
  - mcp__ruflo__memory_search
  - mcp__ruflo__claims_claim
  - mcp__ruflo__claims_release
  - mcp__ruflo__claims_mark-stealable
  - TaskCreate
  - TaskList
  - TaskUpdate
  - ToolSearch
status: stable
growth_stage: evergreen
---

# Backlog

Manage the project backlog — plan, track, and navigate work across phases,
milestones, and epics. Natural language is the primary interface;
these commands are shortcuts for complex operations.

## When to use

When explicitly managing the backlog: planning phases, viewing roadmaps,
restructuring work. Daily task interaction happens through natural
language guided by the task-convention rule — no skill invocation needed.

## CLI Integration — MANDATORY

**NEVER read or write tasks.json directly.**

**Prefer MCP tools** (brana server) when available — structured JSON, 65% fewer tokens:

### Initiative Model (v3)

**Epics are hierarchy nodes, not a field** (ADR-065). An epic is a top-level task with `type: "epic"` whose `subject` is the epic slug (e.g. `"cc-alignment"`). A task belongs to an epic through its `parent` chain — its nearest `type: "epic"` ancestor (walk helper: [`../_shared/epic-ancestor-walk.md`](../_shared/epic-ancestor-walk.md)).

> **Retired — flat `epic` field.** The pre-v3 flat `epic` string field is gone and its set/add write paths are sealed (t-2310): `backlog_set(field: "epic")` and `brana backlog set <id> epic <slug>` are hard-rejected with `unknown field: epic`, and `brana backlog add --epic` is a warned no-op. Never set or create the field. Epic membership is written by setting `parent` to an epic node's id.
>
> **Mid-migration caveat (t-2698):** the ADR-065 backfill (promote old epic slugs to nodes, re-parent tasks) has only run in some projects (e.g. thebrana). In a project whose tasks.json has no `type: "epic"` nodes yet, first create the epic node (`brana backlog add --subject "<slug>" --type epic`), then parent tasks to it — or, if restructuring isn't warranted yet, tag tasks `epic:<slug>` as the interim marker (see below). Never resurrect the flat field.

**Lightweight epic tag — `epic:<slug>`.** The namespaced tag `epic:<slug>` (e.g. `epic:cc-alignment`) is the sanctioned lightweight epic marker: a memorable grouping label for tasks of any size. Use it (a) as the interim marker in un-migrated projects (caveat above), and (b) as an extra cross-cutting handle anywhere a greppable epic label helps. It reads/writes like any tag — `backlog_set(field: "tags", value: "+epic:cc-alignment")` / `brana backlog set <id> tags +epic:cc-alignment` — and filters like any tag: `backlog_query(tag: "epic:cc-alignment")` / `brana backlog query --tag epic:cc-alignment`. The namespace prefix keeps it from colliding with ordinary tags. Limits: tags do NOT feed `focus`, the `--epic` filters, or branch naming — where epic nodes exist, the parent chain stays authoritative; parent to the node first and add the tag only when the extra label earns its keep.

Tasks keep one v3 metadata field:

| Field | Values | Purpose |
|-------|--------|---------|
| `work_type` | `implement` / `research` / `design` / `infra` / `review` / `chore` | Cognitive mode — what kind of work this is. Note: `kind: refactor` tasks use `work_type: implement`. |

**Active epic** is set in the project-local `.claude/tasks-config.json` → `active_epic` (per-repo, never the global `~/.claude/tasks-config.json` — ADR-066, t-2158). It stores the epic *slug* — i.e. an epic node's `subject`. When set, `backlog_focus` / `brana backlog focus` shows ★-marked tasks from that epic first, then P0/P1 overflow from others.

### MCP tools (preferred)

| Operation | MCP tool |
|-----------|---------|
| Get task | `backlog_get(task_id: "t-123")` |
| Get field | `backlog_get(task_id: "t-123", field: "status")` |
| Query tasks | `backlog_query(status: "pending", work_type: "implement")` or `backlog_query(kind: "fix")` |
| Filter by epic | `backlog_query(epic: "cc-alignment")` — read-only; resolves membership via the parent chain (flat `epic` field retired, ADR-065) |
| List epic nodes | `backlog_query(task_type: "epic")` |
| Filter by work type | `backlog_query(work_type: "implement", status: "pending")` |
| Multi-tag AND | `backlog_query(tag: "dx,cli")` |
| Filter by parent | `backlog_query(parent: "ph-001", task_type: "task")` |
| Search | `backlog_search(query: "enforcement")` |
| Aggregate stats | `backlog_stats()` |
| Set field | `backlog_set(task_id: "t-123", field: "status", value: "in_progress")` |
| Approve AC | `backlog_ac_approve(task_id: "t-123")` — promotes proposed_acceptance_criteria + sets `ac_state:approved` (ADR-079, t-2812). `backlog_set(field: "ac_state", value: "approved")` is rejected — this verb is the only path |
| Assign to epic | `backlog_set(task_id: "t-123", field: "parent", value: "<epic-node-id>")` — membership = parent chain (ADR-065); `field: "epic"` is retired and rejected (`unknown field: epic`) |
| Add/remove tag | `backlog_set(task_id: "t-123", field: "tags", value: "+newtag")` |
| Append text | `backlog_set(task_id: "t-123", field: "context", value: "note", append: true)` |
| Create task | `backlog_add(subject: "...", kind: "feature", task_type: "task")` |
| Create under epic | `backlog_add(subject: "...", parent: "<epic-node-id>", work_type: "implement")` — `epic:` param is retired (ADR-065) |
| Focus (top tasks) | `backlog_focus(top: 5)` or `backlog_focus(work_type: "research")` |

### CLI fallback (when MCP unavailable)

| Operation | CLI command |
|-----------|------------|
| Project status | `brana backlog status` |
| Cross-client status | `brana backlog status --all --json` |
| Full roadmap tree | `brana backlog roadmap --json` |
| Subtree of phase | `brana backlog tree <id> --json` |
| Aggregate stats | `brana backlog stats` |
| Tag inventory | `brana backlog tags --output json` |
| Tag filter (AND) | `brana backlog tags --filter "a,b" --output json` |
| Next unblocked task | `brana backlog next --kind feature --tag Y` |
| Query tasks | `brana backlog query --status pending --kind fix --output json` |
| Filter by epic | `brana backlog query --epic cc-alignment` — read-only; resolves via parent chain (flat `epic` field retired, ADR-065) |
| List epic nodes | `brana backlog query --type epic` (works since t-2377) — or MCP `backlog_query(task_type: "epic")` |
| Filter by work type | `brana backlog query --work-type implement --status pending` |
| Multi-tag AND query | `brana backlog query --tag "dx,cli" --count` |
| Filter by parent | `brana backlog query --parent ph-001 --type task` |
| Get full task | `brana backlog get <id>` |
| Get single field | `brana backlog get <id> --field status` |
| Focus (active epic) | `brana backlog focus` |
| Focus by work type | `brana backlog focus --work-type research` |
| Focus override epic | `brana backlog focus --epic cc-alignment` — read-only; epic resolved from nodes, not the retired flat field (ADR-065) |

### Write operations

| Operation | CLI command |
|-----------|------------|
| Set any field | `brana backlog set <id> <field> <value>` |
| Assign to epic | `brana backlog set <id> parent <epic-node-id>` (membership = parent chain, ADR-065; `set <id> epic <slug>` is retired → `unknown field: epic`) |
| Set work type | `brana backlog set <id> work_type implement` |
| **Set active epic** | `brana backlog set-active <slug>` (per-repo — writes project-local `.claude/tasks-config.json`, t-2155) |
| Set to null | `brana backlog set <id> priority null` |
| Append to text | `brana backlog set <id> context --append "note"` |
| Add/remove tag | `brana backlog set <id> tags +newtag` / `tags -oldtag` |
| Add blocked_by | `brana backlog set <id> blocked_by +t-100` |
| Create task (JSON) | `brana backlog add --json '{"subject":"...","kind":"feature","type":"task"}'` |
| Create task (shorthand) | `brana backlog add --subject "..." --kind feature --type task --tags "a,b" --effort S` |
| Create under epic | `brana backlog add --subject "..." --parent <epic-node-id> --work-type implement` (the `--epic` flag is DEPRECATED per ADR-065 — it parses but no-ops with a stderr warning) |
| Create epic node | `brana backlog add --subject "<slug>" --type epic` (`epic` is a valid `--type` on add — t-2322) |
| Create in another project | `brana backlog add --subject "..." --project <slug>` (cross-project via portfolio; default = current project, t-2155) |
| Create initiative | `brana backlog add --subject "..." --kind feature --type initiative` |
| Create task (from file) | `brana backlog add --json @/tmp/task.json` |
| Create task (stdin) | `echo '{"subject":"..."}' \| brana backlog add --json -` |
| Rollup parents | `brana backlog rollup` |
| Approve AC | `brana backlog ac <id> approve` — promote + flip to `ac_state:approved` (ADR-079, t-2812); `set <id> ac_state approved` is rejected. AC edits on an approved task reset it to `proposed` |

### Rules

1. **Prefer MCP tools** (`backlog_query`, `backlog_get`, `backlog_set`, `backlog_add`, `backlog_search`, `backlog_stats`) when available. Fall back to CLI if MCP server is not running.
2. **Every "Read tasks.json" instruction below → call MCP tool or CLI command.**
3. **Every "Write tasks.json" instruction below → call `backlog_set`/`backlog_add` (MCP) or `brana backlog set`/`brana backlog add` (CLI).**
4. For batch creates (plan command), call `backlog_add` once per task.
5. All operations return JSON. MCP returns structured data natively; CLI returns JSON on stdout.
6. All writes are atomic — no need to read-modify-write.
7. Both MCP and CLI auto-detect tasks.json from git root.


## Phase Protocol — how to execute this skill

The subcommand procedures live in per-phase files under `phases/` (this skill's base directory). **Never execute a subcommand from memory.** Three rules:

1. **On invocation:** parse the subcommand from the arguments, then Read its phase file from the PHASES registry below BEFORE doing any of its work. A phase you have not Read this session does not exist — do not improvise its steps.
2. **When a subcommand chains into another** (e.g. `start` proposing `execute`, `done` after `start`): Read the new subcommand's phase file at that boundary.
3. **On resume after compression:** identify the active subcommand (CC TaskList `/brana:backlog — {STEP}` entries, or the conversation), then Read its phase file before continuing. Previously loaded phase content did NOT survive compression.

<!-- PHASES -->
| Subcommand(s) | File | Load when |
|------|------|-----------|
| plan | phases/plan.md | `/brana:backlog plan` invoked |
| status, roadmap, next | phases/views.md | Any view subcommand invoked |
| start (+ `/brana:do` freeform routing) | phases/start.md | `/brana:backlog start` or `/brana:do` invoked |
| done, add, replan, archive, migrate | phases/done-and-add.md | Any of these subcommands invoked |
| tags, context, theme | phases/tags-context-theme.md | Any of these subcommands invoked |
| execute | phases/execute.md | `/brana:backlog execute` invoked |
| triage, sync | phases/triage-sync.md | Either subcommand invoked |
| Display themes + task-line/wide templates | phases/display-themes.md | Before rendering any themed view (status, roadmap, next, tags) |
<!-- /PHASES -->

In the deployed-plugin layout the same relative paths apply: `{base-dir}/phases/{file}`. If a path doesn't resolve, use Glob: `**/skills/backlog/phases/{file}`.

## Commands

- `/brana:backlog plan [project] "[phase-title]"` — plan a phase interactively
- `/brana:backlog status [project] [--all] [--unified] [--wide]` — progress overview (`--all` = cross-client task drill-down, `--unified` = priority-sorted flat list)
- `/brana:backlog roadmap [project] [--wide]` — full tree view with all levels
- `/brana:backlog next [project] [--wide]` — next unblocked task by priority
- `/brana:backlog start <id>` — begin work on a task
- `/brana:backlog done [id]` — complete current task
- `/brana:backlog add "[description]"` — quick-add a task
- `/brana:backlog replan [project] [phase-id]` — restructure a phase
- `/brana:backlog archive [project]` — move completed phases to archive
- `/brana:backlog migrate <file>` — import tasks from a markdown backlog
- `/brana:backlog execute [scope] [--dry-run] [--max-parallel N] [--retry]` — execute tasks via subagents
- `/brana:backlog tags [project]` — tag inventory, filtering, and bulk tag management
- `/brana:backlog context <id> [text]` — view or set rich context on a task
- `/brana:backlog theme [name]` — view or set display theme (classic, emoji, minimal)
- `/brana:backlog triage [project] [--reresearch] [--scope P2+]` — research-informed priority reassessment
- `/brana:backlog sync [--dry-run] [--force]` — sync tasks.json with GitHub Issues

---

## Step Registry (plan and execute subcommands)

For the `plan` and `execute` subcommands, create a CC Task step registry on entry. Follow the [guided-execution protocol](../_shared/guided-execution.md). Other subcommands (status, roadmap, next, add, etc.) are single-step and don't need a registry.

**plan steps:** DETECT, READ, MILESTONES, TASKS, DEPS, PROPOSE, CHALLENGE, WRITE
**execute steps:** READ, FILTER, WAVES, CONFIRM, EXECUTE, WRITEBACK, REPORT

### Resume After Compression

If context was compressed during a plan or execute flow:

1. Call `TaskList` — find CC Tasks matching `/brana:backlog — {STEP}`
2. The `in_progress` task is your current step — resume from there

---

## Field Notes

### 2026-06-10: `deleted` is not a valid task status — use `cancelled`
`brana backlog set <id> status deleted` returns `{"ok":false,"error":"invalid status \"deleted\" — must be pending/in_progress/completed/cancelled or null"}`. The correct status for superseded, extracted, or migrated tasks is `cancelled`. When marking tasks cancelled, add a context note explaining why: `brana backlog set <id> context --append "[t-NNN] cancelled: moved to clients/proyecto-anita/..."`. There is no `deleted` status in the CLI schema (E2026-06-10-6).
Source: t-1950 client migration 2026-06-10