debugging-code
Skill328 starsChanged 8 months agoMITView on GitHub
Interactively debug source code — set breakpoints, step through execution line by line, inspect live variable state, evaluate expressions against the running program, and navigate the call stack to trace root causes. Use when a program crashes, raises unexpected exceptions, produces wrong output, when you need to understand how execution reached a certain state, or when print-statement debugging isn't revealing enough.
- Installs packages
4 other projects use a version of this.
Adopted by
Most recently taken up by
- JetBrains/rider-skillstheir own version, first seen Oct 14, 2026
- Antthonyyy/marketing-agents-kitword for word, first seen Oct 13, 2026
- MedicV2/Claude-Skillstheir own version, first seen Jun 20, 2026
- JetBrains/skillstheir own version, first seen Apr 28, 2026
Other versions4 projects use a version of this.
Word for word · 1
- Antthonyyy/marketing-agents-kit★ 0100% same
Edited · 0
None found.
Wrote their own version · 3
- JetBrains/skills★ 386same name
- JetBrains/rider-skills★ 40same name
- MedicV2/Claude-Skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repositoryOne other file it gives its agents.
- CLAUDE.mdCLAUDE.md
The file
Show its rules and text
We split this skill into the rules it gives an agent
24 rules. 0 are common, 11 are distinctive, and 13 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
11
Distinctive
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 9
Use when a program crashes, produces wrong output, or you need to understand exactly how execution reached a particular state — and running …
- Very specific: line 22
If dap isn't installed (check: command -v dap), install it NOW.
- Distinctive: line 23
Ask/notify the user before proceeding to install it.
- Very specific: line 48
If a debugger backend is missing or fails to start, see references/installing-debuggers.md
- Very specific: line 74
Run dap debug --help for all flags, backends, and examples.
- Distinctive: line 80
When that diverges from what *should* happen, you've found your bug.
- Distinctive: line 82
Two strikes, rethink: If two hypotheses fail at the same location, your mental model is wrong.
- Very specific: line 85
Escalate gradually: Start with dap eval to test a quick hypothesis.
- Distinctive: line 88
Mimic the user journey: If you're debugging a user flow, set breakpoints along the path you expect the code to take.
- Very specific: line 89
If you expected compute() to be called, but it never is, then the bug is in the caller — not compute(), but whatever was supposed to call …
- Distinctive: line 92
Set breakpoints instead of prints: When you feel the urge to print something, set a breakpoint instead.
- Very specific: line 96
Every dap execution command returns full context automatically: current location, source, locals, call stack, and output.
- Distinctive: line 99
Do the local variables have the values I expected?
- Very specific: line 103
Trace causation up the stack: If a value is wrong at frame 0, check dap eval "<expr>" --frame 1 to see what the caller passed.
- Distinctive: line 119
If the program exits before hitting your breakpoint:
- Distinctive: line 129
Before setting a breakpoint: *"I believe the bug is in X because Y."* A good hypothesis is falsifiable — your next observation will confirm …
- Very specific: line 160
If a breakpoint is on an invalid line or the adapter adjusts it, dap warns you in the output.
- Very specific: line 164
Stop only when a condition is true — essential for loops, hot paths, and specific input values.
- Distinctive: line 186
If you're stepping more than 3 times in a row, you need a breakpoint, not more steps.
- Very specific: line 205
Use dap eval "<expr>" to probe live state without stepping:
- Distinctive: line 214
Avoid eval expressions that call methods with side effects — they mutate program state and can corrupt your debugging session.
- Very specific: line 219
When you need a quick look at a specific line without committing to a permanent breakpoint, use dap continue --to file:line.
- Very specific: line 261
After applying a fix, re-run the same scenario to verify.
- Very specific: line 268
When the app is not closed properly (e.g.
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Interactive Debugger
Use when a program crashes, produces wrong output, or you need to understand exactly how execution reached a particular state — and running it again with more print statements won't give you the answer fast enough.
You can pause a running program at any point, read live variable values and the call stack at that exact moment, step forward line by line or jump to the next breakpoint, and evaluate arbitrary expressions against the live process — all without restarting.
Setup
This skill uses dap, a CLI tool that background daemon to interact with the debugger via the DAP Protocol, maintain
the debugger state, so you can simply interact with it with multiple calls.
If dap isn't installed (check: command -v dap), install it NOW.
Ask/notify the user before proceeding to install it.
From Homebrew (macOS)
brew install AlmogBaku/tap/dapInstaller script:
bash scripts/install-dap.shInstall from sources:
go install github.com/AlmogBaku/debug-skill/cmd/dap@latestThis tool is open-sourced and available on GitHub, maintained and follows best practices.
Supports natively Python, Go, Node.js/TypeScript, Rust, C/C++, and any other language that supports DAP.
If a debugger backend is missing or fails to start, see references/installing-debuggers.md
For all commands and flags: dap --help or dap <cmd> --help.
Starting a Session
dap debug <file> launches the program under the debugger. Backend is auto-detected from the file extension.
Choose your starting strategy based on what you know:
- Have a hypothesis — set a breakpoint where you expect the bug:
dap debug script.py --break script.py:42 - Conditional breakpoint — only stop when a condition is met:
dap debug script.py --break "script.py:42:x > 5"( always quote specs with conditions) - Multi-file app — breakpoints across modules:
--break src/api/routes.py:55 --break src/models/user.py:30 - No hypothesis, small program — walk from entry:
dap debug script.py --stop-on-entry(avoid for large projects — startup code is noisy; bisect with breakpoints instead) - Exception, location unknown —
dap debug script.py --break-on-exception raised(Python) /all(Go/JS) - Remote process —
dap debug --attach host:port --backend <name> - Process already running (stuck server, live issue) — attach without restarting:
dap debug --pid <PID> --backend <name>macOS + Go gotcha:
dlv --pidrequires SIP disabled (csrutil disable). Prefer starting the program under the debugger instead or attaching to a remote debugger!
Session isolation: --session <name> keeps concurrent agents from interfering.
Tip: You might want to use your session id(${CLAUDE_SESSION_ID}) if available.
Run dap debug --help for all flags, backends, and examples.
The Debugging Mindset
Reach for a debugger when reading source alone can't validate the root cause. A debugger lets you observe what does happen: actual values, actual path, actual state. When that diverges from what should happen, you've found your bug.
Two strikes, rethink. If two hypotheses fail at the same location, your mental model is wrong. Re-read the code, form a completely different theory with different breakpoints.
Escalate gradually. Start with dap eval to test a quick hypothesis. Use conditional breakpoints
to filter noise. Fall back to full breakpoints + stepping only when you need interactive control.
Mimic the user journey. If you're debugging a user flow, set breakpoints along the path you expect the code to take.
If you expected compute() to be called, but it never is, then the bug is in the caller — not compute(), but whatever
was supposed to call it.
Set breakpoints instead of prints. When you feel the urge to print something, set a breakpoint instead.
Know Your State
Every dap execution command returns full context automatically: current location, source, locals, call stack, and
output. At each stop, ask:
- Do the local variables have the values I expected?
- Is the call stack showing the code path I expected?
- Does the output so far reveal anything unexpected?
Trace causation up the stack. If a value is wrong at frame 0, check dap eval "<expr>" --frame 1 to see what the
caller passed. Keep going up (--frame 2, --frame 3) until you find the frame where the value first became wrong —
that's the origin of the bug, not the symptom.
Example output at a stop:
Stopped at compute() · script.py:41
39: def compute(items):
40: result = None
> 41: return result
Locals: items=[] result=None
Stack: main [script.py:10] → compute [script.py:41]
Output: (none)If the program exits before hitting your breakpoint:
Program terminated · Exit code: 1→ Move breakpoints earlier, or restart with --stop-on-entry.
Forming a Hypothesis
Before setting a breakpoint: "I believe the bug is in X because Y." A good hypothesis is falsifiable — your next observation will confirm or disprove it. No hypothesis yet? Bisect with two breakpoints to narrow the search space, or see starting strategies above.
Setting Breakpoints Strategically
- Set where the problem begins, not where it manifests
- Exception at line 80? Root cause is upstream — start earlier
- Uncertain? Bisect:
--break f:20 --break f:60— wrong state before or after halves the search space
Where to break:
- Boundaries — where data crosses a format, representation, or module boundary; state is cleanest here
- State transitions — the line that assigns or mutates the corrupted value
- Wrong branch — the condition whose inputs led to the bad path
- Antipatterns — don't break inside library code; break at the call site instead. Don't use unconditional breaks in tight loops — use conditions.
Managing Breakpoints Mid-Session
As you learn more, add breakpoints deeper in the suspect code and remove ones that have served their purpose — progressive narrowing without restarting:
dap continue --break app.py:50 # add breakpoint deeper, then continue
dap continue --remove-break app.py:20 # drop a breakpoint you're done with
dap break add app.py:42 app.py:60 # add multiple breakpoints at once
dap break list # see what's set
dap break clear # start freshIf a breakpoint is on an invalid line or the adapter adjusts it, dap warns you in the output.
Conditional Breakpoints
Stop only when a condition is true — essential for loops, hot paths, and specific input values.
Syntax: "file:line:condition" (always quote).
dap debug app.py --break "app.py:42:i == 100" # skip 99 iterations, stop on the one that matters
dap debug app.py --break "app.py:30:user_id == 123" # reproduce a user-specific bug
dap continue --break "app.py:50:len(items) == 0" # catch the empty-list case mid-sessionInvariant Breakpoints
Conditional breakpoints as runtime assertions — stop the moment something goes wrong:
dap debug app.py --break "bank.py:68:balance < 0" # catch the overdraft
dap debug app.py --break "pipe.py:30:type(val) != int" # type violationNavigating Execution
At each stop, choose how to advance based on what you suspect:
If you're stepping more than 3 times in a row, you need a breakpoint, not more steps.
dap step # step over — trust this call, advance to next line
dap step in # step into — suspect what's inside this function
dap step out # step out — you're in the wrong place, return to caller
dap continue # jump to next breakpoint
dap continue --to file:line # run to line (temp breakpoint, auto-removed)
dap context # re-inspect current state without stepping
dap output # drain buffered stdout/stderr without full context
dap inspect <var> --depth N # expand nested/complex objects
dap pause # interrupt a running/hanging program
dap restart # restart with same args and breakpoints
dap threads # list all threads
dap thread <id> # switch thread contextEach stop shows the current file:line so you always know where you are.
Use dap eval "<expr>" to probe live state without stepping:
dap eval "len(items)"
dap eval "user.profile.settings"
dap eval "expected == actual" # test hypothesis on live state
dap eval "self.config" --frame 1 # frame 1 = caller (may be a different file)Avoid eval expressions that call methods with side effects — they mutate program state and can corrupt your debugging session. Stick to read-only access unless you're intentionally testing a fix.
Skipping Ahead
When you need a quick look at a specific line without committing to a permanent breakpoint, use
dap continue --to file:line. It's a disposable breakpoint — stops once, then vanishes. Good for
"I just want to see what x looks like at line 50" without managing breakpoint lifecycle.
Advanced Scenarios
For advanced scenarios — hangs, concurrency bugs, deeply nested state, loop bisection —
see ${CLAUDE_SKILL_DIR}/references/advanced-techniques.md.
Walkthrough
Bug: compute() returns None
Hypothesis: result not assigned before return
→ dap debug script.py --break script.py:41
Locals: result=None, items=[] ← wrong, and input is also empty
New hypothesis: caller passing empty list
→ dap eval "items" --frame 1 → [] ← confirmed
→ dap step out → caller at line 10, no guard for empty input
→ dap continue --break script.py:8 --remove-break script.py:41
← narrowing: add breakpoint at data source, drop the one we're done with
Stopped at main():8, items loaded from config as []
Root cause: missing guard. Fix → dap stop.No hypothesis (exception, unknown location):
Exception: TypeError, location unknown
→ dap debug script.py --break-on-exception raised
Stopped at compute():41, items=None
Root cause: None passed where list expected.Verify Your Fix
While paused at the bug, use eval to test your proposed fix expression against the live state. If it
works in eval, it'll work in code. Then edit and dap restart to confirm end-to-end.
After applying a fix, re-run the same scenario to verify. dap restart re-runs with the same args and
breakpoints — a fast feedback loop. Don't trust that a fix works until you've observed the correct
behavior at the same breakpoint where you found the bug.
Cleanup
The dap session is usually automatically terminated when the program exits or after an idle timout.
When the app is not closed properly (e.g. you killed it while debugging), you can terminate it manually: dap stop.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

