A Claude Code plugin for the front of the bug lifecycle. Read-only by default. It finds defects and captures them in a structured, five-field report; it does not fix them, open a PR, or file an issue on its own.
| Skill | What it does |
|---|---|
/bugs:write |
Turns an informal defect description, one you already observed, into the five-field report. |
/bugs:scan |
Hunts for defects nobody has observed yet in resting code, verifies each candidate adversarially, and reports what survives. |
/bugs:setup |
check inspects both configuration surfaces read-only; apply writes the tracked lane config scan reads. |
Invoke /bugs:write <description> (or let Claude reach for it
when you describe a defect). The five fields are:
- Title. Present tense, one line
- Steps to reproduce. Backed by the source or the reporter; never invented
- Expected vs actual behavior
- Severity (
low/medium/high/critical) with a one-sentence justification - Suggested fix location, a file path and function/class, no patch
- Read-only. Emits Markdown to stdout by default. It never edits code, opens a PR, or files an issue unless you explicitly hand the report off.
- Never fabricates. Any field it cannot back from the source, a test, or the
reporter is marked
(unknown — needs reporter confirmation)and surfaced under Notes, a flagged gap, not an invented step. - Knows when there is no bug. If a quick survey shows the behavior is correct, it emits a short "No bug confirmed" summary instead of a report.
- Routes non-defects away. Feature requests, investigations, and generic chores are recognized and pointed elsewhere rather than forced into the bug shape.
/bugs:write [--file] [--quick|--full] [--no-survey] <bug description>
| Flag | Effect |
|---|---|
| (none) | Survey the named symbol, then ask only for fields it can't back |
--quick |
Skip the survey when the symbol is unambiguous; at most one round of questions |
--full |
Always survey; up to three rounds of questions |
--no-survey |
Trust the description; ask only when a field would otherwise be invented |
--file |
Persist the report to a file (see Configuration), then offer to file it in a tracker |
/bugs:write needs a defect you already noticed. /bugs:scan needs nothing.
No diff, no failing test, no stack trace, no comment marker. It reads resting code and
looks for what is wrong in it.
/bugs:scan [<path|feature|diff>] [--lane <name>] [--track] [--dry-run]
| Flag | Effect |
|---|---|
| (none) | Rotate: self-select the next lane from the tracked lane config, hunt it, report |
<path|feature|diff> |
Hunt exactly that scope. No rotation |
--lane <name> |
Hunt the named lane's globs |
--track |
File the verified findings as raw intake through the work-items seam |
--dry-run |
Report to stdout only. Persists nothing, advances no rotation |
One invocation is one bounded pass, which makes it usable interactively, from a loop, or as a daily routine. Two properties are worth knowing before you rely on it:
- Recall and precision are separated. Per-lens hunter subagents are told to be generous;
a separate fresh-context gate is then told to refute every candidate they produced. Only
survivors reach the report, each labeled
reproducedorverified-by-reading, and refuted candidates stay in the report with the argument that killed them. - A bare run is read-only toward your repository and stays within a budget. It stops at
three verified findings or a complete lane sample. Filing happens only when you pass
--track, and a complete lane sample is never reported as the lane being bug-free. - Cost follows the scope, never the precision. Hunters run on a cheap general-purpose tier and gates on a strong reasoning tier (the skill's sizing table names the current aliases); the scope's size picks how many lenses run and how many candidates reach a gate, and the session's effort level is the ceiling. A main-thread triage step seeds from the previous run's ungated tail, merges same-cause candidates, and parks cosmetic ones before any gate is spent.
Verified findings leave through one ladder: in an interactive session a local finding (one plugin,
no documented contract change, a test file to extend) is fixed in that session through the implement
lane; a non-local or security-relevant one, and every finding from an unattended run, is filed with
--track. Root-causing routes to /debugging:debug, and anything security-relevant routes to the
review:security-review lane. On a cloud or scheduled session the plugin data directory does not
outlive the container, so pass --track: the filed item is the only durable output and is what the
next rotation reads back.
Two surfaces with two different owners.
Personal. One optional userConfig value, prompted by Claude Code at enable time:
| Option | Type | Effect |
|---|---|---|
output_dir |
directory | Where --file writes reports. Leave unset and reports go to the plugin's own persistent data directory. Set it to a path in your repository if you want bug reports committed alongside your code. |
Claude Code owns this value: current releases ignore plugin userConfig values placed in
project or local settings, and changes route through Claude Code's own configuration prompt.
Team, the tracked .claude/bugs.md, which /bugs:scan reads for its lanes
(lanes) and its filing policy (filing_posture). A ## Gotchas section in that file
(and the user-global and local overlay layers) concatenates after the bundled gotchas when
/bugs:scan or /bugs:write loads. Repo-specific lines stay in the layer; a line that is not
repo-specific is filed as an issue on this marketplace (melodic-software/claude-code-plugins) for
curation into the shipped skill. The config is layered per the marketplace's
config-cascade convention, a user-global file, this tracked team file, and a gitignored local
overlay. All layers are optional: with no config at all, scan rotates over bundled generic
default lanes. Keys, defaults, layer order, and per-key merge semantics live in
reference/config.md, their single home.
Run /bugs:setup to work on either surface. check (the default) reports both read-only:
the rendered output_dir and which layer supplied each lane config value. apply writes the
tracked file and nothing else. It drafts lane candidates from your repository, confirms them one
at a time, and never touches settings, pluginConfigs, the local overlay, or your .gitignore.
Project-specific conventions, naming, areas, tracker choice, priority labels, are
read from the consuming project's own CLAUDE.md / rules; the plugin imposes
none of its own.
Generated from this plugin's .claude-plugin/plugin.json. Every option Claude Code
will prompt for when the plugin is enabled, with the environment variable each hook
reads it from.
| Option | Type | Default | Environment variable | Description |
|---|---|---|---|---|
output_dir |
directory | (none) | CLAUDE_PLUGIN_OPTION_OUTPUT_DIR |
Where --file writes reports. When unset, reports go to the plugin's own persistent data directory. Set this to a path in your repository if you want bug reports committed alongside your code. |
Three supported routes, in the order most people want them:
-
Interactively. Claude Code prompts for declared options when you enable the plugin. To change them later:
/plugin configure bugs@<marketplace>. -
Headless. Repeat
--configfor each option. Replace<marketplace>with the marketplace you installed this plugin from:claude plugin install bugs@<marketplace> -s <scope> --config output_dir=<value>
The same command reconfigures a plugin that is already installed: it prints
already installedand still writes the value. The short-circuit message is about the install, not the config write. Do notclaude plugin uninstallto reconfigure: uninstalling drops this plugin's whole storedpluginConfigsentry, resetting every option in the table above to its default.-sdefaults touser, so pass the scopeclaude plugin listreports for this plugin. The verified-version record lives in the plugin-reconfiguration convention.The value is stored immediately; the session you are in does not change. Hooks are handed their
CLAUDE_PLUGIN_OPTION_*when the session starts, so start a fresh Claude Code session before expecting new behavior. A check run in the old session still reports the old value, and that is not a failed write. -
By hand, in settings. Add the value under
pluginConfigsin your user settings (~/.claude/settings.json):{ "pluginConfigs": { "bugs@<marketplace>": { "options": { "output_dir": <value> } } } }Plugin option values are read from user,
--settings, and managed settings only, not from a project's.claude/settings.json. To vary behavior per repository, enable or disable the plugin in that project'senabledPluginsinstead of setting an option there.
Do not set the CLAUDE_PLUGIN_OPTION_* variables yourself. They are how Claude Code
hands a configured value to a hook process; the value comes from the routes above.
- User configuration: the
userConfigschema and theCLAUDE_PLUGIN_OPTION_<KEY>export - Plugin install options: the
--configflag's reference entry - Plugins and skills settings:
enabledPlugins,extraKnownMarketplaces,pluginConfigs - Settings files and who they affect: user vs project vs local precedence
- Manage installed plugins: enabling, disabling,
/plugin list
--file persists the report; filing is an explicit, separate hand-off. When the
work-items plugin is installed and a tracker binding resolves, the report is handed
to /work-items:track add, which owns dedupe, the body template, and the argv-safe
write. Without it, in a GitHub repository with the gh CLI available:
gh issue create --type Bug --body-file <report-path>Let gh prompt for the title interactively. --type Bug sets the native GitHub Issue
Type (org repos; omit on repos without native Issue Types, adding a type: bug label instead). If filing non-interactively, never paste
the reporter's title text into the command string. Write it to a file and pass
--title "$(cat <title-file>)": the substitution result is a quoted argument value and
is not re-parsed, so backticks or $( ) in reporter text cannot execute.
If a work-item tracker MCP tool is available, the skill can hand off to that instead. Otherwise the emitted report is the deliverable. Copy it into your tracker.
/plugin marketplace add melodic-software/claude-code-plugins
/plugin install bugs@<marketplace>MIT (SPDX-License-Identifier: MIT).