Files
mangaBookmark/.claude/skills/plan-tickets/SKILL.md
T
sulthan faa80c41ea Skills: split plan-tickets out of implement-tickets (#162)
Adds `.claude/skills/plan-tickets/SKILL.md` and trims `implement-tickets` to dispatch-only, with the matching `.omp/agents/ticket-implementer.md` update.

Docs/skills only — no backend, userscript, or web changes.

Reviewed-on: #162
Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com>
Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
2026-08-22 16:43:42 +07:00

126 lines
5.1 KiB
Markdown

---
name: plan-tickets
description: "Plan a batch of tickets and write the briefs for its next wave: read the tracker, decide waves and contracts, get the plan approved."
disable-model-invocation: true
---
# Plan tickets
You produce the two artifacts the `implement-tickets` skill runs on: a **plan
file** and one **brief** per ticket in the next wave. You write no ticket code
and create no worktrees — that is the runner's half.
Ticket source and tracker conventions: `docs/agents/issue-tracker.md`. `tea` usage: skill `gitea`.
Called twice in a batch's life, at least: once to open it, then again after each
wave lands, because a later wave's briefs may need what the last one changed. On
a re-entry, read the existing `.scratch/<batch-slug>/plan.md` first and plan only
the next unlanded wave — the waves and contracts already approved there stand
unless the landed wave proved one wrong.
## 1. Collect the tickets
The user's argument is the selector: issue numbers, a label, a parent issue, or
nothing. With nothing, take the open issues labelled `ready-for-agent`.
Fetch each with `tea issue <n> --comments`, and read the **whole** body —
acceptance criteria and the `Blocked by` line are what the rest of this skill
runs on. A ticket whose blockers are still open is out of this batch unless a
blocker is also in it. Read the issue each ticket refers to, its parent or spec,
the same way: nothing on the implementation path reads the tracker after you —
only `cr-spec` does, at review time — so a decision that lives in a comment
reaches the implementer only if you carry it into the brief.
## 2. Plan the batch
Explore enough of the codebase to write briefs a fresh context can act on: the
files each ticket lands in, the patterns it must follow, the `AGENTS.md`
invariants it touches.
Then decide three things:
- **Waves.** Blocking edges set the order; tickets with no open blocker inside
the batch share a wave. Cap each wave at **3** concurrent tickets unless the
user set another width.
- **Contracts.** Two tickets in one wave that meet at a function signature, a
JSON shape, a table column, or a token name: you decide the shape now and
write the identical wording into both briefs. A contract left for the
subagents to negotiate is a merge conflict you scheduled.
- **Splits.** A ticket too big for one fresh context window goes into the wave
as two briefs, or back to the user.
## 3. Write the artifacts
Pick a `<batch-slug>` — short, from what the batch is about — and write
`.scratch/<batch-slug>/plan.md`. It is the handoff: the runner is a fresh context
that reads this and nothing of your reasoning.
<plan-template>
# Batch <batch-slug>
**Base branch.** The branch every worktree forks from and merges back into.
**Waves.** A table: wave number, ticket number, title, brief path, and status —
`planned` | `dispatched` | `landed` | `handed back`. Every ticket in the batch,
including waves not briefed yet.
**Contracts.** Each cross-ticket contract verbatim, naming both ticket numbers.
**Assumptions.** What you had to assume, and what the user corrected at approval.
</plan-template>
Then write a brief per ticket in the next wave to
`.scratch/<batch-slug>/t<n>-brief.md`, using the template below, in the
ubiquitous language of `CONTEXT.md` — a brief that says "scrape" where the domain
says Poll hands the subagent the wrong model of the system.
<brief-template>
# Ticket #<n> — <title>
**Decisions.** Whatever the ticket's comments or its parent spec settled that
the body never got updated with, restated verbatim. The implementer reads this
brief and the code, never the tracker — a decision missing here is lost to it,
and a stale comment thread is not a source you want a fresh context guessing
from. Omit only when the ticket has no comments.
**Goal.** The end-to-end behaviour this ticket makes work, from the user's side.
**Acceptance criteria.** Verbatim from the ticket.
**Contract.** The exact shared signatures / shapes / names this ticket must
implement or consume, and which sibling ticket is on the other end. Omit when
the ticket touches nothing shared.
**Where it lands.** The files and packages, and the existing pattern to follow
in each.
**Binding invariants.** The `AGENTS.md` rules this change can break — name them.
**TDD seams.** Where a test comes first — run the `tdd` skill at each one and
follow its red → green loop. Or "none — verify after".
**Verify.** The exact commands, e.g. `cd backend && go test ./...`,
`node --test userscript/test/logic.test.js`.
**Out of scope.** What not to touch, especially a sibling ticket's files.
</brief-template>
## 4. Get the plan approved
Present, and stop:
- the wave list, and for each ticket in the next wave: number, title, one-line
brief summary, the files or areas it will touch, its verification commands
- every cross-ticket contract, verbatim as it appears in the briefs
- anything you had to assume
Wait for approval. Apply the user's edits to the plan, do not relitigate them —
into the files, not just the reply, or the runner never sees them.
Then hand off: name the batch slug and the wave, and stop. Running the wave is
`implement-tickets`.