debugging-code

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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.
Think like a developer sitting at a debugger. Each pause is an observation. Each observation either confirms your current theory about the bug or disproves it and points somewhere new. You're not guessing — you're surgically stopping execution where the truth lives and reading it directly.
适用于程序崩溃、输出错误结果,或是你需要准确了解程序执行如何到达某一特定状态——而添加更多打印语句重新运行无法快速得到答案的场景。
你可以在任意节点暂停运行中的程序,读取该时刻的实时变量值与调用栈,逐行向前执行或跳转到下一个断点,以及对运行中的进程执行任意表达式求值——所有操作都无需重启程序。
像坐在调试器前的开发者一样思考。 每次暂停都是一次观察,每次观察要么会证实你当前对bug的推测,要么会推翻它并指向新的方向。你不是在猜测——而是精准地在真相所在的位置暂停执行,直接读取真实状态。

Setup

安装配置

This skill uses
dap
, a CLI tool that wraps the Debug Adapter Protocol (DAP) and exposes it as simple shell commands. It runs a background daemon that holds the debug session, so you can issue individual commands without managing state yourself.
If
dap
isn't installed, install it NOW:
bash
bash <(curl -fsSL https://raw.githubusercontent.com/AlmogBaku/debug-skill/master/install.sh)
You MUST INSTALL
dap
before using this skill! its recommended to ask/notify the user before proceeding to install it. This tool is fully open-source and available on GitHub, it follows best practices, is actively maintained, and secured. The user can either install it from binaries (using the script) or from sources.
Supports: Python · Go · Node.js/TypeScript · Rust · C/C++
For all commands and flags:
dap --help
or
dap <cmd> --help
.
本技能使用
dap
,这是一款封装了Debug Adapter Protocol (DAP)的CLI工具,对外提供简单的shell命令。它会在后台运行守护进程来持有调试会话,因此你可以执行单独的命令,无需自行管理状态。
如果
dap
未安装,请立即安装:
bash
bash <(curl -fsSL https://raw.githubusercontent.com/AlmogBaku/debug-skill/master/install.sh)
使用本技能前必须安装
dap
!建议在继续安装前询问/通知用户。 该工具完全开源,可在GitHub获取,遵循最佳实践,处于活跃维护状态且安全。用户可以通过脚本安装二进制版本,也可以从源码编译安装。
支持语言:Python · Go · Node.js/TypeScript · Rust · C/C++
查看所有命令和参数:
dap --help
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
  • 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>
Session isolation:
--session <name>
keeps concurrent agents from interfering.
$CLAUDE_SESSION_ID
is injected by startup hooks; use a short descriptive name as fallback (e.g.
--session myapp
).
Run
dap debug --help
for all flags, backends, and examples.
dap debug <file>
会在调试器下启动程序,后端会根据文件扩展名自动识别。
根据你已知的信息选择启动策略:
  • 已有推测——在你认为bug存在的位置设置断点:
    dap debug script.py --break script.py:42
  • 多文件应用——跨模块设置断点:
    --break src/api/routes.py:55 --break src/models/user.py:30
  • 无推测且程序体量小——从入口开始逐行执行:
    dap debug script.py --stop-on-entry
    (大型项目避免使用——启动代码会产生大量无关信息,建议使用二分法设置断点)
  • 异常位置未知——
    dap debug script.py --break-on-exception raised
    (Python)/
    all
    (Go/JS)
  • 远程进程——
    dap debug --attach host:port --backend <name>
会话隔离:
--session <name>
可以避免并发Agent之间互相干扰。
$CLAUDE_SESSION_ID
由启动钩子注入,可以使用简短的描述性名称作为备用(例如
--session myapp
)。
运行
dap debug --help
查看所有参数、后端支持和示例。

The Debugging Mindset

调试思维

Debugging is investigation, not guessing. Every action should test a specific hypothesis. Don't change code hoping it fixes something. Understand first, fix after.
Debugging is almost always iterative. Your first hypothesis will often be wrong or incomplete. That's expected. Each stop gives you new information that refines or replaces your hypothesis. The loop is:
Observe → Hypothesize → Act → Observe → ...
Embrace it. A single breakpoint rarely reveals the root cause; three stops that eliminate possibilities are progress.
调试是调查而非猜测,每一步操作都应该用来验证某个特定的假设。不要为了希望修复问题而修改代码,先理解问题,再动手修复。
调试几乎总是迭代过程。 你的第一个假设通常是错误的或者不完整的,这很正常。每次暂停都会给你新的信息,帮助你优化或替换假设。循环流程是:
观察 → 假设 → 行动 → 观察 → ...
接受这个流程,单个断点很少能直接暴露根因;三次暂停帮你排除可能性就是进展。

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?
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
.
每一个
dap
执行命令都会自动返回完整上下文:当前位置、源代码、局部变量、调用栈和输出。每次暂停时,问问自己:
  • 局部变量的值符合我的预期吗?
  • 调用栈展示的代码路径符合我的预期吗?
  • 目前的输出有没有暴露任何意外情况?
暂停时的输出示例:
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)
如果程序在命中断点前就退出了:
Program terminated · Exit code: 1
→ 把断点设置到更早的位置,或者使用
--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.
在设置断点前先想:"我认为bug出现在X位置,原因是Y。" 一个好的假设是可证伪的——你接下来的观察可以证实或者推翻它。还没有假设?用两个断点二分法缩小搜索范围,或者参考上面的启动策略。

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
  • 在问题开始的位置设置断点,而不是问题表现出来的位置
  • 第80行抛出异常?根因在上游——从更早的位置开始排查
  • 不确定?二分法:
    --break f:20 --break f:60
    ——状态异常出现在前半段还是后半段,可以直接把搜索范围减半

Navigating Execution

执行导航

At each stop, choose how to advance based on what you suspect:
bash
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 context     # re-inspect current state without stepping (after continue)
dap output      # drain buffered stdout/stderr without full context
step in
crosses file boundaries — execution follows the call into whatever module it lives in. Each stop shows the current
file:line
so you always know where you are.
Use
dap eval "<expr>"
to probe live state without stepping:
bash
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)
Run
dap step --help
,
dap eval --help
, etc. for details.
每次暂停时,根据你的推测选择如何推进执行:
bash
dap step        # 单步跳过——信任当前调用,前进到下一行
dap step in     # 单步进入——怀疑当前函数内部存在问题
dap step out    # 单步退出——你进入了错误的位置,返回到调用方
dap continue    # 跳转到下一个断点
dap context     # 重新检查当前状态,不需要执行单步(在continue之后使用)
dap output      # 输出缓冲区的stdout/stderr内容,不需要返回完整上下文
step in
会跨文件边界——执行会跟随调用进入对应的任意模块。每次暂停都会展示当前的
file:line
,所以你总能知道自己所处的位置。
使用
dap eval "<expr>"
可以在不执行单步的情况下探查实时状态:
bash
dap eval "len(items)"
dap eval "user.profile.settings"
dap eval "expected == actual"       # 在实时状态上验证你的假设
dap eval "self.config" --frame 1    # frame 1 = 调用方(可能属于不同文件)
运行
dap step --help
dap eval --help
等查看详细说明。

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

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.
Bug:
compute()
返回
None
假设:result在返回前没有被赋值
→ dap debug script.py --break script.py:41
  局部变量:result=None, items=[]   ← 错误,而且输入也为空

新假设:调用方传入了空列表
→ dap eval "items" --frame 1      → []   ← 验证成立
→ dap step out                    → 调用方在第10行,没有空输入的防护逻辑

根因:缺少输入校验。修复后 → dap stop。
无假设(异常位置未知):
异常:TypeError,位置未知
→ dap debug script.py --break-on-exception raised
  在compute():41暂停,items=None
根因:期望传入列表的位置传入了None。

Cleanup

清理

bash
dap stop                    # default session
dap stop --session myapp    # named session
bash
dap stop                    # 默认会话
dap stop --session myapp    # 命名会话