A Claude Code skill that finds bugs in code that compiles fine, passes tests, and looks right but breaks the moment a real user does something unexpected.
Companion: bug-echo — runs after a fix to find sibling instances of the same bug pattern. The two skills cover opposite halves of the bug-finding loop.
bug-prospector and pattern-based linters are complementary, not competitive: linters check how your code is written against a rule catalog; bug-prospector checks what your code assumes against 7 forward-looking lenses. A thorough audit uses both.
Built while shipping Stuffolio, an iOS/macOS app currently at build 33. Free, open source, Apache 2.0.
~6 min read · scan the TL;DR if you only have 30 seconds
- What: 7 forward-looking analysis lenses (assumptions, state machines, boundaries, lifecycle, errors, time, platform) that find behavioral bugs in code that compiles fine and passes tests.
- Why: Linters find code that looks wrong (force unwraps, deprecated APIs, retain cycles). bug-prospector finds code that looks right but behaves wrong — quiet assumptions that turn out not to hold under real-world conditions.
- Install: Two
/plugincommands in Claude Code; then/bug-prospectoris available in any project. - Try first:
/bug-prospector quickruns 3 of 7 lenses (Assumptions + Errors + Boundaries) on your recent changes. Light, fast, real report. - Example output: a real backup-manager audit on Stuffolio (4 BUG findings, 4 lenses). Also: quick-scan on TypeScript.
- Maturity: Used through real App Store submission cycles; works on any language, with extra Swift/SwiftUI lens depth.
If you're newer to Claude Code and unsure what an "audit skill" does, here's the short version.
A skill is a markdown file Claude Code knows how to run. When you type /bug-prospector, Claude follows the instructions in that skill, looks at your code, and writes you a report. You don't have to memorize anything. The skill tells Claude what to do; you read the report.
bug-prospector and linters are complementary — they catch different bugs at different layers.
Pattern-based tools (SwiftLint, ESLint, custom rule sets, single-file linters) check how your code is written. They flag force unwraps, missing @MainActor, retain cycles, deprecated APIs. If the syntax breaks a known rule, they catch it. They're fast, run continuously, and catch a real class of bugs cheaply. They will find issues bug-prospector won't — anything expressible as a single-file pattern.
bug-prospector checks what your code assumes. Things like:
- What happens when that array is empty?
- What if the user double-taps Save before the first save finishes?
- What if the network call completes after the view disappears?
- What if they open the app for the first time in 3 months?
These are bugs that compile fine, pass tests, and look right. The bug isn't in any single line. It's in a quiet assumption that turns out not to hold under real-world conditions. bug-prospector will find issues linters won't — assumption bugs have no code signature to search for.
The short version: linters find code that looks wrong. bug-prospector finds code that looks right but behaves wrong.
| What linters do better | What bug-prospector does better |
|---|---|
| Run on every save (cheap, continuous) | Run before release or after a crash (deeper, slower) |
| Catch style and pattern violations | Catch behavioral and assumption bugs |
| Mechanical, deterministic | Asks questions the rule catalog doesn't cover |
| Mature ecosystem | 7-lens forward-looking analysis |
A useful analogy: a linter is the building inspector confirming every wire is up to code. bug-prospector is the home inspector asking "what happens if the dishwasher and the microwave are running at the same time?" Different layer, different bugs. The inspection isn't complete without both.
Both have "bug" in the name; they answer different questions and run at different times.
| bug-prospector | bug-echo | |
|---|---|---|
| When you run it | Before a release, after a crash report, during exploration | Right after you fix a bug |
| What it asks | "What could go wrong?" | "Where else does this exact thing live?" |
| What it needs | Just code | The diff of a fix you just committed |
| Pattern source | 7 forward-looking lenses (assumptions, state machines, boundaries, lifecycle, errors, time, platform) | The pattern is inferred from your actual diff and validated against the pre-fix file |
Many people run both — bug-prospector before releases, bug-echo after every bug fix. They complement each other.
Two commands in Claude Code, run one at a time:
/plugin marketplace add Terryc21/bug-prospector
/plugin install bug-prospector@bug-prospector
Why two commands? Claude Code's slash-command dispatcher treats the second
/pluginas text inside the first command. Run them one at a time and wait for the first to confirm before running the second.
After installing, try:
/bug-prospector quick
This runs three of the seven analysis passes (Assumptions, Errors, Boundaries) on your recent changes. It's the lightest run bug-prospector offers — produces a real report you can act on without committing to the full sweep.
bug-prospector runs before a fix. bug-echo runs after one — same workflow loop, opposite end. Most users want both:
/plugin marketplace add Terryc21/bug-echo
/plugin install bug-echo@bug-echo
(Same one-at-a-time rule applies.)
/bug-prospector quick
Runs three lenses (Assumptions, Errors, Boundaries) on your recent changes. Light, fast, low token cost. Good for a first run or for routine pre-PR audits.
/bug-prospector all
Runs all 7 lenses. Heavier, more findings, takes longer. Save it for before a release or after a crash report.
/bug-prospector
No arguments — prompts you to choose scope and lenses interactively. Useful when you want to focus on one area of your code.
Each lens is a different angle for asking "what could go wrong here?"
| # | Lens | What it finds |
|---|---|---|
| 1 | Assumptions | Implicit assumptions that hold today but break when conditions change |
| 2 | State machine | States that shouldn't be reachable, two states active at once, transitions that get interrupted |
| 3 | Boundary conditions | Zero, one, the maximum value, an empty collection, off-by-one errors |
| 4 | Data lifecycle | Data created but never cleaned up, stale displays, orphaned references |
| 5 | Error paths | Errors that leave the UI stuck, errors swallowed silently, errors that lose user data |
| 6 | Time-dependent bugs | Timezones, rapid taps creating duplicates, slow networks, first-launch-after-weeks code |
| 7 | Platform divergence | Code that works on Apple Silicon but fails on Intel, or on iOS but not macOS, OS-version gaps |
You usually don't need all 7 every time. The right combination depends on what you just changed:
| Situation | Useful lenses |
|---|---|
| Pre-release audit | All 7 |
| After adding a new feature | Assumptions + State machine + Error paths |
| After a crash report | Boundaries + Error paths + Platform |
| Debugging intermittent failures | State machine + Time-dependent |
| Adding support for a new platform | Platform + Boundaries |
| Changing your data model | Data lifecycle + Assumptions |
bug-prospector scopes by lens selection + scope picker. The two dimensions are independent: you pick what to look at (recent changes / a specific file or feature / the whole codebase) and which lenses to apply (quick 3 / all 7 / custom subset).
| Goal | Command |
|---|---|
| First run — lightest possible | /bug-prospector quick (3 lenses on recent changes) |
| Full pre-release audit | /bug-prospector all (7 lenses on the whole project) |
| Interactive scope + lens picker | /bug-prospector (asks both questions) |
| Focus on one file or feature | /bug-prospector then pick "single file or directory" when prompted |
| Use a specific lens combo | /bug-prospector then pick "custom lenses" |
Fresh vs prior history. Every bug-prospector run is fresh — the skill reads your current code and applies the 7 lenses from scratch. There's no resume mode and no diff-against-prior-report mode (workflow-audit's --diff is the closest analog in the family). Prior reports live in .agents/research/ and can be compared by hand. If a finding shows up on three consecutive runs and you've decided it's a false positive for your codebase, document it in the lens-specific section of your project's CLAUDE.md so the skill knows to skip it next time; the skill respects context-rich guidance in CLAUDE.md when classifying findings.
Reports go to .agents/research/YYYY-MM-DD-bug-prospector-*.md in your project. Standard format across the radar/audit ecosystem:
- File and line citations for every claim
- 9-column rating table: severity, urgency, risk-of-fix, risk-of-no-fix, ROI, blast radius, fix effort, status, axis classification
- 3-axis classification: Axis 1 (release-blocking), Axis 2 (quality), Axis 3 (hygiene)
- Detailed findings with the current code and a suggested fix
- A "FRAGILE" section for code that works now but is likely to break later
- An "Already guarded" section for cases the lens checked and confirmed are fine
A complete sample report (4 BUG findings, 2 FRAGILE, 3 OK, 1 REVIEW across 4 lenses): example output.
A lighter second example showing the Quick 3 preset on a single TypeScript file: quick-scan example.
The report doesn't change your code. You decide which findings to fix.
The 9-column rating table needs a wide terminal (~180 chars) to render as a horizontal table. In a narrower window the cells stack vertically and the report becomes harder to scan. For best readability:
- GitHub or GitLab: open the report file in the web UI; tables render natively.
- Markdown viewer apps: Bear (Mac/iOS, free tier; import .md as a note), MacDown (Mac, free), Marked 2 (Mac, paid), Obsidian or Typora (cross-platform).
- VS Code: built-in Markdown Preview (cmd-shift-V on Mac).
If tables look broken in your terminal, widen the window or use one of the apps above.
After the report, the skill offers four ways to proceed:
- Fix all bugs now — walks through each phase with a confirmation before each one. Opt out of remaining confirmations whenever you want.
- Fix selected bugs — pick specific findings, confirm once, all selected get fixed.
- Create implementation plan — phased plan without making any code changes.
- Report is sufficient — just the report. You take it from there.
This skill is a tool, not an oracle. A few things to keep in mind:
- It surfaces candidates, not verdicts. The lens flags places where an assumption could break; you decide whether the assumption actually matters.
- False positives happen. A lens may flag a state-machine concern in code that's intentionally simple.
- False negatives happen. Bugs whose pattern doesn't fit any of the 7 lenses won't get caught.
- It can't run your code. It reads your code and reasons about it. Some bugs only show up at runtime; static reasoning has limits.
Treat findings as leads to investigate, not items to fix blindly. Verify critical findings before committing.
Where to look for the bugs bug-prospector won't find: pattern-based linters (SwiftLint, etc.) catch the single-file style violations; bug-echo catches sibling instances after a fix; runtime profiling (Instruments, sanitizers) catches concurrency and memory issues; targeted unit tests catch business-logic correctness. bug-prospector covers the forward-looking-assumptions slot in that picture.
The previous, more detailed README is preserved as README-detailed.md. The full methodology lives in docs/HOW_IT_WORKS.md, including how bug-prospector pairs with Workflow Audit.
- bug-echo — sibling-bug scan after a fix; companion skill
- workflow-audit — 5-layer SwiftUI behavioral flow audit
- unforget — one-file deferred-work ledger
- radar-suite — 6-skill suite tracing user behavior paths through the app (iOS + macOS)
- prompter — prompt rewriting before execution
- skill-reviewer — candid reviews of other Claude Code skills
- tutorial-creator — annotated tutorials from your codebase
Terry Nyberg, Coffee & Code LLC. If bug-prospector catches a real bug for you, a coffee is appreciated. Issue reports about what worked or didn't are more useful.