dap — Real Debugging for Coding Agents
TL;DR
After installing @piex-dev/dap, the agent can "run and look" like a human. It won't replace tests, but it turns "guess the variable" into "read the variable".
Overview
Most coding agents "fix bugs" by reading code, guessing a cause, editing a few lines, re-running tests in bash, then guessing again. This works for simple issues but breaks on runtime-only problems: which stack frame threw? what was that local variable? does a breakpoint on a conditional branch hold?
DAP is the VS Code debugging protocol. @piex-dev/dap brings it to Pi: the model calls a debug tool to launch, set breakpoints, step and inspect variables.
How it works
Three layers: Agent (Pi + LLM decides) → DAP client (@piex-dev/dap translates to standard DAP requests) → Debug Adapter (debugpy/dlv/lldb-dap controls the process). The session state machine is running/stopped/terminated; each tool call returns a session summary + formatted text, not raw JSON-RPC.
launch/attach → spawn adapter(stdio) → initialize
→ running → stopped(breakpoint/step/exception)
→ stack_trace/variables/evaluate
→ continue/step_* → terminate
Adapter selection: defaults.json holds start command, language suffix, project-root marker and launch/attach defaults; launch auto-picks by suffix + workspace marker. The Node port is stdio-only (covers local debugging, no socket lifecycle), no remote TCP attach.
Usage
Install
pi install npm:@piex-dev/dap
Source: extensions/dap
Prerequisites
The extension handles protocol and sessions, not installing debuggers. Install the adapter for your language:
pip install debugpy # Python
brew install llvm # lldb-dap
go install github.com/go-delve/delve/cmd/dlv@latest # Go
14 adapters supported: gdb, lldb-dap, codelldb, debugpy, dlv, js-debug-adapter, netcoredbg, kotlin-debug-adapter, rdbg, php-debug-adapter, bash-debug-adapter, dart-debug-adapter, flutter-debug-adapter, elixir-ls-debugger.
Configuration
Defaults live in extensions/dap/defaults.json. No manual config needed — the extension auto-selects an adapter by file suffix + project-root marker; the model may also name an adapter explicitly.
Typical usage
debug(action=launch, program=./main.py)
debug(action=set_breakpoint, path=main.py, line=42)
debug(action=continue)
# after hit
debug(action=stack_trace)
debug(action=variables, variablesReference=…)
debug(action=evaluate, expression="user.id")
Verify
pi -e ./extensions/dap/src/dap.ts -p "what is 1+1" --no-session
Implementation
dap.ts registers the debug tool and dispatches actions; client.ts handles Content-Length frames + JSON-RPC; session.ts manages sessions, breakpoint queue, output buffer and idle cleanup; config.ts reads defaults.json and picks an adapter.
| Domain | actions |
|---|---|
| Session | launch / attach / terminate / sessions / output |
| Breakpoints | set_breakpoint / remove_breakpoint |
| Execution | continue / step_over / step_in / step_out / pause |
| Inspection | stack_trace / threads / scopes / variables / evaluate |
| Low-level | disassemble / read_memory / write_memory / modules / loaded_sources / custom_request |
Capabilities are checked against the adapter's reported capabilities: unsupported ops error out, no silent no-op. Engineering details: serialized breakpoint mutations, ring-buffered output (~128KB), idle reaping, clamped timeouts (5s–300s, default 30s), non-interactive env injection (PAGER=cat).
Design notes
| Project | Mechanism | piex choice |
|---|---|---|
| oh-my-pi dap | full DAP client: stdio + TCP + WebSocket; 14+ adapters; structured output; TUI variable explorer | Adopted: 14-adapter config, JSON-RPC framing, breakpoint queue, output cap, idle reaping. Not adopted: TCP/WebSocket, TUI overlay (pi API limits) |
| VS Code DAP | three-layer spec (editor / client / adapter) | Borrowed: three-layer split, capabilities check, auto context summary on stop |
Core trade-off: stdio only (simple and safe), no remote attach; text output first, TUI later; capabilities-driven action surface, not all at once.
Changelog
Roadmap
| Current | Impact | Plan |
|---|---|---|
| stdio only, no TCP/WebSocket | hard to attach remote debug servers | optional TCP as advanced, stdio default |
| data/instruction/exception breakpoints not fully exposed | "who wrote this memory" questions are hard | gradually expose by capabilities |
| completions, exceptionInfo not all exposed | existing adapter capabilities unused | add actions by usage frequency |
| plain-text output | stack/vars less readable than omp | default stop summary first, then TUI |
| depends on locally installed adapters | higher setup barrier | document gaps; preinstall in eval images |
Product direction: context-on-stop (auto top frame + key vars); project-aware launch (read .vscode/launch.json); eval hook (debug_success reproducible tasks).
Version history
| Version | Date | Changes |
|---|---|---|
| 0.1.1 | 2026-07-19 | Initial release: 14-adapter default config; DAP client (stdio + JSON-RPC); session management (breakpoint queue, ring-buffered output, idle reaping, clamped timeout); Node port (Bun.spawn → child_process.spawn) |
Source Markdown: docs/packages/dap.md