| name | investigate |
| description | Systematic debugging with root cause investigation. Enforces the Iron Law: no fixes without root cause. Four phases: investigate (gather symptoms, trace code, check history), pattern-match (race condition, nil propagation, state corruption, stale cache, config drift, integration failure), hypothesize and test (confirm before fixing, 3-strike escalation), implement (minimal fix + regression test). Use this skill whenever the user reports a bug, error, unexpected behavior, or says things like 'debug this', 'fix this', 'why is this broken', 'investigate this error', 'root cause analysis', 'this stopped working', 'getting an error', 'something is wrong'. Proactively suggest when the user is troubleshooting or applying fixes without investigating first. |
| argument-hint | <error description or symptom> |
Investigate — Systematic Debugging
The Iron Law
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST.
This is the single most important rule. Fixing symptoms creates whack-a-mole debugging — every fix that doesn't address root cause makes the next bug harder to find. Resist the urge to apply a quick patch. Find the root cause, then fix it.
Why this matters: Claude's default behavior is to see an error, guess the cause, and immediately write a fix. This works for trivial bugs but creates disasters for complex ones. The fix passes the immediate test but introduces subtle regressions, masks the real issue, or solves a symptom while the disease spreads. This skill exists to break that habit.
Phase 1: Root Cause Investigation
Gather context before forming any hypothesis. You are a detective collecting evidence, not a repair person reaching for a tool.
Step 1: Collect Symptoms
Read the error messages, stack traces, and reproduction steps. If the user hasn't provided enough context, ask ONE question:
"Can you show me the exact error message and the steps to trigger it?"
Don't ask multiple questions. One question, get the answer, proceed.
Step 2: Read the Code
Trace the code path from the symptom back to potential causes:
- Start at the error location (file + line from stack trace)
- Read the function/method where the error occurs
- Trace backwards: who calls this? What data flows in?
- Use Grep to find all references to the key variables, functions, or types involved
- Read related tests — do they cover this case?
Write down what you learn. Before moving on, state:
- What the code is supposed to do
- What it's actually doing
- Where the divergence happens (or where you're unsure)
Step 3: Check Recent Changes
git log --oneline -20 -- <affected-files>
git diff HEAD~5 -- <affected-files>
Was this working before? What changed? A regression means the root cause is in the diff — you can often find it in minutes instead of hours.
Also check:
- Were dependencies updated recently? (
git log --oneline -10 -- package.json Cargo.lock go.sum requirements.txt)
- Were config files changed? (
git log --oneline -10 -- *.yml *.json *.toml .env*)
Step 4: Reproduce
Can you trigger the bug deterministically? If you can reproduce it, you can verify the fix. If you can't:
- Gather more evidence before proceeding
- Add logging at the suspected points
- Check if it's timing-dependent (race condition signal)
Step 5: State Your Hypothesis
Output a clear, testable claim:
ROOT CAUSE HYPOTHESIS:
- What: {specific thing that's wrong}
- Where: {file:line or component}
- Why: {mechanism — how the bug manifests}
- Evidence: {what supports this hypothesis}
- Test: {how to confirm or deny it}
Do NOT proceed to fixing until you have this.
Phase 2: Pattern Analysis
Check if the bug matches a known pattern. This accelerates diagnosis — most bugs fall into one of these categories:
| Pattern | Signature | Where to Look |
|---|
| Race condition | Intermittent, timing-dependent, "works sometimes" | Concurrent access to shared state, async operations, event handlers |
| Nil/null propagation | TypeError, NoMethodError, "cannot read property of undefined" | Missing guards on optional values, API responses, DB queries |
| State corruption | Inconsistent data, partial updates, "wrong data showing" | Transactions, callbacks, hooks, shared mutable state |
| Integration failure | Timeout, unexpected response, "works locally" | External API calls, service boundaries, network |
| Configuration drift | "Works on my machine", fails in staging/prod | Env vars, feature flags, DB state differences |
| Stale cache | Shows old data, fixes on refresh/clear, "was working earlier" | Redis, CDN, browser cache, in-memory caches, ORM caches |
| Off-by-one / boundary | Fails at edges (first item, last item, empty list, max value) | Loops, array indexing, pagination, date boundaries |
| Encoding / serialization | Garbled text, unexpected characters, parse errors | JSON/XML parsing, character encoding, binary data handling |
Recurring bugs are an architectural smell. If git log shows prior fixes in the same files for similar issues, the problem is structural, not incidental. Flag this:
"This area has had {N} related fixes in the last {M} commits. The root cause may be architectural — {specific pattern you see}."
External search: If the bug doesn't match known patterns, search for the error — but sanitize first. Strip hostnames, IPs, file paths, SQL, customer data, and any proprietary identifiers. Search the generic error type and framework context:
- "{framework} {sanitized error type}"
- "{library} {component} known issues"
If you find a documented solution or known dependency bug, present it as a candidate hypothesis.
Phase 3: Hypothesis Testing
Before writing ANY fix, verify your hypothesis. Guessing creates more bugs than it solves.
Confirm the Hypothesis
Add a temporary diagnostic at the suspected root cause:
- A log statement that prints the suspicious value
- An assertion that would fail if your hypothesis is correct
- A debugger breakpoint or conditional break
Run the reproduction. Does the evidence match your hypothesis?
If the Hypothesis is Wrong
Do NOT guess again immediately. Instead:
- What did the diagnostic tell you? (New evidence)
- Does this evidence point to a different pattern from Phase 2?
- Search for the error if you haven't already (sanitize first)
- Return to Phase 1 with the new evidence. Gather more data.
3-Strike Rule
If 3 hypotheses fail, STOP. This is not a failure — it's information. The bug is more complex than it appears.
Present options:
STATUS: 3 hypotheses tested, none confirmed.
Hypotheses tested:
1. {hypothesis} — Disproved because: {evidence}
2. {hypothesis} — Disproved because: {evidence}
3. {hypothesis} — Disproved because: {evidence}
This suggests the issue may be:
A) Architectural — not a local bug but a systemic interaction
B) Environmental — depends on conditions I can't reproduce here
C) Data-dependent — requires specific data state to trigger
Recommendation: {what to try next}
Red Flags — Slow Down If You See These
- "Quick fix for now" — There is no "for now." Fix it right or escalate. Quick fixes become permanent, and the next developer inherits your hack.
- Proposing a fix before tracing data flow — You're guessing, not investigating.
- Each fix reveals a new problem elsewhere — You're at the wrong layer. The fix is in the architecture, not the code.
- The fix requires changes in 5+ files — Legitimate sometimes, but flag the blast radius.
Phase 4: Implementation
Once — and ONLY once — root cause is confirmed:
1. Fix the Root Cause, Not the Symptom
The smallest change that eliminates the actual problem. Not a workaround. Not a defensive check that hides the real issue. The actual fix.
Bad: Adding a nil check before the crash (hides the fact that the value should never be nil)
Good: Fixing the code path that produces nil in the first place
2. Minimal Diff
Fewest files touched, fewest lines changed. Resist the urge to refactor adjacent code, update comments, or "clean up while you're here." Bug fixes should be surgically precise so they can be reviewed and reverted easily.
3. Write a Regression Test
Every bug fix gets a test that:
- Fails without the fix (proves the test actually catches the bug)
- Passes with the fix (proves the fix works)
If you can't write such a test, explain why and flag it as a risk.
4. Run the Full Test Suite
{project's test command}
Paste the output. No regressions allowed. If the fix breaks other tests, that's evidence your root cause analysis was incomplete — go back to Phase 1.
5. Flag Blast Radius
If the fix touches more than 3 files, explicitly flag it:
BLAST RADIUS: This fix touches {N} files.
Files modified:
- {file1}: {what changed and why}
- {file2}: {what changed and why}
This is {expected/larger than expected} because {reason}.
Completion Report
After implementing the fix:
INVESTIGATION COMPLETE
Root cause: {one sentence}
Pattern: {which pattern from Phase 2, or "novel"}
Fix: {one sentence description}
Files changed: {count}
Test: {test name that covers this}
Confidence: {HIGH — root cause confirmed with evidence / MEDIUM — strong hypothesis, fix works / LOW — fix resolves symptom but root cause not fully confirmed}
{If LOW confidence: explain what remains uncertain and what to watch for}
Anti-Patterns This Skill Prevents
| Anti-Pattern | What Happens | What To Do Instead |
|---|
| Guess and patch | See error → guess cause → write fix → hope it works | Investigate → hypothesize → test → confirm → then fix |
| Defensive coding as debugging | Add nil checks, try/catch, fallbacks everywhere | Find WHY the value is nil. Don't mask the symptom. |
| Scope creep during bugfix | "While I'm here, let me also refactor this..." | Fix the bug. Only the bug. Refactor in a separate PR. |
| Infinite retry loops | Fix doesn't work → try another fix → another → another | 3-strike rule. Stop. Gather evidence. Escalate if needed. |
| Fixing without reproducing | "I think this should fix it" based on code reading alone | Reproduce first. If you can't reproduce, add logging, don't guess. |