Ticket changes land only in the gitignored .pql/pql.db; the post-checkout/post-merge hooks rebuild it from the committed changelog on every branch switch, so un-exported tickets vanish silently (this is how the T-208-T-225 tree was lost). Add an export-and-commit step to Step 3a and a matching anti-pattern, cross-linked to the pql skill. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9.5 KiB
name, description, user-invocable, allowed-tools
| name | description | user-invocable | allowed-tools |
|---|---|---|---|
| whats-next | Surface the best batch of tickets to pick up next from pql. Walks the initiative/epic tree, filters to unblocked work, refines context via parallel agents (or `pql ticket refine` for empty descriptions), and optionally activates the batch on a fresh branch. Use when the user says "what's next", "next batch", "pick up work", or invokes /whats-next. NOT triggered by "what should we work on" in a design context — that's a discussion, not a batch selection. | true | Bash, Read, Grep, Glob, Agent, AskUserQuestion |
What's Next
Dependency-driven batch selection against pql. Three steps: batch selection → refinement review → batch activation.
Pql is the single source of truth for tickets and decisions in this repo
(see pql skill and decisions/README.md). Always run from the repo root.
Step 0: Sync state
Decisions on disk may be ahead of pql.db. Always sync before reading:
pql decisions sync
If pql is missing, stop and tell the user — don't fall back to grep.
Step 1: Batch Selection
1a. Find active top-level work
Pql has no milestone concept; initiatives (and large epics) play
that role. List in-flight top-level work:
pql ticket list --status in_progress --pretty
pql ticket list --status ready --pretty
If nothing is in_progress or ready at the initiative/epic level,
fall back to pql plan status --pretty for a dashboard read and ask the
user which area to advance.
1b. Build the work landscape
For each candidate epic or initiative, read its full descendant subtree
(nested, with the direct parent in ancestors) — one call, no client-side
flattening (pql ≥ 1.6.0):
pql ticket show <id> --tree --pretty # add --depth N to cap levels
This replaces the old --with-children + hand-rolled status summaries.
1c. Filter to unblocked, actionable leaves
Don't walk blockers per ticket — pql does it. Compose the list filters
(pql ≥ 1.6.0): --leaf (no children), --unblocked (every blocker is
done/cancelled), and --status (since --leaf/--unblocked are
structure/blocker-state only and would otherwise include done leaves):
pql ticket list --under <epic-id> --leaf --unblocked --status backlog --pretty
--status takes a SINGLE value (not a comma list — backlog,ready matches
nothing and silently returns []). The repo is almost all backlog; if a
team uses ready, run it a second time with --status ready.
That returns exactly the actionable, unblocked leaves under the epic — the
multi-result complement to pql plan whatsnext (which now also skips blocked
tickets, for the single best pick). Note --unblocked only means no ticket
blocker is open; a ticket "blocked on upstream" in prose (e.g. T-158) still
shows — read the description before batching.
1d. Rank and group
Rank unblocked tickets by:
- Priority (critical > high > medium > low) — read from ticket fields.
- Epic proximity to done — for each epic parent, compute
done_children / total_children. Higher ratio ranks higher: finishing an epic unlocks downstream work and tightens the board. - Fan-out — tickets that unblock the most other tickets rank higher.
Approximate by scanning
pql ticket list --status backlog --prettyand counting how many list this ticket in their blockers (use--with-blockersper candidate, or read--jsonlonce and reduce in memory).
Group into epic-sized batches: tickets sharing a parent_id, or a
logical cluster if no shared parent. If nothing groups naturally, batch
by area (the directory the work touches, e.g. lib/src/pty/).
1e. Show the board
pql ticket board --pretty
This is the "what's currently in flight" view — the user wants to see WIP before committing to more.
1f. Present the recommended batch
Show the user:
- The recommended batch — IDs, titles, priorities, parent epic.
- Why this batch — which epic it advances, what it unblocks downstream.
- Current board state (WIP count vs. ready/backlog).
- One or two alternative batches worth considering.
Wait for user confirmation before Step 2.
Step 2: Ticket Refinement Review
Two cases — handle the cheap one first.
2a. Tickets with empty descriptions → use pql
If any ticket in the batch has no description, hand off to pql's built-in refinement flow:
pql ticket refine list --pretty
pql ticket refine next --pretty # full context for the next one
pql ticket refine write T-NN '{"description":"..."}'
Walk these with the user (AskUserQuestion per ticket if appropriate) before moving on.
2b. Tickets with descriptions → spawn refinement agents
For each ticket that already has a description but may still be
under-specified, spawn one agent in parallel. Use general-purpose
subagent_type (custom subagent_types lose SendMessage):
Agent({
subagent_type: "general-purpose",
model: "sonnet",
description: "Refine T-NN context",
prompt: "You are the Refinement Manager for ticket T-NN.
Ticket: <title>
Description: <body>
Decision ref: <D-NN or Q-NN, if set>
Your job:
1. Run `pql decisions show <decision_ref> --with-refs --pretty` and
read the linked D/Q-record in decisions/<domain>.md.
2. Grep decisions/questions-*.md for related Q-records.
3. Verify referenced files, classes, and APIs actually exist in the
current tree (Read/Grep). Flag dangling references.
4. Cross-check against CLAUDE.md guardrails (single process, CLI-first,
own the rendering stack, etc.) — flag tickets that conflict.
Assess: does an implementer have enough context to proceed without
guessing? Report exactly one of:
- READY: <one-paragraph summary of what the implementer needs to know>
- GAPS: <list of specific ambiguities, each with 2–3 options>"
})
Run all agents in parallel (single message, multiple Agent tool calls).
2c. Resolve gaps
For each ticket that came back GAPS, surface ambiguities to the user
via AskUserQuestion. After the user resolves, append the resolution to
the ticket with pql ticket append (pql ≥ 1.6.0) — it appends
blank-line-separated WITHOUT round-tripping the existing description, so
there's no JSON-splicing or read-modify-write:
pql ticket append T-NN "Refinement (<date>): <resolution>"
# longer notes: pql ticket append T-NN --file note.md (or --stdin)
(Use append, not refine write — the latter replaces the whole
description from a JSON patch and forces you to re-send the existing body.)
If a gap really requires a new D-record (architectural choice, not just
detail), flag it. Ask whether to write the D-record now (pql decisions claim D <domain> "title" then author the markdown) or defer with a note
on the ticket.
2d. Present refined batch summary
Per ticket:
- READY summary, or the resolution the user just gave.
- Linked D/Q-records.
- Remaining blockers (should be none — re-check if Step 1 was a while ago).
Ask: "Batch ready. Activate?"
Step 3: Batch Activation
3a. Mark tickets in_progress
Batch transition (comma-separated IDs):
pql ticket status T-1,T-2,T-3 in_progress
Then persist it. Ticket mutations (status here, and any ticket new in
Step 2) land only in the gitignored .pql/pql.db. The post-checkout/post-merge
hooks rebuild that DB from the committed changelog on every branch switch — so
un-exported changes vanish silently the next time anyone switches branches. After
creating or transitioning tickets, always:
pql plan export # regenerates .pql/changelog/*.sql
git add .pql/changelog && git commit # durable; survives rebuild
See the pql skill.
3b. Branch? Default no.
Solo-dev flow on this repo — work lands directly on main (see recent
git log). Don't create a topic branch unless the user explicitly asks.
If they do, plain git checkout -b is fine; there is no gh CLI.
3c. Spawn implementation agents (optional)
If the user wants agents driving the work, spawn general-purpose
subagents (model: sonnet) per ticket. Each prompt should include:
- Ticket details + the refinement summary from Step 2.
- The full content of any linked D-record (Read it and inline it — don't just cite the ID; the agent has no project memory of it).
- Repo guardrails the work touches (from CLAUDE.md — quote the relevant bullets, don't link).
- A RULES block: write files only, no git commits, no destructive ops, message back when blocked or done.
3d. Report
End with a tight summary:
- Branch.
- Tickets now
in_progress. - Agents spawned (if any).
- Next step: implement, then commit per the git-commit skill.
Anti-patterns
- Don't skip Step 0 — stale
pql.dbmakes the rest of the skill lie. - Don't leave ticket changes un-exported —
pql.dbis gitignored and the post-checkout/post-merge hooks rebuild it from the committed changelog, so a branch switch silently drops un-exported tickets. Alwayspql plan export+ commit.pql/changelog/after mutating tickets (Step 3a). - Don't activate a batch the user hasn't confirmed.
- Don't spawn refinement agents for tickets that have no description — use
pql ticket refineinstead; it's cheaper and writes back through the proper channel. - Don't reach for
gh— this system doesn't have it. Plaingitonly. - Don't
cdinto subdirectories — run everything from the repo root.