Repository context. Gather first
Collect these with individual Bash calls, one command per call, never combined into a single
invocation:
- Current branch,
git branch --show-current
- Working tree (empty = clean),
git status --porcelain | head -5
The pipe is the bound and belongs in the command. A read-time cap ("read only the first 5 entries")
bounds nothing: the Bash tool returns the command's complete output into context before there is
anything to decide about.
Treat a failure (not a repository, git unavailable) as an unknown value and carry on. Keep these as
separate body Bash calls rather than pre-compute lines: the harness runs a skill's whole pre-compute
block as one shell invocation, and a worktree-isolated session refuses a compound command that
contains git.
Variables
Arguments: $ARGUMENTS
Purpose
/bugs:write produces a five-field structured report so the next session (or a human) can act without re-asking on vague repro, missing severity, no fix location, or hand-wavy expected/actual. Read-only. It captures, it does not fix, and it does not file (unless you explicitly ask).
This is the bug-intake stage. It sits upstream of filing the report into a work-item tracker, and it is independent of any downstream fix workflow, when the report itself is the deliverable (a Slack message, a PR comment, a verbal handoff), that is all this skill needs to do.
Five fields: title, steps to reproduce, expected vs actual, severity (with justification), and suggested fix location. A (unknown — needs reporter confirmation) placeholder is used for any field that cannot be backed from the source, rather than inventing one.
A sharp report captured up front saves the next session from re-asking. Unrepresented reproduction steps cost far more to recover later than to capture now.
Skip conditions, when not to invoke
- Investigation needed, the bug needs reproduce-first diagnosis, not just capture. If your project provides a debugging or investigation skill, hand off to it; otherwise scope the investigation separately from this read-only capture.
- Fix already in progress. This skill only captures; it does not complete a fix.
- Feature request (a missing capability, not a defect). This is product intent, not a bug. If your project provides a PRD or requirements-intake skill, route there; otherwise capture it as a feature request, not a five-field bug report.
- Generic chore (a TODO, docs gap, or non-defect task). File it directly in your tracker; it does not need the five-field bug shape.
If it is ambiguous, surface the question once and let the user pick.
The bugs process
Step 1. Skip-condition check
If the request matches a skip condition, stop and recommend the right path instead of producing a report: a feature request, an investigation task, and a generic chore each have a better home (above).
Step 2. Survey before you write
A fast breadth pass before deep work. In parallel:
Glob/Grep for the symbol named in the description (function, class, file, error message)
- If more than one symbol matches, the description is ambiguous. Ask which one
git log --oneline -10 -- <suspected-file> if a file is named, a recent change may be the cause
- Check the output directory (see Step 4) for prior bug reports on the same area, to avoid duplicates
Skip the survey when --no-survey was passed (unconditionally, the flag means "trust the description"), or when --quick was passed AND the description names a single unambiguous symbol.
Step 3. Targeted Q&A
Ask one question at a time. Use AskUserQuestion when 2-4 named options exist (e.g. "which flush()? There are 3 in the repo: …"); use prose for open-ended questions.
Question priority order. Only ask if the field cannot be backed from context:
| Field |
Highest-value question |
| Steps to reproduce |
"Walk me through the smallest sequence that triggers it." |
| Expected vs actual |
"What did you expect? What did you see instead?" |
| Severity |
"Who or what is blocked? Production users / dev workflow / cosmetic?" |
| Fix location |
(do not ask. Derive from the survey; if unknown, mark (unknown — needs reporter confirmation)) |
| Title |
(do not ask. Derive from symptom + symbol) |
Stop conditions: every required field has a backed answer OR an explicit (unknown — needs reporter confirmation) placeholder. Modifiers:
| Flag |
Effect |
| (none) |
Survey + targeted Q&A; default to --full discipline if the symbol is ambiguous |
--quick |
Skip the survey if the symbol is unambiguous; max 1 round of Q&A |
--full |
Always survey; up to 3 rounds of Q&A |
--no-survey |
Trust the description; only ask when a field would otherwise be invented |
--file |
Write the report to a file (see Step 4) instead of only stdout; then offer to file it in a tracker |
Step 4. Emit the report
Default: emit Markdown to stdout (read-only). Follow the 5-field template. See context/template.md for the full structure.
A person reads the report, so each field opens with its finding and carries no filler: invoke /writing:be-concise via the Skill tool when the writing plugin is installed; otherwise apply that discipline inline. The five fields, their order, and the template's shape are unchanged, and no repro step, severity justification, or unknown-field placeholder is dropped to shorten it.
--file mode: write the report to a file with frontmatter type: bug-report. Resolve the output directory in this precedence, and always tell the user the final path:
- If the consumer configured
output_dir, write to ${user_config.output_dir}.
- Otherwise, write to
${CLAUDE_PLUGIN_DATA}/bug-reports/<project-slug>/, where <project-slug> is the kebab-cased basename of the project root (${CLAUDE_PROJECT_DIR}, or the git toplevel when unset). The plugin data directory is per-plugin, not per-project. Without the slug, Step 2's duplicate scan would match another repository's report on the same symbol.
- If neither resolves, fall back to
${CLAUDE_PROJECT_DIR}/.bug-reports/ and state clearly where the file landed.
Filename: derive a slug from the title (kebab-case, ~40-char cap), prefix an ISO basic UTC timestamp with no colons (Windows-safe), e.g. 20260502T143000Z-bug-pricefor-discount-math.md. If the title cannot yet produce a slug, fall back to the timestamp alone.
Step 5. Hand off
After emitting the report, recommend the next step; do not invoke it yourself:
- File it as a work item. When the
work-items plugin is installed and a tracker binding resolves, hand the report to /work-items:track add (pass the report summary via --context); it owns dedupe, the body template, the issue type, and the argv-safe write, so do not call the tracker directly beside it. Map the severity onto the tracker's priority labels if it has them. Without work-items, in a GitHub repository with the gh CLI: --body-file needs a report file on disk (in --file mode use the emitted report path; in stdout mode save the report first, offering to re-run the write step or Write it to a temp file). Run gh issue create --type Bug --body-file <report> and let gh prompt for the title interactively. If filing non-interactively, never interpolate the reporter's title text into the command string: write the title to a file first, then run gh issue create --type Bug --title "$(cat <title-file>)" --body-file <report>, because the command-substitution result is a quoted argument value and is not re-parsed, so backticks or $( ) inside the reporter's text cannot execute. --type Bug sets the native GitHub Issue Type (an org-repo feature, the same one the work-items lanes set); on a repo without native Issue Types, drop the flag and add a type: bug label instead when the repo defines one. If a work-item tracker MCP tool is available and neither path applies, use it.
- A fix is next. If your project provides an investigation or implementation workflow, route there; otherwise scope the fix separately.
- The report is the deliverable (Slack, PR comment, hand-off). Done; copy/paste the stdout.
Severity rubric
Severity is low / medium / high / critical with a one-line justification. It is not "how upset is the reporter". It is blast radius × blocking factor × data-integrity impact:
| Severity |
Use when |
critical |
Production data corruption, security breach, full-app outage, money-affecting math bug |
high |
Feature broken for a large share of users, blocking dependent work, affects a core flow |
medium |
Feature broken for a narrow case, has a workaround, edge-case data issue |
low |
Cosmetic, documentation, dev-experience, or tooling drift |
If a tracker uses priority labels (e.g. p0/p1/p2/p3 or priority:high), map this rubric onto them when filing. If severity cannot be calibrated from context, ask one question rather than inventing it.
What this skill does NOT do
- Does not write code or open a PR. It produces a report only.
- Does not invent reproduction steps. If a step cannot be backed from the source, a test, or the reporter's description, it is marked
(unknown — needs reporter confirmation) and surfaced under Notes. Flag a gap rather than fabricate one.
- Does not file the report by default. The user reads the report and decides.
--file persists it; filing into a tracker is an explicit hand-off in Step 5.
- Does not investigate the bug. Step 2's survey is a fast grounding pass, not deep work. A fix that needs real investigation should be scoped separately.
- Does not auto-fix typos in the user's description. "There is a bug in
flusH()" may be intentional in some languages. Ask one question.
Gotchas
- Repro steps must be backed. If you cannot derive them from the user's description, the source, or a test, mark
(unknown — needs reporter confirmation). Inventing repro is worse than admitting a gap.
- Severity is blast radius, not frustration. Use the rubric; justify in one sentence.
- Suggested fix location is not a patch. Name the file path and function/class. No code, no diff, no "just change line X to Y". The fixer decides the patch.
- Title in present tense. "
priceFor returns wrong total when discountPercent is non-zero", not "fixed pricing bug" or "pricing was broken".
- When there is no bug, do not emit a report. If the survey and Q&A reveal the behaviour is correct, emit the short "No bug confirmed" summary instead (see
context/template.md).
Cross-references
context/template.md. Read it before emitting a report: the full Markdown template, the --file frontmatter, and the "No bug confirmed" form
- Consumer conventions (naming, areas, priority labels, tracker choice) come from the consuming project's own
CLAUDE.md / rules. This skill reads them rather than imposing its own
1---2name: write3description: Produce a structured 5-field bug report (title, steps to reproduce, expected vs actual, severity with justification, suggested fix location) from an informal description. Read-only, never modifies code, never opens PRs, never files issues by default. Use when the user names a defect they observed ('there is a bug in <X>', 'expected X got Y', 'I am seeing <error> in <file>') or asks for one written up ('report a bug', 'file a bug', 'write this up as a bug'). Skip when: deep investigation is needed, a fix is already in progress, or the request is a feature request (missing capability) rather than a defect. Emits Markdown to stdout by default; with --file, persists a report file and can hand off to a work-item tracker for filing.4---56## Repository context. Gather first78Collect these with **individual** Bash calls, one command per call, never combined into a single9invocation:1011- Current branch, `git branch --show-current`12- Working tree (empty = clean), `git status --porcelain | head -5`1314The pipe is the bound and belongs in the command. A read-time cap ("read only the first 5 entries")15bounds nothing: the Bash tool returns the command's complete output into context before there is16anything to decide about.1718Treat a failure (not a repository, git unavailable) as an unknown value and carry on. Keep these as19separate body Bash calls rather than pre-compute lines: the harness runs a skill's whole pre-compute20block as one shell invocation, and a worktree-isolated session refuses a compound command that21contains git.2223## Variables2425Arguments: `$ARGUMENTS`2627## Purpose2829`/bugs:write` produces a five-field structured report so the next session (or a human) can act without re-asking on vague repro, missing severity, no fix location, or hand-wavy expected/actual. **Read-only**. It captures, it does not fix, and it does not file (unless you explicitly ask).3031This is the **bug-intake** stage. It sits upstream of filing the report into a work-item tracker, and it is independent of any downstream fix workflow, when the report itself is the deliverable (a Slack message, a PR comment, a verbal handoff), that is all this skill needs to do.3233Five fields: title, steps to reproduce, expected vs actual, severity (with justification), and suggested fix location. A `(unknown — needs reporter confirmation)` placeholder is used for any field that cannot be backed from the source, rather than inventing one.3435A sharp report captured up front saves the next session from re-asking. Unrepresented reproduction steps cost far more to recover later than to capture now.3637## Skip conditions, when not to invoke3839- **Investigation needed**, the bug needs reproduce-first diagnosis, not just capture. If your project provides a debugging or investigation skill, hand off to it; otherwise scope the investigation separately from this read-only capture.40- **Fix already in progress**. This skill only captures; it does not complete a fix.41- **Feature request** (a missing capability, not a defect). This is product intent, not a bug. If your project provides a PRD or requirements-intake skill, route there; otherwise capture it as a feature request, not a five-field bug report.42- **Generic chore** (a TODO, docs gap, or non-defect task). File it directly in your tracker; it does not need the five-field bug shape.4344If it is ambiguous, surface the question once and let the user pick.4546## The bugs process4748### Step 1. Skip-condition check4950If the request matches a skip condition, stop and recommend the right path instead of producing a report: a feature request, an investigation task, and a generic chore each have a better home (above).5152### Step 2. Survey before you write5354A fast breadth pass before deep work. In parallel:5556- `Glob`/`Grep` for the symbol named in the description (function, class, file, error message)57- If more than one symbol matches, the description is ambiguous. Ask which one58- `git log --oneline -10 -- <suspected-file>` if a file is named, a recent change may be the cause59- Check the output directory (see Step 4) for prior bug reports on the same area, to avoid duplicates6061Skip the survey when `--no-survey` was passed (unconditionally, the flag means "trust the description"), or when `--quick` was passed AND the description names a single unambiguous symbol.6263### Step 3. Targeted Q&A6465Ask one question at a time. Use `AskUserQuestion` when 2-4 named options exist (e.g. "which `flush()`? There are 3 in the repo: …"); use prose for open-ended questions.6667Question priority order. Only ask if the field cannot be backed from context:6869| Field | Highest-value question |70|-------|------------------------|71| Steps to reproduce | "Walk me through the smallest sequence that triggers it." |72| Expected vs actual | "What did you expect? What did you see instead?" |73| Severity | "Who or what is blocked? Production users / dev workflow / cosmetic?" |74| Fix location | (do not ask. Derive from the survey; if unknown, mark `(unknown — needs reporter confirmation)`) |75| Title | (do not ask. Derive from symptom + symbol) |7677Stop conditions: every required field has a backed answer OR an explicit `(unknown — needs reporter confirmation)` placeholder. Modifiers:7879| Flag | Effect |80|------|--------|81| (none) | Survey + targeted Q&A; default to `--full` discipline if the symbol is ambiguous |82| `--quick` | Skip the survey if the symbol is unambiguous; max 1 round of Q&A |83| `--full` | Always survey; up to 3 rounds of Q&A |84| `--no-survey` | Trust the description; only ask when a field would otherwise be invented |85| `--file` | Write the report to a file (see Step 4) instead of only stdout; then offer to file it in a tracker |8687### Step 4. Emit the report8889Default: emit Markdown to stdout (read-only). Follow the 5-field template. See [`context/template.md`](context/template.md) for the full structure.9091A person reads the report, so each field opens with its finding and carries no filler: invoke `/writing:be-concise` via the Skill tool when the `writing` plugin is installed; otherwise apply that discipline inline. The five fields, their order, and the template's shape are unchanged, and no repro step, severity justification, or unknown-field placeholder is dropped to shorten it.9293`--file` mode: write the report to a file with frontmatter `type: bug-report`. Resolve the output directory in this precedence, and always tell the user the final path:94951. If the consumer configured `output_dir`, write to `${user_config.output_dir}`.962. Otherwise, write to `${CLAUDE_PLUGIN_DATA}/bug-reports/<project-slug>/`, where `<project-slug>` is the kebab-cased basename of the project root (`${CLAUDE_PROJECT_DIR}`, or the git toplevel when unset). The plugin data directory is per-plugin, not per-project. Without the slug, Step 2's duplicate scan would match another repository's report on the same symbol.973. If neither resolves, fall back to `${CLAUDE_PROJECT_DIR}/.bug-reports/` and state clearly where the file landed.9899Filename: derive a slug from the title (kebab-case, ~40-char cap), prefix an ISO basic UTC timestamp with no colons (Windows-safe), e.g. `20260502T143000Z-bug-pricefor-discount-math.md`. If the title cannot yet produce a slug, fall back to the timestamp alone.100101### Step 5. Hand off102103After emitting the report, recommend the next step; do not invoke it yourself:104105- **File it as a work item.** When the `work-items` plugin is installed and a tracker binding resolves, hand the report to `/work-items:track add` (pass the report summary via `--context`); it owns dedupe, the body template, the issue type, and the argv-safe write, so do not call the tracker directly beside it. Map the severity onto the tracker's priority labels if it has them. Without `work-items`, in a GitHub repository with the `gh` CLI: `--body-file` needs a report file on disk (in `--file` mode use the emitted report path; in stdout mode save the report first, offering to re-run the write step or Write it to a temp file). Run `gh issue create --type Bug --body-file <report>` and let `gh` prompt for the title interactively. If filing non-interactively, never interpolate the reporter's title text into the command string: write the title to a file first, then run `gh issue create --type Bug --title "$(cat <title-file>)" --body-file <report>`, because the command-substitution result is a quoted argument value and is not re-parsed, so backticks or `$( )` inside the reporter's text cannot execute. `--type Bug` sets the native GitHub Issue Type (an org-repo feature, the same one the work-items lanes set); on a repo without native Issue Types, drop the flag and add a `type: bug` label instead when the repo defines one. If a work-item tracker MCP tool is available and neither path applies, use it.106- **A fix is next.** If your project provides an investigation or implementation workflow, route there; otherwise scope the fix separately.107- **The report is the deliverable** (Slack, PR comment, hand-off). Done; copy/paste the stdout.108109## Severity rubric110111Severity is `low / medium / high / critical` with a one-line justification. It is not "how upset is the reporter". It is blast radius × blocking factor × data-integrity impact:112113| Severity | Use when |114|----------|----------|115| `critical` | Production data corruption, security breach, full-app outage, money-affecting math bug |116| `high` | Feature broken for a large share of users, blocking dependent work, affects a core flow |117| `medium` | Feature broken for a narrow case, has a workaround, edge-case data issue |118| `low` | Cosmetic, documentation, dev-experience, or tooling drift |119120If a tracker uses priority labels (e.g. `p0`/`p1`/`p2`/`p3` or `priority:high`), map this rubric onto them when filing. If severity cannot be calibrated from context, ask one question rather than inventing it.121122## What this skill does NOT do123124- **Does not write code or open a PR.** It produces a report only.125- **Does not invent reproduction steps.** If a step cannot be backed from the source, a test, or the reporter's description, it is marked `(unknown — needs reporter confirmation)` and surfaced under Notes. Flag a gap rather than fabricate one.126- **Does not file the report by default.** The user reads the report and decides. `--file` persists it; filing into a tracker is an explicit hand-off in Step 5.127- **Does not investigate the bug.** Step 2's survey is a fast grounding pass, not deep work. A fix that needs real investigation should be scoped separately.128- **Does not auto-fix typos in the user's description.** "There is a bug in `flusH()`" may be intentional in some languages. Ask one question.129130## Gotchas131132- **Repro steps must be backed.** If you cannot derive them from the user's description, the source, or a test, mark `(unknown — needs reporter confirmation)`. Inventing repro is worse than admitting a gap.133- **Severity is blast radius, not frustration.** Use the rubric; justify in one sentence.134- **Suggested fix location is not a patch.** Name the file path and function/class. No code, no diff, no "just change line X to Y". The fixer decides the patch.135- **Title in present tense.** "`priceFor` returns wrong total when `discountPercent` is non-zero", not "fixed pricing bug" or "pricing was broken".136- **When there is no bug, do not emit a report.** If the survey and Q&A reveal the behaviour is correct, emit the short "No bug confirmed" summary instead (see `context/template.md`).137138## Cross-references139140- [`context/template.md`](context/template.md). Read it before emitting a report: the full Markdown template, the `--file` frontmatter, and the "No bug confirmed" form141- Consumer conventions (naming, areas, priority labels, tracker choice) come from the consuming project's own `CLAUDE.md` / rules. This skill reads them rather than imposing its own