Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
.claude/skills/kdlbs-acp-debug/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 190% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 67% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 65% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 131% | 0% |
| case-11 | ✗→✓ | ▲ Improved | -13% | 0% |
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.
session/new response actually look like for X"bashtest -x apps/backend/bin/acpdbg || make -C apps/backend build-acpdbg
textacpdbg 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 stdlib > flag parser, 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 write > acpdbg prompt --prompt "..." --timeout 240s <agent>, not acpdbg 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 (default 30s)--workdir PATH — child cwd (default: fresh /tmp/kandev-acpdbg-<pid>-*)--verbose — mirror frames to stderr--stderr — capture child stderr into the JSONLCreate a task for each step below and mark them as completed as you go.
acpdbg probe Xacpdbg prompt --prompt "..." Xacpdbg matrixacpdbg session-load --session-id <id> Xacpdbg mcp-probe Xacpdbg probe --exec "path/to/bin --acp"Always capture stdout — it contains the JSONL file path (and for matrix, the summary table and matrix-summary.json path).
bashapps/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.
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:
bash# 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
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:
text**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
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.
matrix, read matrix-summary.json toobashjq '.' 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.
matrix-summary.json output or build a separate visualization tool on top of the JSONL.fs/read_text_file, session/request_permission, etc.) are answered with -32601 method not found so the session doesn't hang. If you need to exercise a real permission flow, use the full kandev backend.auggie --acp invocation.Other measured skills in the registry, with their headline benchmark lift.