Help us improve
Share bugs, ideas, or general feedback.
From bug-echo
After fixing a bug, find and rate other instances of the same pattern in the codebase. Two modes: described, or inferred from a recent fix with self-validation. Triggers: "run bug-echo", "echo this fix", "scan for similar bugs", "find other instances", "after-fix scan".
npx claudepluginhub terryc21/bug-echo --plugin bug-echoHow this skill is triggered — by the user, by Claude, or both
Slash command
/bug-echo:bug-echoThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **Quick Ref:** After a bug fix, identify the pattern, scan the codebase, classify findings, and produce a rated report.
Mandates invoking relevant skills via tools before any response in coding sessions. Covers access, priorities, and adaptations for Claude Code, Copilot CLI, Gemini CLI.
Share bugs, ideas, or general feedback.
Quick Ref: After a bug fix, identify the pattern, scan the codebase, classify findings, and produce a rated report. Output:
.agents/research/YYYY-MM-DD-bug-echo-<slug>.md.
bug-echo is most effective when the pattern came from a fix that just shipped. A real fix proves which anti-pattern matters in your specific codebase. Pattern matching after a real fix is dramatically more accurate than pattern matching from a theoretical catalog — the fix is the evidence the pattern is a bug.
The high-leverage loop is surface → verify → generalize, three skills working in sequence:
/unforget (or any tracker) shows you a deferred row you're about to mark Fixed./radar-suite focus on <symbol> (or just reading the file) catches stale Open rows where the fix shipped weeks ago and nobody updated the ledger./bug-echo with a one-sentence description of what the fix replaced. The output is a rated list of every echo of that anti-pattern across the codebase — including instances that haven't crashed yet but sit under the same runtime conditions.Bugs that haven't fired yet are the highest-ROI thing in any audit cycle. They cost the same to fix as crashed bugs, but you skip the cost of the crash itself (lost user trust, support tickets, root-cause investigation under deadline). bug-echo is the systematic way to find them.
Companion skills:
https://github.com/Terryc21/unforget) — the surface; consolidates deferred work in one filehttps://github.com/Terryc21/radar-suite) — the verifier; confirms the fix is real before bug-echo generalizesbug-echo also runs standalone when you describe the pattern manually (Step 2A below) — useful when no recent fix exists but you've spotted a shape worth chasing.
YOU MUST EXECUTE THIS WORKFLOW. Do not just describe it.
Required output: Every BUG finding MUST include Urgency, Risk of Fixing, Risk of Not Fixing, ROI, Blast Radius, and Fix Effort using the 9-column Issue Rating Table format defined in Step 5. Findings missing any of the six dimensions are invalid.
This skill uses Claude's native tools only. No external scripts or pattern catalogs. AST-grep is optional; if it is installed, prefer it for higher precision on Swift, otherwise fall back to regex via the Grep tool.
Before any scanning work, verify the working environment is sane.
Check for uncommitted changes:
git status --porcelain via Bash.Note build manifest presence (advisory):
Package.swift, xcodeproj, Cargo.toml, package.json, or a similar build manifest exists in the project root. Note the result in the report header. Do NOT run a build — that's the user's responsibility before applying any fix this skill suggests. If no manifest is detected, mention it but continue scanning. This step is advisory metadata for the report, not a gate.Resolve output directory:
.agents/research/. This is a convention shared with radar-suite, bug-prospector, and other Coffee & Code audit skills; if your project doesn't already use it, this run creates it via mkdir -p .agents/research/.output=<path> (e.g., /bug-echo output=docs/audits/), use that path instead. Create it with mkdir -p if missing. Trailing slash is optional.Base all findings on the current source tree only. Do not read prior reports in .agents/research/, scratch/, or auto-memory caches as a source of findings. See § Deferred to v1.1+ for the planned recurrence-detection mode that would cross-reference prior reports.
Two modes are supported:
git log -p -1). Use AskUserQuestion to confirm. Go to Step 2B.If both are possible, disambiguate with AskUserQuestion:
Question (header: "Source"): "How should I identify the pattern?"
Options:
- "Infer from my recent fix" (Recommended). Analyze the diff and derive the pattern.
- "I'll describe it". I'll write out the pattern.
- "Cancel". Stop.
See § Deferred to v1.1+ for the planned catalog-selection mode.
Summarize the pattern back to the user:
**Pattern:** [name]
**Anti-pattern:** [what the bad code looks like]
**Correct pattern:** [what it should be]
**Search scope:** [file globs or directories]
**Platforms:** [iOS, iPadOS, macOS, watchOS, or "all"]
Confirm with AskUserQuestion (Yes scan now / Refine / Cancel) before proceeding to Step 3.
This is bug-echo's distinctive mode. Execute these steps directly using Bash and native tools:
Identify the diff source. In priority order:
git diff --cached via Bash.git diff via Bash.git log -p -1 via Bash.
Use the first non-empty result. If all are empty, fall back to Step 2A.Parse the diff.
- (and not ---) are removed lines (the anti-pattern).+ (and not +++) are added lines (the correct pattern).Construct a search pattern from the removed lines.
which ast-grep returns a path via Bash, prefer constructing an AST-grep pattern. Otherwise construct a regex compatible with the Grep tool.try? would match every optional-try in the codebase; that's not useful. Prefer something like try?\\s+context\\.fetch for a try?-on-fetch fix.Self-validate against the pre-fix file.
--- a/path/to/file.swift).git diff --cached): the pre-fix version is the HEAD baseline. Use git show HEAD:path/to/file.swift.git diff): the pre-fix version is HEAD. Use git show HEAD:path/to/file.swift.git log -p -1): the pre-fix version is HEAD~1. Use git show HEAD~1:path/to/file.swift. If this returns empty because the repo has only one commit (git rev-list --count HEAD returns 1), abort with "no pre-fix baseline available; switch to Step 2A described mode."git log --follow --name-status -1 -- path/to/file.swift. If the R<score> line shows a prior path, use git show HEAD~1:<prior-path> instead.Present the inferred pattern using the Step 2A summary format and confirm with the user before scanning.
The validation step is non-negotiable. If you cannot construct a pattern that matches the pre-fix file, the inference has failed. Do not proceed with a guess.
Run the validated pattern across the codebase.
Build the file list:
search_scope (default **/*.swift for Swift fixes; adjust by language).#if os(...) and #if !os(...) blocks during classification. Code inside an excluded platform branch is not flagged.Choose the scan strategy based on file count:
AST-grep precision (optional, opt-in):
Language-specific custom analyzers (rare, opt-in):
examples/2026-05-03-bug-echo-deep-viewbuilder-crash.md, which uses a custom Python brace-depth analyzer) — a custom analyzer is acceptable. Invoke an external script (Python, Swift, etc.) via the Bash tool. The script must accept a list of paths and emit findings with file:line context the classification step in Step 4 can consume. Note the tool in the report header's "Scan tool:" field.For each match, regardless of how it was found:
Read the file at the match location (Read tool), at minimum 20 lines around the match. Multi-platform code may need a wider window to capture surrounding #if blocks.
Check for known intentional usages.
try? in test code where failure is acceptable, force-unwrap of an IBOutlet) are classified as OK. See § Deferred to v1.1+ for the planned known-intentional.yaml suppression file.Classify as one of:
@ViewBuilder split that scoped a known crash, but if more conditions are added the scope could cross back into BUG territory). WATCH findings get a row in the Issue Rating Table with urgency typically ⚪ LOW or 🟢 MEDIUM and a documentation-only suggested fix (e.g., add a comment warning future maintainers about the threshold). Use WATCH when the code is correct today but the path to incorrect is short and foreseeable; use REVIEW when you can't tell.as! after a validated is check; strong self capture in a SwiftUI struct view).Classify each match individually. Do not batch-judge a directory or file.
Write the report directly to <output_dir>/YYYY-MM-DD-bug-echo-<slug>.md using the Write tool, where <output_dir> is the path Pre-flight Step 3 resolved (default .agents/research/, or the output=<path> override from the invoking prompt). The slug is a short kebab-case description of the pattern.
# bug-echo Report: [Pattern Name]
**Date:** YYYY-MM-DD
**Pattern source:** [user-described | inferred from fix]
**Scan tool:** [ast-grep | regex]
**Files scanned:** [N]
**Pattern validated against pre-fix file:** [yes | n/a for user-described]
## Pattern
**Anti-pattern:** [description]
**Correct pattern:** [description]
**Search regex:** `[pattern]` (or `ast-grep query: ...`)
## Summary
- BUG findings: [N]
- WATCH findings: [N]
- OK findings: [N]
- REVIEW findings: [N]
## BUG Findings
### Issue Rating Table
| # | Finding | Urgency | Risk: Fix | Risk: No Fix | ROI | Blast Radius | Fix Effort | Status |
|---|---|---|---|---|---|---|---|---|
| 1 | [short description] | [🔴 CRITICAL / 🟡 HIGH / 🟢 MEDIUM / ⚪ LOW] | [⚪ Low / 🟡 High / 🔴 Critical] | [⚪ Low / 🟢 Medium / 🟡 High / 🔴 Critical] | [🟠 Excellent / 🟢 Good / 🟡 Marginal / 🔴 Poor] | [⚪ 1 file / 🟢 N files / 🟡 N+ files] | [Trivial / Small / Medium / Large] | Open |
The Status column is `Open` on first display. After fixes are applied, the column updates to `Fixed`, `Deferred`, or `Skipped`.
### Detailed findings
For each BUG finding:
[N]. [short description]
path/to/file.swift:[line]
[code snippet, 5-10 lines around the match]
Why this is a bug: [1-2 sentences] Suggested fix: [1-2 sentences]
## WATCH Findings (near-threshold, defensive only)
WATCH findings use the same Issue Rating Table shape as BUG, but typically with documentation-only suggested fixes (e.g., add a comment near the threshold warning future maintainers, or convert the conditional shape to one that scales better). They are not release-blocking; they record what's currently safe but easy to break.
### Issue Rating Table
Same 9 columns as BUG. Urgency is typically ⚪ LOW or 🟢 MEDIUM.
### Detailed findings
For each WATCH finding:
[N]. [short description]
path/to/file.swift:[line]
[code snippet, 5-10 lines around the match]
Why this is WATCH not BUG: [1-2 sentences explaining the architectural defense or near-threshold status] Suggested fix (defensive, not urgent): [1-2 sentences, typically a comment or refactor recommendation]
## OK Findings (intentional, no action needed)
For each OK match, one line:
- `path/to/file.swift:[line]` - [reason it's OK]
## REVIEW Findings (need human judgment)
For each REVIEW match:
- `path/to/file.swift:[line]` - [why context is unclear]
The report is human-readable and self-contained. See § Deferred to v1.1+ for the planned JSON sidecar that would enable downstream skill chaining (e.g., feeding findings into safe-refactor).
After the report is written, offer guided fixes via AskUserQuestion:
Question (header: "Next"): "How would you like to proceed?"
Options:
- "Fix all BUG findings". Walk through each finding; apply fixes with approval.
- "Fix selected". Choose which findings to fix.
- "Report only". I'll handle fixes manually.
For guided fixes:
Present the BUG finding with file:line, code snippet, and suggested fix.
Show the proposed Edit (old_string and new_string).
Ask for explicit approval before applying.
Apply via the Edit tool only after the user confirms.
Update the report's Issue Rating Table to mark Status as Fixed, Skipped, or Deferred for each finding processed.
After all selected fixes are applied, present an AskUserQuestion:
Question (header: "Commit"): "Commit these bug-echo fixes now?"
Options:
- "Yes, commit as `bug-echo: applied N fixes from <slug>`" (Recommended).
Stage only the files this skill edited (track them as Step 6.4 applies
each Edit), then `git commit` via Bash with the message
`bug-echo: applied <N> fixes from <slug> report`. The commit message
references the report at `.agents/research/<date>-bug-echo-<slug>.md`
so the commit and the report are linked.
- "Leave uncommitted". The user commits later. Note: re-running bug-echo
will trip Pre-flight's clean-tree check until these changes are
committed or reverted.
- "Cancel". Stop without committing.
On "Yes, commit": run git add <file1> <file2> ... for only the files Step 6.4 edited (do not stage anything else), then git commit -m "bug-echo: applied <N> fixes from <slug> report". Verify with git status --porcelain that only the bug-echo-edited files were committed.
Re-display the rating table at the end of the fix session with all Status columns populated.
| Problem | Solution |
|---|---|
| Diff parsing fails because the recent edit is not a bug fix (rename, comment change, formatting) | Pattern self-validation will fail. Fall back to Step 2A and ask the user to describe the pattern manually. |
| Too many matches | Narrow the scope by passing a directory in the user's pattern description (e.g., Sources/Features/Auth/). |
| AST-grep not installed | Use regex via the Grep tool. Install with brew install ast-grep for higher precision on Swift if precision matters. |
| All matches classified OK | Pattern is localized to the original file. Report zero BUG findings and stop. That's a successful run, not a failed one. |
| Sub-agent dispatch fails | Fall back to sequential scan in the main agent. Slower but functional. |
| Mixed intentional and buggy matches | Classify each individually using Step 4 rules. Do not batch-judge. |
Pattern matches across #if os(...) boundaries | Honor platform conditionals during classification. Code inside the wrong #if block is OK, not BUG. |
If Step 2B's self-validation fails (the inferred pattern doesn't match the pre-fix file) and Step 2A's user-described mode also doesn't apply (no recent fix, no described pattern), bug-echo's job is done — it has no diff to work with. Rather than synthesize a catalog, the skill should suggest the right tool for the next step:
AskUserQuestion with questions:
[
{
"question": "I can't infer a pattern from a recent fix or description. Run bug-prospector instead?",
"header": "Next",
"options": [
{"label": "Yes, run bug-prospector", "description": "It uses 7 forward-looking lenses to find bugs without needing a fix to reference"},
{"label": "I'll describe a pattern manually", "description": "Restart bug-echo in Step 2A described mode"},
{"label": "Cancel", "description": "Stop"}
],
"multiSelect": false
}
]
If "Yes, run bug-prospector": instruct the user to invoke /bug-prospector (skill must be installed separately — see github.com/Terryc21/bug-prospector).
bug-prospector and bug-echo cover opposite halves of the bug-finding loop. bug-echo is reactive (after a fix); bug-prospector is forward-looking (before a fix). When bug-echo can't infer, the user's question is "what could go wrong?" not "where else does this live?" — that's bug-prospector's job, not a missing feature in bug-echo.
The frontmatter declares two metadata keys for cross-skill coordination across Coffee & Code's audit family (bug-prospector, radar-suite, workflow-audit, unforget):
tier — where the skill operates in a typical workflow.
execution (used by bug-echo) — runs in response to a concrete event (a fix landed, a release approaches). Produces an artifact (a report, a commit) the user acts on directly.planning — runs before an event to inform a decision (e.g., bug-prospector's forward-looking lenses, unforget's deferred-work survey).review — runs over a finished artifact to grade or audit it (e.g., radar-suite's capstone, app-store-code-review).category — the domain the skill targets.
debugging (used by bug-echo) — finds bugs, traces causes, or generalizes fixes.architecture, release-prep, documentation, ui-audit, data-model.These keys are descriptive metadata only — no router currently reads them at activation time. They exist so users browsing multiple companion skills can recognize the workflow stage at a glance. If a future router or skill-family index starts reading them, the canonical list lives in the radar-suite README.
These features are documented for future releases:
.agents/research/ to detect recurring patterns and suggest architectural fixes.known-intentional.yaml user file: explicit suppression of patterns the user has confirmed are intentional, so they don't surface again.