SkillAgentSearch skills...

acpdbg

acpdbg is an LLDB assistant that use agent client protocol

Install / Use

claude mcp add phimage -- npx -y github:phimage/acpdbg

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

76/100

Supported Platforms

Claude Code
Claude Desktop
GitHub Copilot

Tags

<p align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/phimage/acpdbg/main/assets/logo.png"> <img src="https://raw.githubusercontent.com/phimage/acpdbg/main/assets/logo-light.png" alt="acpdbg" width="320"> </picture> </p> <p align="center"><strong>Debug native crashes by handing them to your coding agent.</strong></p>

acpdbg is an LLDB assistant. When a C/C++/Rust/Swift program stops (crash, signal, or breakpoint), it captures an enriched snapshot of the failure — the backtrace, every frame's arguments, and the surrounding source — and asks an AI to explain the root cause and propose a fix. The AI can then run live debugger commands to confirm its hypothesis, just like you would.

acpdbg speaks the Agent Client Protocol (ACP) to whatever coding agent you already run — GitHub Copilot CLI, the Gemini CLI, the Claude Code ACP adapter, or the bundled zero-setup mock agent so you can try it in ten seconds.

Real output, acpdbg --agent copilot -- ./samples/crash:

acpdbg → copilot (investigating…)

• Run crash under lldb and inspect variables at breakpoint (completed)
Confirmed live: `s` (second parameter to `describe`) is 0x0000000000000000 —
a NULL pointer — right at the point where strlen(s) dereferences it, matching
the reported crash address 0x0.

Root cause: In main, `name` is set to NULL whenever the program is run with no
arguments (argc == 1). That NULL is passed into describe(..., name) and handed
to strlen(s) with no NULL-check, so strlen dereferences 0x0 → SIGSEGV.

One-line fix (guard in describe):
    return s ? strlen(s) : 0;

Install

acpdbg is a normal Python package (Python 3.10+). The only dependency is the ACP SDK.

pip install acpdbg          # or: pipx install acpdbg

You do not need to install acpdbg into LLDB's own Python. The LLDB plugin is pure standard library, so it loads even in an old embedded interpreter (for example, Xcode's LLDB ships Python 3.9). The agent itself runs in a separate helper process on the Python you installed acpdbg into. acpdbg --install-lldbinit wires the two together automatically — see Load it in every session.

You also need lldb itself:

  • macOS: xcode-select --install
  • Debian/Ubuntu: sudo apt install lldb
  • Fedora: sudo dnf install lldb python3-lldb

Try it in 10 seconds (nothing else to install)

git clone https://github.com/acpdbg/acpdbg && cd acpdbg/samples
make                     # builds ./crash with -g
acpdbg -- ./crash        # runs it; on the crash the bundled mock agent explains

The mock agent is a real ACP agent that reads your crashing source over the protocol and streams back a diagnosis. It proves the whole loop works offline. Swap in a real agent when you want real analysis (below).

The CLI runs your program under lldb and triggers the agent from a stop hook when the process faults. If your LLDB build doesn't stop on the fault under batch mode, use the interactive path below — it always works.

Use a real coding agent

Point acpdbg at any ACP-compatible agent:

# GitHub Copilot CLI  (npm i -g @github/copilot, then `copilot` on PATH)   ← verified
acpdbg --agent copilot -- ./crash

# Google Gemini CLI  (npm i -g @google/gemini-cli, then `gemini` on PATH)
acpdbg --agent gemini -- ./crash

# Claude Code ACP adapter  (npm i -g @zed-industries/claude-code-acp)
acpdbg --agent claude-code -- ./crash

# Any other ACP agent: pass its launch command verbatim
acpdbg --agent "my-agent --acp" -- ./crash

GitHub Copilot CLI (copilot --acp) is the reference agent used in the example above. Different agents bring different tools: Copilot investigates with its own shell and lldb, while agents that honour ACP mcpServers drive acpdbg's built-in debugger_command / get_backtrace / get_locals tools against the already stopped process. Either way the answer is streamed back to your terminal.

Use it inside an interactive LLDB session

acpdbg is also a plain LLDB plugin — drive it straight from an LLDB session:

$ lldb ./crash
(lldb) command script import acpdbg.lldb_plugin
(lldb) run
...
Process stopped: EXC_BAD_ACCESS (SIGSEGV)
(lldb) ask why did this stop and how do I fix it?
(lldb) acpdbg config agent copilot     # switch agents on the fly

Commands added to LLDB:

| Command | What it does | | --- | --- | | ask <question> | Investigate the stopped program and answer. | | why | Shorthand for "why did this stop?" | | acpdbg <question> | Same as ask. | | acpdbg config | Show configuration. | | acpdbg config <key> <value> | Change a setting (see below). | | acpdbg session [start\|stop\|reset] | Manage the persistent agent conversation (see below). | | acpdbg serve / acpdbg serve stop | Expose the session to an external MCP client (see below). | | copilot <question> | Ask GitHub Copilot CLI, one-off. | | claude <question> | Ask Claude Code (via the ACP adapter), one-off. | | gemini <question> | Ask Gemini CLI, one-off. |

The per-agent commands are registered only for agents actually installed (their executable resolves on PATH when the plugin loads). They ask that agent for a single question without changing the configured default agent:

(lldb) why                        # uses the configured agent
(lldb) claude and what would you change to fix it?   # one-off Claude opinion

Load it in every session (.lldbinit)

Add the commands to your ~/.lldbinit once so they're available in every LLDB session automatically — including inside Xcode:

acpdbg --install-lldbinit          # or: acpdbg --print-lldbinit  to see the snippet

On load you'll see a confirmation line so you know it's active:

acpdbg 0.1.0 loaded — commands: ask, why, acpdbg  (agent: mock; debugger Python 3.9).
  Stop your program (crash or breakpoint), then: ask why did this stop?

The snippet puts acpdbg on LLDB's path and records which Python to run the agent helper with, so it works no matter what Python your LLDB embeds. It's managed by markers and is idempotent — re-run acpdbg --install-lldbinit after upgrading to refresh it (it preserves the rest of your ~/.lldbinit).

Xcode: Xcode's LLDB uses an older embedded Python (3.9). That's fine — the plugin runs there and launches the agent out-of-process. Just make sure the acpdbg --install-lldbinit snippet is in ~/.lldbinit, then in Xcode's debugger console ((lldb)), at any stop, type ask ….

Choosing the agent for Xcode

The agent is selected by the ACPDBG_AGENT environment variable (default mock). Xcode is launched from the macOS GUI, so it does not inherit your shell — an export ACPDBG_AGENT=… in ~/.zshrc won't reach it, and its PATH won't include /opt/homebrew/bin. Bake both into ~/.lldbinit in one step:

acpdbg --install-lldbinit --agent copilot

This records ACPDBG_AGENT=copilot and adds the agent's directory to PATH so it resolves under Xcode's minimal environment. Verify from Xcode's console with acpdbg config — it should show agent = copilot (/opt/homebrew/bin/copilot --acp). You can still switch per session with acpdbg config agent <name>.

Not just crashes — analyze live state at any stop

ask works at any stop: a breakpoint, a watchpoint, a signal, or a manual process interrupt — not only crashes. Stop wherever you want to reason about the program and ask about the current state. The agent sees each frame's live argument values and can run debugger commands (frame variable, p expr, …) to inspect anything else it needs:

(lldb) breakpoint set --name process_request
(lldb) run
...
Process stopped at breakpoint 1.1
(lldb) ask why is `retry_count` already 3 here? which caller set it?

Ask follow-ups — the agent remembers (persistent sessions)

By default the first ask opens one persistent agent conversation and every later ask continues it: the agent remembers its earlier findings, and the agent's startup cost (minutes, for some CLIs) is paid once per debug session instead of once per question.

(lldb) ask why did this crash?
acpdbg → copilot (starting the persistent session — later asks reuse it)
...
(lldb) ask and what's the smallest safe fix?
acpdbg → copilot (session turn 2)          # same conversation, instant start

Follow-ups send only your question. If the program has stopped anew since the last ask (a re-run, the next breakpoint), acpdbg notices and resends fresh context automatically, telling the agent its earlier live state is stale.

(lldb) acpdbg session          # status: agent, turns, uptime
(lldb) acpdbg session reset    # forget the conversation, keep the agent warm
(lldb) acpdbg session stop     # end it (the next ask opens a fresh one)
(lldb) acpdbg session start    # open one explicitly, before any ask

acpdbg config session off (or --no-session, or ACPDBG_SESSION=0) restores the old behavior — a fresh one-shot agent per ask. Asking a different agent (e.g. a one-off gemini <question> while the session is with copilot) runs one-shot without disturbing the conversation. One caveat: permission prompt mode needs the console for its interactive approvals, so those asks always run one-shot.

Let the agent drive execution (debug like a human)

By default the agent can only observe. Turn on control mode and it also gets tools to step and run the program like you would at the prompt:

(lldb) acpdbg config control on          # or: acpdbg --control -- ./prog
(lldb) ask set a breakpoint in parse(), continue to it, then step until `n` goes negative

Control tools: step_over, step_into, step_out, continue_execution, set_breakpoint, and run_to_line. After each step the agent is told where the program stopped and the source line, so it can watch state evolve and stop once it has found the cause. Control is off by default — during crash triage you usually don't want to resume past the fault and lose it.

These live tools reach agents that honour ACP's mcpServers (e.g. Gemini CLI). Some agents (including GitHub Copilot CLI) prefer their own built-in shell and debugger instead — they still debug from acpdbg's captured context, they just don't call these specific tools.

Drive it from an external app (Claude Code, Copilot, Cursor…)

Normally acpdbg launches the agent for you. But you can also expose a live lldb session as an MCP server and drive it from an MCP-capable app you already have open — it connects to the debugger you're sitting in front of:

(lldb) acpdbg config control on     # optional: include step/continue tools
(lldb) run                          # stop somewhere (crash or breakpoint)
(lldb) acpdbg serve
acpdbg: debugger exposed to external MCP clients — step/continue/breakpoint tools INCLUDED.
  bridge file: ~/.acpdbg/bridge.json

  claude mcp add acpdbg --env ACPDBG_BRIDGE_FILE=~/.acpdbg/bridge.json --env ACPDBG_CONTROL=1 -- /path/to/acpdbg-mcp

acpdbg serve keeps a bridge alive and writes its connection info to a stable file, so the external app's MCP config never changes between sessions. Add the printed acpdbg MCP server to the app once; from then on, whenever an lldb session is serve-ing, that app can call get_backtrace, get_locals, debugger_command, and (in control mode) step_over / continue_execution / set_breakpoint / … against your live process. Run acpdbg serve stop to end.

Keep the lldb session stopped and don't type lldb commands while an external app is driving it — one driver at a time. The bridge is a local, token-guarded

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars3
CategoryDevelopment
Updated1mo ago
Forks0

Languages

Python

Security Score

87/100

Audited on Aug 1, 2026

2 low