ACP Debug
Debug ACP agents by spawning them, capturing JSON-RPC frames, and analyzing capabilities.
Installation
- Make sure Claude is on your device and in your terminal.
Skills load from
~/.claude/skills/when Claude Code starts up β so you need it on your machine first. If you don't have it yet, install it once with the command below, then runclaudein any terminal to verify.One-time setupnpm i -g @anthropic-ai/claude-codeAlready have it? Skip ahead.
- Paste into Claude Code or into your terminal.
This copies the whole skill folder into
~/.claude/skills/acp-debug-kdlbs/β the SKILL.md plus any scripts, reference docs, or templates the skill ships with. Safe default: works for every skill.Faster alternative (instruction-only skills)
Skips the clone and grabs only the SKILL.md file. Don't use this if the skill ships Python scripts, reference markdowns, or asset templates β they won't be downloaded and the skill will fail when it tries to load them.
Quick install (SKILL.md only)Sign up to copy - Restart Claude Code.
Quit and reopen Claude Code (or any other agent that loads from
~/.claude/skills/). New skills are picked up on startup. - Just ask Claude.
Skills auto-activate when your request matches the skill's description β no slash command needed. Trigger phrases live in the skill's own frontmatter; you can read them in the βWhat this skill doesβ section above.
Prefer to read the source first? Open on GitHub.
When Claude uses it
Debug an ACP agent CLI by spawning it, speaking raw JSON-RPC, and capturing every frame to a JSONL file. Use when the user asks to probe an agent's capabilities, compare agents, test a prompt against an agent, inspect raw ACP wire frames, or investigate why an agent fails to initialize.
What this skill does
ACP Debug
Run a headless ACP JSON-RPC session against any registered kandev agent (or an arbitrary command), record every wire frame to a JSONL file, and summarize the handshake. Backed by the acpdbg binary at apps/backend/bin/acpdbg.
When to use this skill
- "what models does auggie advertise"
- "probe claude-acp" / "probe all agents" / "run the matrix"
- "debug why copilot-acp isn't starting"
- "what does a
session/newresponse actually look like for X" - "try this prompt against auggie with mode=ask"
- "reproduce session/load for session <id> against claude-acp"
- User mentions inspecting raw ACP wire payloads or a JSONL file from an earlier run
Before anything else: build the binary if missing
test -x apps/backend/bin/acpdbg || make -C apps/backend build-acpdbg
Sub-commands
acpdbg list # enumerate registered ACP agents
acpdbg probe <agent> # initialize + session/new + close
acpdbg probe --exec "<cmd> [args...]" # probe an arbitrary binary not in the registry
acpdbg mcp-probe <agent> # inject a temporary MCP sentinel into session/new
acpdbg prompt --prompt "..." [--model M] [--mode M] <agent>
acpdbg session-load --session-id <id> <agent>
acpdbg matrix # probe every ACP agent in parallel
Flags MUST come before the positional
<agent>. The CLI uses Go's stdlibflagparser, which stops at the first non-flag token β so any flag placed after<agent>is silently ignored (probe/matrix, e.g. a dropped--timeout) or errors (promptβ--prompt is required). Always writeacpdbg prompt --prompt "..." --timeout 240s <agent>, notacpdbg prompt <agent> --prompt ....
Shared flags (apply to every sub-command):
--out DIRβ JSONL output directory (default./acp-debug/)--file PATHβ exact JSONL path, overrides--out--timeout DURβ overall run timeout (default30s)--workdir PATHβ child cwd (default: fresh/tmp/kandev-acpdbg-<pid>-*)--verboseβ mirror frames to stderr--stderrβ capture child stderr into the JSONL
Steps
Create a task for each step below and mark them as completed as you go.
1. Pick the sub-command that matches the user's intent
- "what models does X have" / "does X support modes" β
acpdbg probe X - "test a prompt against X" β
acpdbg prompt --prompt "..." X - "compare all agents" / "run the matrix" β
acpdbg matrix - "resume session <id>" β
acpdbg session-load --session-id <id> X - "did this agent attach the injected MCP server" β
acpdbg mcp-probe X - "try this random binary" β
acpdbg probe --exec "path/to/bin --acp"
2. Run the command
Always capture stdout β it contains the JSONL file path (and for matrix, the summary table and matrix-summary.json path).
apps/backend/bin/acpdbg probe --timeout 45s auggie
For matrix, prefer --timeout 60s so npx-spawned agents have time to cold-start.
For Claude ACP, the generated default workdir is an absolute temporary
directory and is sent as the ACP cwd; no --workdir flag is required. If
you override it, supply an existing absolute directory (for example, run
mkdir -p /tmp/kandev-acpdbg-claude before passing that path to --workdir).
An empty cwd can cause Claude to reject session/new; confirm the cwd in
the recorded request frame before diagnosing a provider failure.
3. Read the JSONL file
The JSONL schema is:
direction | Meaning | Extra fields |
|---|---|---|
meta | acpdbg-generated marker | event (start / close), meta (map with agent, command, workdir for start; exit_code, reason for close) |
sent | Frame written to child's stdin | frame (JSON-RPC request or reply) |
received | Frame read from child's stdout | frame (JSON-RPC request, response, or notification) |
stderr | Child stderr line (only when --stderr) | line |
Entries are strictly chronological. Each line is a single JSON object terminated by \n.
Useful jq recipes:
# Full initialize response
jq -c 'select(.direction == "received" and .frame.id == 1)' acp-debug/<file>.jsonl
# Full session/new response (models, modes, auth)
jq '.frame.result' acp-debug/<file>.jsonl | head -50
# Just the models advertised
jq -r 'select(.direction == "received") | .frame.result.models.availableModels[]?.modelId' acp-debug/<file>.jsonl
# Close event (exit code + reason)
jq -c 'select(.direction == "meta" and .event == "close")' acp-debug/<file>.jsonl
# All agent-initiated requests we auto-replied to
jq -c 'select(.direction == "received" and .frame.method and .frame.id)' acp-debug/<file>.jsonl
4. Summarize for the user
Give a concise markdown summary: agent, protocol version, models found (with currentModelId), modes found (with currentModeId), auth methods, any errors, and the JSONL path for deeper inspection. Example:
**auggie** (protocol v1, auggie 0.20.1)
Models (11): claude-sonnet-4-6 (current), claude-opus-4-6, gpt-5-4, β¦
Modes (2): default (current), ask
Auth methods: (none advertised)
JSONL: acp-debug/auggie-probe-20260409-183104.jsonl
5. If something looks wrong, walk the frames
Common failure modes:
| Symptom | Likely cause | Next step |
|---|---|---|
meta close exit_code: 127 immediately | child binary not installed | Check which <cmd>; suggest install command |
meta close before any received frame | child crashed on startup | Re-run with --stderr to capture the error |
initialize response has populated authMethods but session/new fails | auth required | Surface the auth method ids; suggest setting env var / running CLI login |
session/new hangs (context deadline exceeded) | agent waiting on an unanswered agent-initiated request | Check JSONL for received frames with method + id that we auto-replied to with method not found β the agent may be retrying |
Response has no models / modes fields | agent doesn't expose them over ACP | Not a bug β document the gap |
Re-run with --stderr whenever the child exits before the handshake completes; the stderr lines land in the JSONL and usually contain the root cause.
For mcp-probe, distinguish sentinel_delivered (the agent accepted the
session/new configuration) from initialize_observed and
tools_list_observed (the temporary endpoint received MCP traffic). An
unobserved result is intentionally not a generic agent failure: a provider
can attach lazily or ignore the supplied transport. Sentinel metadata has only
opaque connection IDs and timestamps; the explicit acpdbg JSONL still contains
raw ACP frames and must stay a developer-only artifact.
6. For matrix, read matrix-summary.json too
jq '.' acp-debug/matrix-summary.json
One entry per agent with status, models_count, current_model_id, auth_methods_count, duration_ms, and jsonl (the full per-agent JSONL file). Useful for answering "which agents succeeded / failed / need auth" without re-reading every JSONL.
What this skill does NOT do
- No interactive UI. For ad-hoc side-by-side comparison, read the
matrix-summary.jsonoutput or build a separate visualization tool on top of the JSONL. - No permission-request handling beyond canned replies. Agent-initiated requests (
fs/read_text_file,session/request_permission, etc.) are answered with-32601 method not foundso the session doesn't hang. If you need to exercise a real permission flow, use the full kandev backend. - No automatic credential bootstrap. The child inherits the parent shell's env; if an auth check fails the skill reports which methods were advertised and lets the user fix their local credentials.
- No Docker / remote executor support. Standalone subprocess only β same as a manual
auggie --acpinvocation.
Related skills
Documentation Co-Authoring
anthropics
Guide structured workflows for writing docs, proposals, and technical specs collaboratively.
MCP Server Builder
anthropics
Build protocol servers that connect language models to external APIs and services.
Skill Builder & Optimizer
anthropics
Create, edit, and optimize Claude skills with performance testing and benchmarking.
Multi-Component Web Artifacts
anthropics
Build complex React artifacts with Tailwind CSS and shadcn/ui components.