Purpose
Confirm where /bugs:write --file writes reports, and manage the tracked project config
/bugs:scan reads for its lanes and filing posture.
Two surfaces, two owners
| Surface |
Holds |
Written by |
output_dir. Native userConfig |
one operator's personal --file destination on one machine |
Claude Code's own plugin configuration prompt, never this skill |
.claude/bugs.md. Tracked, cascade-layered |
team policy: /bugs:scan lanes and filing posture |
apply here, team layer only |
This is the narrow-write setup shape: apply is bounded to the one writable artifact this plugin
owns, and the unwritable surface beside it stays check-only. output_dir is a personal value that
Claude Code prompts for when the plugin is enabled, stores in user settings, and ignores in
pluginConfigs entries under project and local settings on current releases (≥ 2.1.207), so an
apply could only write the pluginConfigs the uniform setup contract forbids, and reconfiguration
routes through the native flow instead.
Official contract: https://code.claude.com/docs/en/plugins-reference#user-configuration.
Keys, layers, merge semantics, the output_dir partition rule, and the file format live in
${CLAUDE_PLUGIN_ROOT}/reference/config.md, their single home. Read it
before checking or writing; never restate its keys here, and never let this skill and that reference
disagree.
Both actions are non-interactive when the invocation and the repo make the values unambiguous:
report and recommend, and ask only where a lane genuinely needs the user. No argument runs check.
check (read-only, the default)
Modify nothing. Report both surfaces, then one remediation line per gap.
A. output_dir (native userConfig)
- Read the rendered
${user_config.output_dir} value from this skill. Do not inspect or edit
settings.json, settings.local.json, managed settings, or pluginConfigs directly.
- Explain the effective behavior:
- empty or unexpanded value:
--file uses
${CLAUDE_PLUGIN_DATA}/bug-reports/<project-slug>/;
- configured value:
--file uses that directory.
- State the tradeoff instead of asking: machine-private (the default under
${CLAUDE_PLUGIN_DATA}) versus a repository path committed alongside code. For the
repository option, inspect the consumer's CLAUDE.md, AGENTS.md, and existing report or
artifact directories and recommend one portable location. Never recommend a machine-absolute
team path.
- If the recommended value differs, reconfigure through Claude Code's native flow per the marketplace's
plugin-reconfiguration convention, which owns the verified-version record: interactive
/plugin configure bugs@<marketplace> any time, or headless claude plugin install bugs@<marketplace> -s <scope> --config output_dir=<path> — it prints already installed and still writes the value.
Never uninstall to reconfigure: that drops the whole stored pluginConfigs entry, resetting every
option to its manifest default. -s defaults to user; pass the scope claude plugin list reports,
from that project's directory for a project/local scope, or the write lands at a scope that does
not load. Rerun check in a fresh session (the rendered value is injected at skill load, so a
same-session check still reports the OLD value), then report the observed destination. Convention:
https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/plugin-reconfiguration/README.md.
B. .claude/bugs.md (tracked lane config)
Anchor at the repo root. Use ${CLAUDE_PROJECT_DIR} when set, otherwise git rev-parse --show-toplevel,
never the CWD. Then report each layer separately and the effective merged result:
- Per-layer presence. Name every layer of the surface (the reference's layer table is
authoritative) and say for each: absent, present-and-parsed, or malformed. A malformed layer
degrades soft. Surface the error, name the layer, and resolve as if it were absent.
- Effective config and provenance. Report the merged
lanes and filing_posture and which
layer supplied each value, honoring the reference's merge semantics, including an explicit
empty-list opt-out, which is reported as an opt-out, not as a broken layer. All layers absent is
a valid, fully working state: INFO, never FAIL. /bugs:scan falls through to its bundled
generic default lanes.
- Per-layer version-control verdict. A present team file must be tracked, which takes two
probes: not-ignored and actually-tracked. Run
git check-ignore -v .claude/bugs.md; a
non-empty result is FAIL, naming the matching pattern. Teammates would never receive it. Then run
git ls-files --error-unmatch .claude/bugs.md; a non-zero exit on a present file is also
FAIL, "present but untracked, commit it so teammates receive it". The ignore probe alone cannot
see this: an untracked, unignored file returns the same empty output as a healthy tracked one, so
check would bless a config nobody else ever receives. The .local.md overlay must be
gitignored; staged or unignored is FAIL. The user-global layer sits outside the worktree, so no git
verdict applies to it. Say so rather than running a command whose answer is meaningless.
- Unreachable layers. When a layer cannot be read (the user-global one often is not), WARN that
it was not considered rather than presenting the rest as the whole effective config.
- Unknown keys. Report them as inert, naming their layer, including
output_dir, which is not
a recognized key here per the reference's partition rule.
apply (idempotent, bounded to .claude/bugs.md)
Run check first, then converge the team file, the only artifact this action writes. Never
touch settings.json, settings.local.json, managed settings, pluginConfigs, userConfig, the
user-global layer, the .local.md overlay, or the consumer's .gitignore. An output_dir change
requested here is routed to the native flow in check step A4, never written.
- Read the effective config first, across every layer, and present it. Where a user-global or
overlay layer changes the team file's effect, adding lanes, replacing one by name, opting out
with an empty list, or supplying
filing_posture nearest-wins, say so explicitly: a team-scope
edit alone will not account for it, and re-adding a lane an overlay opts out of will not restore
it on this machine. Prompt the user to also update that layer; do not edit it for them.
- Draft lanes from the repository. Before asking anything, infer candidates from what exists:
entrypoint and API directories, the highest-churn source areas in
git log, and any subsystem
the repo's own docs treat as critical. Propose kebab-case lane names with globs relative to the
repo root. Degrade to the bundled generic default lanes as the proposal when history or layout
gives nothing to infer from.
- Confirm, one decision at a time. Present each drafted lane with a recommendation; let the
user accept, edit, or drop it. Then settle
filing_posture, stating what each value permits per
the reference, and that neither value ever lets a bare invocation file.
- Write conservatively. Scaffold the file in the reference's documented format when absent; for
an existing file, make a targeted update. Fill absent keys at their documented defaults,
preserve prose and keys you do not recognize, and report rather than silently rewrite anything
you cannot reconcile. Never overwrite blind, and never rewrite a file you did not first read.
- Verify after writing. Re-run the
check B probes against the file on disk: it parses, every
lane declares name and globs, the globs match real paths (a lane matching nothing is reported
as skipped), and git check-ignore -v .claude/bugs.md confirms it is not ignored. A file
just scaffolded here is legitimately untracked until it is staged, so
git ls-files --error-unmatch will not match yet. That is not a FAIL at this point; state the
commit obligation instead (step 7). Report the values you observed, never an unobserved change.
- Recommend the overlay line, do not write it. Personal deviations belong in
.claude/bugs.local.md; recommend the consumer add the recursive .gitignore line the
reference names if it is not already covered. Their ignore file is their artifact.
- Remind them to stage it. The team file only reaches teammates once committed.
Re-running apply when everything already matches changes nothing and reports "already configured".
Output
Report, for each surface: the effective state and the layer that supplied it, the recommended state,
and what changed, the tracked file's path and the keys written, plus whether the user must still
change the Claude-owned output_dir through Claude Code's own flow. Do not claim a configuration
change until it is observed: for the tracked file, by re-reading it; for output_dir, by a rerun in
a fresh session.
Boundaries
- Do not produce or file a bug report; invoke
/bugs:write via the Skill tool.
- Do not run a hunt; that is
/bugs:scan. This skill only verifies and writes its config.
- Do not write the plugin cache, Claude Code user settings, or
pluginConfigs, per the uniform
setup contract (docs/PLUGIN-PHILOSOPHY.md "Setup is explicit and repeatable" in the
marketplace repository).
- Do not delete the tracked config:
apply converges to the configured state and never removes.
- Do not invent an organization, repository, marketplace, or environment-variable prefix.
1---2name: setup3description: Verify and configure the bugs plugin for this repository. check inspects both surfaces read-only, the rendered output_dir userConfig value, and the tracked .claude/bugs.md lane config across its cascade layers; apply writes or updates that tracked file and nothing else. Use when: 'set up bugs', 'configure bugs', 'bugs setup', 'where do bug reports land', you want --file reports committed alongside code, or '/bugs:scan' needs project lanes and a filing posture. Actions: check (read-only, default) | apply (creates or updates the tracked lane config; output_dir still routes through Claude Code's own configuration prompt).4---56## Purpose78Confirm where `/bugs:write --file` writes reports, and manage the tracked project config9`/bugs:scan` reads for its lanes and filing posture.1011## Two surfaces, two owners1213| Surface | Holds | Written by |14|---|---|---|15| `output_dir`. Native `userConfig` | one operator's personal `--file` destination on one machine | Claude Code's own plugin configuration prompt, never this skill |16| `.claude/bugs.md`. Tracked, cascade-layered | team policy: `/bugs:scan` lanes and filing posture | `apply` here, team layer only |1718This is the narrow-write setup shape: `apply` is bounded to the one writable artifact this plugin19owns, and the unwritable surface beside it stays check-only. `output_dir` is a personal value that20Claude Code prompts for when the plugin is enabled, stores in user settings, and ignores in21`pluginConfigs` entries under project and local settings on current releases (≥ 2.1.207), so an22`apply` could only write the `pluginConfigs` the uniform setup contract forbids, and reconfiguration23routes through the native flow instead.2425Official contract: <https://code.claude.com/docs/en/plugins-reference#user-configuration>.2627Keys, layers, merge semantics, the `output_dir` partition rule, and the file format live in28[`${CLAUDE_PLUGIN_ROOT}/reference/config.md`](../../reference/config.md), their single home. Read it29before checking or writing; never restate its keys here, and never let this skill and that reference30disagree.3132Both actions are non-interactive when the invocation and the repo make the values unambiguous:33report and recommend, and ask only where a lane genuinely needs the user. No argument runs `check`.3435## `check` (read-only, the default)3637Modify nothing. Report both surfaces, then one remediation line per gap.3839### A. `output_dir` (native `userConfig`)40411. Read the rendered `${user_config.output_dir}` value from this skill. Do not inspect or edit42 `settings.json`, `settings.local.json`, managed settings, or `pluginConfigs` directly.432. Explain the effective behavior:44 - empty or unexpanded value: `--file` uses45 `${CLAUDE_PLUGIN_DATA}/bug-reports/<project-slug>/`;46 - configured value: `--file` uses that directory.473. State the tradeoff instead of asking: machine-private (the default under48 `${CLAUDE_PLUGIN_DATA}`) versus a repository path committed alongside code. For the49 repository option, inspect the consumer's `CLAUDE.md`, `AGENTS.md`, and existing report or50 artifact directories and recommend one portable location. Never recommend a machine-absolute51 team path.524. If the recommended value differs, reconfigure through Claude Code's native flow per the marketplace's53 plugin-reconfiguration convention, which owns the verified-version record: interactive54 `/plugin configure bugs@<marketplace>` any time, or headless `claude plugin install bugs@<marketplace>55 -s <scope> --config output_dir=<path>` — it prints `already installed` and still writes the value.56 Never uninstall to reconfigure: that drops the whole stored `pluginConfigs` entry, resetting every57 option to its manifest default. `-s` defaults to `user`; pass the scope `claude plugin list` reports,58 from that project's directory for a `project`/`local` scope, or the write lands at a scope that does59 not load. Rerun `check` in a **fresh session** (the rendered value is injected at skill load, so a60 same-session `check` still reports the OLD value), then report the observed destination. Convention:61 <https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/plugin-reconfiguration/README.md>.6263### B. `.claude/bugs.md` (tracked lane config)6465Anchor at the repo root. Use `${CLAUDE_PROJECT_DIR}` when set, otherwise `git rev-parse --show-toplevel`,66never the CWD. Then report **each layer separately** and the effective merged result:67681. **Per-layer presence.** Name every layer of the surface (the reference's layer table is69 authoritative) and say for each: absent, present-and-parsed, or malformed. A malformed layer70 degrades soft. Surface the error, name the layer, and resolve as if it were absent.712. **Effective config and provenance.** Report the merged `lanes` and `filing_posture` and which72 layer supplied each value, honoring the reference's merge semantics, including an explicit73 empty-list opt-out, which is reported as an opt-out, not as a broken layer. All layers absent is74 a valid, fully working state: INFO, never FAIL. `/bugs:scan` falls through to its bundled75 generic default lanes.763. **Per-layer version-control verdict.** A present team file must be tracked, which takes **two**77 probes: not-ignored and actually-tracked. Run `git check-ignore -v .claude/bugs.md`; a78 non-empty result is FAIL, naming the matching pattern. Teammates would never receive it. Then run79 `git ls-files --error-unmatch .claude/bugs.md`; a non-zero exit on a present file is also80 FAIL, "present but untracked, commit it so teammates receive it". The ignore probe alone cannot81 see this: an untracked, unignored file returns the same empty output as a healthy tracked one, so82 `check` would bless a config nobody else ever receives. The `.local.md` overlay must be83 gitignored; staged or unignored is FAIL. The user-global layer sits outside the worktree, so no git84 verdict applies to it. Say so rather than running a command whose answer is meaningless.854. **Unreachable layers.** When a layer cannot be read (the user-global one often is not), WARN that86 it was not considered rather than presenting the rest as the whole effective config.875. **Unknown keys.** Report them as inert, naming their layer, including `output_dir`, which is not88 a recognized key here per the reference's partition rule.8990## `apply` (idempotent, bounded to `.claude/bugs.md`)9192Run `check` first, then converge the **team** file, the only artifact this action writes. Never93touch `settings.json`, `settings.local.json`, managed settings, `pluginConfigs`, `userConfig`, the94user-global layer, the `.local.md` overlay, or the consumer's `.gitignore`. An `output_dir` change95requested here is routed to the native flow in `check` step A4, never written.96971. **Read the effective config first, across every layer**, and present it. Where a user-global or98 overlay layer changes the team file's effect, adding lanes, replacing one by name, opting out99 with an empty list, or supplying `filing_posture` nearest-wins, say so explicitly: a team-scope100 edit alone will not account for it, and re-adding a lane an overlay opts out of will not restore101 it on this machine. Prompt the user to also update that layer; do not edit it for them.1022. **Draft lanes from the repository.** Before asking anything, infer candidates from what exists:103 entrypoint and API directories, the highest-churn source areas in `git log`, and any subsystem104 the repo's own docs treat as critical. Propose kebab-case lane names with globs relative to the105 repo root. Degrade to the bundled generic default lanes as the proposal when history or layout106 gives nothing to infer from.1073. **Confirm, one decision at a time.** Present each drafted lane with a recommendation; let the108 user accept, edit, or drop it. Then settle `filing_posture`, stating what each value permits per109 the reference, and that neither value ever lets a bare invocation file.1104. **Write conservatively.** Scaffold the file in the reference's documented format when absent; for111 an existing file, make a targeted update. Fill absent keys at their documented defaults,112 preserve prose and keys you do not recognize, and *report* rather than silently rewrite anything113 you cannot reconcile. Never overwrite blind, and never rewrite a file you did not first read.1145. **Verify after writing.** Re-run the `check` B probes against the file on disk: it parses, every115 lane declares `name` and `globs`, the globs match real paths (a lane matching nothing is reported116 as skipped), and `git check-ignore -v .claude/bugs.md` confirms it is not ignored. A file117 just scaffolded here is legitimately untracked until it is staged, so118 `git ls-files --error-unmatch` will not match yet. That is not a FAIL at this point; state the119 commit obligation instead (step 7). Report the values you observed, never an unobserved change.1206. **Recommend the overlay line, do not write it.** Personal deviations belong in121 `.claude/bugs.local.md`; recommend the consumer add the recursive `.gitignore` line the122 reference names if it is not already covered. Their ignore file is their artifact.1237. **Remind them to stage it.** The team file only reaches teammates once committed.124125Re-running `apply` when everything already matches changes nothing and reports "already configured".126127## Output128129Report, for each surface: the effective state and the layer that supplied it, the recommended state,130and what changed, the tracked file's path and the keys written, plus whether the user must still131change the Claude-owned `output_dir` through Claude Code's own flow. Do not claim a configuration132change until it is observed: for the tracked file, by re-reading it; for `output_dir`, by a rerun in133a fresh session.134135## Boundaries136137- Do not produce or file a bug report; invoke `/bugs:write` via the Skill tool.138- Do not run a hunt; that is `/bugs:scan`. This skill only verifies and writes its config.139- Do not write the plugin cache, Claude Code user settings, or `pluginConfigs`, per the uniform140 setup contract (`docs/PLUGIN-PHILOSOPHY.md` "Setup is explicit and repeatable" in the141 marketplace repository).142- Do not delete the tracked config: `apply` converges to the configured state and never removes.143- Do not invent an organization, repository, marketplace, or environment-variable prefix.