From faa80c41eae8acba313737351424483cccd51f73 Mon Sep 17 00:00:00 2001 From: Sulthan Zaki Date: Sat, 22 Aug 2026 16:43:42 +0700 Subject: [PATCH] Skills: split plan-tickets out of implement-tickets (#162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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: https://gitea.violetcrown.my.id/sulthan/mangaBookmark/pulls/162 Co-authored-by: Sulthan Zaki Co-committed-by: Sulthan Zaki --- .claude/skills/implement-tickets/SKILL.md | 118 ++++++-------------- .claude/skills/plan-tickets/SKILL.md | 125 ++++++++++++++++++++++ .omp/agents/ticket-implementer.md | 31 +++--- 3 files changed, 172 insertions(+), 102 deletions(-) create mode 100644 .claude/skills/plan-tickets/SKILL.md diff --git a/.claude/skills/implement-tickets/SKILL.md b/.claude/skills/implement-tickets/SKILL.md index 9f3b088..95d4b81 100644 --- a/.claude/skills/implement-tickets/SKILL.md +++ b/.claude/skills/implement-tickets/SKILL.md @@ -1,108 +1,49 @@ --- name: implement-tickets -description: "Orchestrate a batch of tickets: plan the briefs, then hand each ticket to its own implementer subagent in its own worktree." +description: "Run a planned wave of tickets: one implementer subagent per ticket in its own worktree, then land, merge and close what comes back." disable-model-invocation: true --- # Implement tickets -You are the **orchestrator**. You write briefs, dispatch, land results, and talk -to the tracker. You do not write the implementation — every line of ticket code -is written by a `ticket-implementer` subagent in its own git worktree. Reach for -the editor yourself only for a merge conflict resolution. +You are the **orchestrator**. You dispatch, land results, and talk to the +tracker. You do not write the implementation — every line of ticket code is +written by a `ticket-implementer` subagent in its own git worktree. Reach for the +editor yourself only for a merge conflict resolution. Ticket source and tracker conventions: `docs/agents/issue-tracker.md`. `tea` usage: skill `gitea`. -## 1. Collect the tickets +## 0. Load the plan -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`. +Your argument is the batch slug. Read `.scratch//plan.md` — it gives +the base branch, the waves, the contracts, and each ticket's brief path and +status. Run the earliest wave that is not landed. -Fetch each with `tea issue --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. +The briefs are the requirements and they are already approved: read each one you +are about to dispatch, but do not rewrite it, and do not fetch the tickets from +the tracker to second-guess it. A brief that is wrong or thin is a `plan-tickets` +problem — say so and stop, rather than patching it here. -## 2. Plan the batch +No plan file, or no briefs for the next wave: run `plan-tickets` first. That +skill owns wave membership, contracts, and every brief. -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. Get the plan approved - -Present, and stop: - -- the wave list, and for each ticket: number, title, one-line brief summary, - the files or areas it will touch, its verification commands -- every cross-ticket contract, verbatim as it will appear in the briefs -- anything you had to assume - -Wait for approval. Apply the user's edits to the plan, do not relitigate them. - -## 4. Run a wave +## 1. Dispatch the wave Per ticket, before dispatch: ```bash -git worktree add ../ticket- -b ticket/- # base = the branch you are on +git worktree add ../ticket- -b ticket/- # base = the plan's base branch, checked out here cp .env ../ticket-/ 2>/dev/null # gitignored, worktrees do not get it tea issue edit --add-assignees # tea login list has it ``` -Write the brief to `.scratch//t-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. Then dispatch the whole wave in **one** `task` batch, every item on the `ticket-implementer` agent. Each dispatch names: the absolute brief path, the worktree path, the branch, the base ref, and the report path -`.scratch//t-report.md`. +`.scratch//t-report.md`. Mark each ticket `dispatched` in the plan +file. - - -# Ticket # — - -**Read first.** `tea issue <n> --comments` for this ticket, then the issue it -refers to — the parent or spec — the same way. The comments carry decisions the -body never got updated with. This brief stays the requirements; those two reads -are the intent behind them. - -**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> - -## 5. Land the wave +## 2. Land the wave The wave is landed when every ticket in it is closed, reverted, or handed back to the user. Per returned ticket: @@ -120,14 +61,17 @@ clash — both sides green apart, wrong together — goes back to whichever tick owns the contract, as a re-dispatch with the collision described. Then `tea comment <n> "<the report summary>"`, `tea issue close <n>`, and -`git worktree remove ../ticket-<n>`. Keep the report file. +`git worktree remove ../ticket-<n>`. Keep the report file, and mark the ticket +`landed` or `handed back` in the plan file. -Only once the whole wave is landed does the next wave start — its briefs may -need what this one changed. +## 3. Hand back or close the batch -## 6. Close the batch +Waves left in the plan: stop and say which wave is next. Its briefs are written +by `plan-tickets` against the base you just changed — that is why they were not +written up front, and why you do not write them. -Run the full suite once on the merged base, and report: a line per ticket with -its status, commits, and open concerns, plus anything still assigned or open on -the tracker. A red suite after every ticket went green is an interaction bug — -diagnose it, name the two tickets, and fix it or hand it back with both named. +Last wave landed: run the full suite once on the merged base, and report a line +per ticket with its status, commits, and open concerns, plus anything still +assigned or open on the tracker. A red suite after every ticket went green is an +interaction bug — diagnose it, name the two tickets, and fix it or hand it back +with both named. diff --git a/.claude/skills/plan-tickets/SKILL.md b/.claude/skills/plan-tickets/SKILL.md new file mode 100644 index 0000000..0251b4a --- /dev/null +++ b/.claude/skills/plan-tickets/SKILL.md @@ -0,0 +1,125 @@ +--- +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`. diff --git a/.omp/agents/ticket-implementer.md b/.omp/agents/ticket-implementer.md index 7d422b0..216be13 100644 --- a/.omp/agents/ticket-implementer.md +++ b/.omp/agents/ticket-implementer.md @@ -24,34 +24,35 @@ Your branch is already checked out there. Never `git checkout`, `git switch`, ## Order of work -1. Read the brief file. It is the single source of requirements — use its exact - values verbatim. -2. Read the ticket and the issue it refers to, as the brief's **Read first** - section names them: `tea issue <n> --comments` for each. The ticket's - comments and its parent carry the intent and the decisions behind the brief. - Read no other ticket and no other brief. -3. Read `AGENTS.md` in the worktree, plus the nested `AGENTS.md` for the area +1. Read the brief file. It is the only statement of requirements you get — use + its exact values verbatim, and read nothing from the tracker. The + orchestrator has already read the ticket, its comments and its parent spec, + and folded every live decision into the brief; the threads themselves also + hold reversed and rejected ones you cannot tell apart from here. +2. Read `AGENTS.md` in the worktree, plus the nested `AGENTS.md` for the area you touch. Its invariants bind you: security rules, design system, comment policy. -4. Ask before writing code if requirements, acceptance criteria, approach, or +3. Ask before writing code if requirements, acceptance criteria, approach, or dependencies are unclear. Asking is free; guessing is not. -5. Implement exactly what the brief specifies. At each TDD seam the brief names, +4. Implement exactly what the brief specifies. At each TDD seam the brief names, run the `tdd` skill and follow its red → green loop. Follow the patterns already in the codebase; improve what you touch, restructure nothing outside the ticket. -6. Verify. Focused tests while iterating, the brief's full verification commands +5. Verify. Focused tests while iterating, the brief's full verification commands once at the end. Test output must be pristine. -7. Commit to your branch. Reference the ticket number in the subject. -8. Review (below), fix, re-verify, commit the fixes. -9. Write the report file, then return the status contract. +6. Commit to your branch. Reference the ticket number in the subject. +7. Review (below), fix, re-verify, commit the fixes. +8. Write the report file, then return the status contract. ## Review After your first green commit, run the **`code-review`** skill over `<base ref>...HEAD` in the worktree, with two changes to how it dispatches: use the **`cr-spec`** agent for the Spec axis and **`cr-standards`** for the -Standards axis, both in one batch, and give the Spec axis your brief file plus -the ticket body as the spec. +Standards axis, both in one batch, and hand the Spec axis your brief file as the +spec plus the ticket number from the brief's title, telling it to read the +ticket itself (`tea issue <n> --comments`). The tracker check belongs in that +read-only context, not in yours. Fix every Critical and Important finding, then re-run the tests that cover the amended code. Two fix rounds maximum: anything still open after that goes in the