From claudekit
Guides systematic debugging of bugs, errors, test failures, production incidents, and flaky issues through root cause investigation, reproduction, logging, and git analysis before fixes.
npx claudepluginhub duthaho/claudekit --plugin claudekitThis skill uses the workspace's default tool permissions.
- Bug reports with unclear cause
Enforces systematic root cause analysis before fixes for bugs, test failures, unexpected behavior, performance issues, and build failures.
Guides root cause debugging for bugs, test failures, and unexpected behavior. Enforces reproduce-investigate-hypothesize-fix process with evidence before fixes. No guessing.
Provides systematic debugging methodology using reproduce-investigate-hypothesize-fix-prevent workflow and root cause analysis for bugs, test failures, flaky behavior, production errors, performance degradation, integration failures.
Share bugs, ideas, or general feedback.
Goal: Understand what's happening before attempting to fix.
Steps:
Read error messages carefully
- What is the exact error message?
- What is the stack trace?
- What line numbers are mentioned?
- What values are shown?
Reproduce consistently
- Can you trigger the bug reliably?
- What exact steps reproduce it?
- What environment is required?
- Document the reproduction steps
Track recent changes
- What changed recently?
- git log --oneline -20
- When did it last work?
- What was deployed?
Gather evidence
- Collect logs
- Check monitoring/metrics
- Review related code
- Note any patterns
Add instrumentation (for multi-component systems)
// Add diagnostic logging at each boundary
console.error('[DEBUG] Input received:', JSON.stringify(input));
console.error('[DEBUG] After validation:', JSON.stringify(validated));
console.error('[DEBUG] Before database call:', JSON.stringify(query));
console.error('[DEBUG] Database result:', JSON.stringify(result));
# Python equivalent — add diagnostic logging at boundaries
import logging
logger = logging.getLogger(__name__)
async def get_user(user_id: str, db: AsyncSession) -> User:
logger.error(f"get_user called with user_id={user_id!r}, type={type(user_id)}")
user = await db.get(User, user_id)
logger.error(f"get_user result: {user!r}")
if not user:
raise HTTPException(status_code=404, detail=f"User {user_id} not found")
return user
Goal: Find comparable working code to identify differences.
Steps:
Find working code
- Is there similar functionality that works?
- What did this code look like before?
- Are there reference implementations?
Study reference thoroughly
- How does the working version handle this case?
- What dependencies does it use?
- What assumptions does it make?
Identify differences
- What's different between working and broken?
- Configuration differences?
- Data differences?
- Environment differences?
Understand dependencies
- What does this code depend on?
- What depends on this code?
- Are dependencies behaving correctly?
Goal: Form and test a specific theory about the cause.
Steps:
Form specific hypothesis
Write it down explicitly:
"The bug occurs because [X] causes [Y] when [Z]"
Example:
"The bug occurs because the cache returns stale data
when the user's session expires during an active request"
Test with minimal changes
- Change ONE variable at a time
- Don't combine multiple fixes
- Verify results after each change
Validate hypothesis
- Does the fix address the hypothesis?
- Can you explain WHY it works?
- Does it make the bug impossible, not just unlikely?
Goal: Fix properly with verification.
Steps:
Write failing test first
it('should handle expired session during request', () => {
const session = createExpiredSession();
const result = processRequest(session);
expect(result.error).toBe('SESSION_EXPIRED');
});
# Python equivalent
async def test_expired_session_returns_401(client, expired_token):
response = await client.get(
"/api/me",
headers={"Authorization": f"Bearer {expired_token}"},
)
assert response.status_code == 401
Implement single targeted fix
// Fix addresses root cause, not symptom
function processRequest(session: Session) {
if (session.isExpired()) {
return { error: 'SESSION_EXPIRED' };
}
// ... rest of logic
}
# Python equivalent — add expiry check in dependency
async def get_current_user(token: str = Depends(oauth2_scheme)):
payload = decode_token(token)
if payload.exp < datetime.utcnow().timestamp():
raise HTTPException(status_code=401, detail="Token expired")
return await get_user(payload.sub)
Verify fix works
# TypeScript
npm test -- --grep "expired session"
# Python
pytest tests/test_auth.py -v -k "expired_session"
Verify no regressions
# TypeScript
npm test
# Python
pytest -v
If three or more fixes fail consecutively, STOP.
This signals an architectural problem, not a simple bug:
Fix attempt 1: Failed
Fix attempt 2: Failed
Fix attempt 3: Failed
STOP: This is not a bug - this is a design problem.
Action: Discuss with user/team before proceeding
- Explain what's been tried
- Explain why it's not working
- Propose architectural changes
BAD: "There's an error somewhere"
GOOD: "TypeError: Cannot read property 'id' of undefined
at UserService.getUser (user-service.ts:42)"
BAD: "I think I know what's wrong" (starts coding)
GOOD: "Let me reproduce this first" (writes repro steps)
BAD: Fix where error appears
GOOD: Trace data backward to find where it became invalid
BAD: "I changed A, B, and C - now it works!"
(Which one fixed it? Are the others safe?)
GOOD: "I changed A - still broken.
I reverted A and changed B - now it works.
B was the fix."
Before attempting any fix:
Before declaring fixed:
| Stack | Log Inspection | REPL Debug | Test Isolation |
|---|---|---|---|
| Python/FastAPI | logging + structlog | breakpoint() / pdb | pytest -x -k test_name |
| TypeScript/NestJS | NestJS Logger | debugger + --inspect | jest --testNamePattern |
| Next.js | console.error + React DevTools | Browser DevTools | vitest run file.test.ts |
| React | React DevTools + useDebugValue | Browser DevTools | vitest run --reporter=verbose |
| Django | django.utils.log + DEBUG=True | breakpoint() / pdb | python manage.py test app.tests.TestCase.test_name |
# Quick pdb breakpoint (Python 3.7+)
breakpoint() # drops into pdb at this line
# Conditional breakpoint
if user_id == "problematic_id":
breakpoint()
# SQLAlchemy query logging — see actual SQL
import logging
logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
# FastAPI request/response logging middleware
@app.middleware("http")
async def log_requests(request: Request, call_next):
logger.info(f"{request.method} {request.url}")
response = await call_next(request)
logger.info(f"Status: {response.status_code}")
return response
// NestJS — enable verbose logging
const app = await NestFactory.create(AppModule, { logger: ['verbose'] });
// Prisma — log queries
const prisma = new PrismaClient({ log: ['query', 'info', 'warn', 'error'] });
// Next.js — debug server components
// Add to next.config.js
module.exports = { logging: { fetches: { fullUrl: true } } };
root-cause-tracing -- Deep-dive technique for tracing issues back through complex dependency chainsdefense-in-depth -- Add defensive layers to prevent similar bugs from recurringverification-before-completion -- Ensures the fix is actually verified with evidence before claiming the bug is resolved