writing-good-tickets
Write, file, or update an issue or ticket that an agent or a developer can take to one PR. Use when filing a bug or feature, updating an issue, or breaking a plan into tickets.
- License 许可
- MIT
- 最近更新
- 2026-11-03
- Stars
- ★ 10
- Forks
- 2
01 前言 Front Matter
- name
- writing-good-tickets
- description
- Write, file, or update an issue or ticket that an agent or a developer can take to one PR. Use when filing a bug or feature, updating an issue, or breaking a plan into tickets.
- user-invokable
- false
- disable-model-invocation
- false
02 资源文件 1
- 参考文档agents/openai.yaml42 B
03 SKILL.md 正文
Writing good tickets
A ticket hands one problem to someone who was not in the conversation, a developer or an agent, who takes it to one PR. It answers, in order: what goes wrong today and for whom, what shows it, how anyone will know it is fixed, and what to read before starting. The closing PR proves each ## Done when item with a witness, per the writing-good-prs skill.
Edit the prose with the unslop skill. Follow the repository's tracker and template conventions, starting from its issue tracker record, docs/agents/issue-tracker.md, when it has one. When the repository has an issue template, fill its sections and apply the rules below to the section that plays each role.
Everything the ticket points at is reachable by any developer with access to the repository: issues, PRs, CI runs, hosted media, and public URLs. Paths on your machine, such as your home directory, /tmp, a worktree, or an agent state folder, are reachable only by you. Paste what they hold instead. Say "on main" or name the released version where you saw it, rather than a commit hash.
Title
Write area: symptom, with no trailing period: the trigger and what the reader sees, for one failure. A cause or a remedy stays out of the title, because the symptom stays true when the guessed cause turns out wrong.
- Good:
subagents: an autonomous run sends one unit through five fix rounds until the operator stops it - Bad:
subagents: an autonomous run has no round count per unit, so nothing stops a third fix round, which names the missing mechanism instead of what the reader saw.
Body
## Problem
## Done when
- [ ]
## Suggested approach
## Context
## Problem and ## Done when are required. Drop any other section with nothing to say.
Problem
- Open with one story, in the present tense. Who hits it, the trigger, what happens, what should happen, and what it costs. For a feature, the story is the person and the moment the current behavior fails them, quoted in their words when you have them. This story is the baseline: the closing PR is judged by whether the same story now ends differently.
- Show the witness. Paste the decisive lines: output, a log excerpt, a screenshot, or a quoted report, with where you saw it and how often, such as
3 of 3 runs. - Give the recipe. The exact steps, run from a fresh clone of the repository after its normal setup. Say whether you reproduced it yourself, and write
reported, not reproducedwhen you did not.
Preserve the nuances from the conversation that an implementer would otherwise lose.
Done when
Each item is one behavior, written so a developer reads what must be true and an agent reads how to check it:
- [ ] **<the behavior, in plain words>.** Check: <the setup, the action, and the exact result to observe>.
- The check names a surface that anyone can run: a command and the output it must print, a test case and what it asserts, or a walk through the running app with the repository's
verify-*skill. - The first item replays the Problem's story with the new ending.
- When the fix could overshoot, give the boundary its own item: what must keep working as before, such as "real
pi --printlaunches are still refused". - A behavior the conversation settled, such as "a missing Java still fails the check", is an item here.
- An unknown that running something can settle is an item too, such as "The faster layout is kept. Check: prototype both and keep the one that renders in under 16 ms."
- Repository gates such as
vp run verifygo last, and never stand alone.
A ticket that still waits on a product call only a person can make is not ready. Ask that person before you file.
Suggested approach
Optional, and never binding: the implementer owns the how. Give it when you hold something that would save them time:
- The cause you suspect, marked
Hypothesiswith what you saw that points to it. - A possible approach and the alternative you would rule out, with the reason.
- A visual from the writing-good-prs Shape menu when it shows the idea faster than prose.
Name behavior and symbols, not file paths. Finding where a symbol lives is one search.
Context
List the material the implementer reads before starting that neither a code search nor the tracker gives them, each with one line on why it matters:
- Docs, specs, and external URLs the fix must follow.
- Attachments: logs, screenshots, recordings, and data, hosted where everyone can open them.
Relate other issues and PRs through the tracker itself, as a parent, a blocker, or a sub-issue, per the issue tracker record, so the link lives in one place. When another issue settled something this ticket depends on, state what it settled in Problem or Done when.
Example
The same ticket, condensed from a real one and written well:
delegate-guard: a delegate's read-only grep for launch strings is refused as a launch
## Problem
When a reviewer subagent greps the code for launch strings, the guard refuses the read-only search with "Delegates spawn nothing", so the reviewer cannot read the guard it is reviewing. None of these commands starts Pi. Reproduced on main, 3 of 3 runs, by saving this as `repro.ts` in a clone and running `bun repro.ts`:
```ts
import { spawnGuard } from "./agent/extensions/delegate-guard.ts";
const guard = spawnGuard(["node", "pi", "--print"])!;
for (const cmd of [
"grep -nE 'pi-subagent|pi --print' delegate-guard.ts",
'rg "foo; pi -p" .',
]) console.log(cmd, guard(cmd) === undefined ? "allowed" : "BLOCKED");
```
```text
grep -nE 'pi-subagent|pi --print' delegate-guard.ts BLOCKED
rg "foo; pi -p" . BLOCKED
```
## Done when
- [ ] **A delegate can search for launch strings.** Check: `delegate-guard.test.ts` runs both commands above as a delegate, and the guard allows each.
- [ ] **Real launches are still refused.** Check: the existing launch cases, including heredoc and `bg_start` launches, are still blocked.
- [ ] **The repository gate passes.** Check: `vp run verify` exits 0.
## Suggested approach
Hypothesis: the guard splits commands on `;` and `|` inside quotes, so the quoted words read as a `pi --print` command. Teaching the splitter shell quoting would fix it. Allowing every command that starts with `grep` or `rg` would not, because `rg x; pi -p` would then start Pi.
## Context
- The subagents skill's Kinds section defines delegates and owners and why a delegate starts nothing. The fix must keep that rule.
The same ticket, written badly:
delegate-guard: improve command parsing
## Problem
The regex in delegate-guard is broken and blocks valid commands. See /tmp/reflect-result.md.
## Done when
- [ ] Use a proper parser
- [ ] Add tests
Its title names a remedy instead of a symptom. Its Problem states a guessed cause as fact, names nobody who is hurt, and points at a file only its writer can open. Its Done when prescribes code instead of a behavior, gives no check anyone could run, and leaves out the boundary: nothing says real launches must still be refused.
Size
Size each ticket as a vertical slice. It cuts a narrow path through every layer it needs, is verifiable on its own, and fits in one agent session. Split a wide refactor into an expand ticket, migrate tickets in batches, and a contract ticket, each blocked by the one before.
Before you file
- Search the tracker for the same symptom, error text, and area. For a confident duplicate, add the new evidence to the existing issue instead of filing. For a possible match, file the new ticket, then comment on the match with a link to it and say why it is not a duplicate.
- For complex agent-facing workflow instructions inside a ticket, use the writing-for-agents skill.
Check the body
Write the body to a file and run both gates.
-
Structure. Run
../writing-good-prs/scripts/check-body.ts ticket <body-file> --title "<title>", with--template <path>when the repository has an issue template. Fix each printed problem and rerun until it exits 0. Exit 0 means the headings and title parse. It says nothing about the case the body makes. -
Implementer read. Give one subagent in the
cross-family reviewerrole, per the subagents skill, only the title and the body file. Ask it to:- Retell the problem as one story, with who it costs, and name the witness that shows it, or write
none visible. - For each Done-when item, say exactly what it would run and what result counts as done, or write
unclear. - As the implementer, list what it would still need to start, or write
nothing.
Run the read once. Fix every gap its answers show, then move on without a second read.
A delegate launches no subagent, so it writes the body file and names this read in its report for its parent to run.
- Retell the problem as one story, with who it costs, and name the witness that shows it, or write
Publish the same file through the tracker, then read the ticket back and compare what the tracker stored with the title and the body file. On GitHub, publish with gh issue create --body-file or gh issue edit --body-file, read back with gh issue view <n> --json title,body, and diff the body with gh issue view <n> --json body --jq .body | diff <body-file> -. Fix each difference at its cause, such as a shell expansion or a template the tracker applied, republish, and read it back once more. Report any difference that remains.
04 同仓库更多 Skills
changelog
Write the changelog entry for a pull request. Use when a PR changes behavior that users, operators, or integrators can notice.
writing-good-prs
Write or update a pull request title and body that a reviewer can trust and own. Use when opening a PR or editing its description.
writing-good-commits
Write or reword a git commit message and size the commit it describes. Use when committing, or when reshaping commits during a rebase.
writing-for-agents
Writing documents for agents. Use when creating or editing skills, or modifying AGENTS.md or CLAUDE.md.
wizard
Generate an interactive bash wizard that walks a human through steps only they can perform. Use when provisioning infrastructure, setting up credentials or CI secrets, walking an unfamiliar third-party dashboard, or running a one-off migration or cutover. Don't invoke this for steps the agent can perform itself.
why
Use for 'why does X work this way', 'why we picked Y', design rationale, regressions, postmortems, or data-backed thresholds. Use how for runtime behavior.