Skip to content
Back to skills

Diagnosing Bugs

ASecurity

Diagnoses hard bugs and performance regressions by building a red feedback loop first. Use when asked to debug, or something is broken or slow.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
ai-agentsgoshellbashtestinggitperformance

Works with

  • terminal
  • cli

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add tedliou/whetstone --skill diagnosing-bugs --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Diagnosing Bugs?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Diagnosing Bugs
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tedliou-diagnosing-bugs/badge)](https://www.skillsdirectory.com/skills/tedliou-diagnosing-bugs)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: diagnosing-bugs
description: Diagnoses hard bugs and performance regressions by building a red feedback loop first. Use when asked to debug, or something is broken or slow.
---

# Diagnosing bugs

A bug is found by a tight loop, not by reading code. A tight loop is one command that runs in seconds, gives the same verdict every run, and goes red on this exact bug. Build it before forming any theory. Work through the phases in order; skip one only when you can say why.

```
loop -> reproduce -> minimise -> hypothesise -> instrument -> fix -> clean up
 ^ no theory before this command exists
```

Read `GLOSSARY.md` and the ADRs in `docs/adr/` that touch the area, if they exist, so you name modules the way the project does.

## Redact

You will show commands, output, and captured data. Replace every secret with `<REDACTED>` before showing it. Pass credentials through environment variables so they stay out of the loop's source. From captured requests, quote only the lines that carry the signal. If redacted output is not enough to diagnose, say so and ask the user.

## 1. Build a feedback loop

This phase is most of the work. Try several kinds of loop before concluding none can be built. Roughly in this order:

1. A failing test at whatever seam reaches the bug (unit, integration, e2e).
2. A curl or HTTP script against a running dev server.
3. A CLI call with a fixture input, diffing output against a known-good snapshot.
4. A headless browser script (Playwright, Puppeteer) asserting on DOM, console, or network.
5. A replay of a captured request, payload, or event log through the code path in isolation.
6. A throwaway harness: the smallest subset of the system that reaches the bug in one call.
7. A property or fuzz loop: many random inputs, looking for the failure.
8. A bisection harness for "it worked at state X": script the check and run `git bisect run`.
9. A differential loop: same input through the old and new version (or two configs), diff the output.
10. A human-in-the-loop script, as a last resort. See [Human in the loop](#human-in-the-loop).

Then tighten it: make it faster (cache setup, narrow scope), sharper (assert the exact symptom, not "did not crash"), and deterministic (pin time, seed randomness, isolate the filesystem and network).

For an intermittent bug, aim for a higher reproduction rate, not a clean repro: loop the trigger many times, run in parallel, add load, inject sleeps. Keep raising the rate until it fails often enough to debug.

If no loop can be built, stop. List what you tried and ask the user for one of: access to an environment that reproduces it, a redacted capture (HAR, log dump, core dump, timestamped recording), or permission to add temporary production logging.

Done when you can name one command, have run it at least once (show the call and redacted output), and it is:

- red-capable: it drives the real code path and asserts the user's exact symptom, so it goes green only when this bug is fixed;
- deterministic: same verdict every run, or a pinned high failure rate for intermittent bugs;
- fast: seconds, not minutes;
- runnable by you without help, except through the human-in-the-loop script.

## 2. Reproduce and minimise

Run the loop and watch it go red. Check that:

- the failure is the one the user described, not a nearby one;
- it fails on repeated runs (or at a high enough rate);
- you have recorded the exact symptom (message, wrong value, timing) to verify the fix against.

Then shrink the scenario. Remove one input, caller, config value, or step at a time and rerun. Keep only what keeps it red. A smaller repro leaves fewer suspects and becomes the regression test. Done when removing any remaining element turns the loop green.

## 3. Hypothesise

Write 3 to 5 ranked hypotheses before testing any. One hypothesis anchors you on the first plausible idea. Each states a prediction:

```
If <X> is the cause, then changing <Y> makes the bug disappear (or changing <Z> makes it worse).
```

A hypothesis with no prediction gets sharpened or dropped. Show the ranked list to the user; they often know what changed recently or what is already ruled out. Do not wait for an answer if they are away.

## 4. Instrument

Each probe tests one prediction. Change one variable at a time.

- Prefer a debugger or REPL; one breakpoint beats ten log lines.
- Otherwise log at the boundaries that tell the hypotheses apart. Never log everything and grep.
- Tag every debug line with one unique prefix such as `[DEBUG-a4f2]`, so cleanup is one search.

For performance regressions, measure instead of logging: take a baseline with a timer, profiler, or query plan, then bisect.

## 5. Fix with a regression test

If the fix is more than a few lines, or touches behaviour other code depends on, offer to open a GitHub issue first (`gh issue create`, see [github.md](../_shared/github.md)) with the symptom, the loop command, and the confirmed hypothesis. Then branch and commit as in [workflow.md](../_shared/workflow.md).

Write the regression test before the fix, at a seam that reproduces the real bug pattern. A seam that is too shallow (one caller when the bug needs two, a unit test that skips the chain that triggers it) gives false confidence. If no such seam exists, report that as a finding: the design is stopping the bug from being locked down, and `improve-codebase-architecture` is the place to address it.

With a good seam:

1. Turn the minimised repro into a failing test there.
2. Watch it fail. If you forced the failure by editing code or a fixture, diff against a clean copy to prove the edit took effect.
3. Apply the fix and watch the test pass.
4. Rerun the phase 1 loop on the original, unminimised scenario.

## 6. Clean up

Done when all hold:

- the phase 1 loop no longer reproduces the bug;
- the regression test passes, or the missing seam is reported;
- a search for the debug prefix finds nothing;
- throwaway harnesses are deleted;
- the commit or PR message states which hypothesis was correct.

## Human in the loop

When only a person can trigger the bug (clicking through a UI, a device), script their steps so the loop stays structured. Copy the template that matches the user's shell to a temp directory, outside the repo:

- bash: `${CLAUDE_SKILL_DIR}/scripts/hitl-loop.template.sh`
- PowerShell: `${CLAUDE_SKILL_DIR}/scripts/hitl-loop.template.ps1`

Edit the steps between the markers. `step` shows an instruction and waits for Enter; `capture` asks a question and records the answer. The script is interactive, so ask the user to run it in their own terminal and paste back the `Captured` block it prints. Use `step` for anything involving sign-in, so no credential is ever captured.

Files in this skill

  • SKILL.md6.6 KB
  • scripts/hitl-loop.template.ps11.5 KB
  • scripts/hitl-loop.template.sh1.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.