LLMs can read your code but they can't run it in their head. When something breaks, they end up asking you to paste errors and add console.log statements one at a time while they guess at what's going on.
llm-trace fixes this. It gives LLMs a way to instrument your code with structured traces, see actual runtime values, and figure out what went wrong without the back-and-forth.
Install the debugging skill so your LLM tool knows how to use llm-trace. The skill will ask to npm install llm-trace into your project — it's the SDK that provides the trace(), span(), and checkpoint() calls for code instrumentation.
Claude Code:
/plugin marketplace add moondef/llm-trace
/plugin install debugging-with-llm-trace@llm-traceCodex:
$skill-installer install https://github.com/moondef/llm-trace/tree/main/skills/debugging-with-llm-trace
Any tool (via npx):
npx skills add moondef/llm-traceOr clone and copy manually:
git clone https://github.com/moondef/llm-trace.git
cp -r llm-trace/skills/debugging-with-llm-trace ~/.claude/skills/Just ask your LLM to debug something. The skill handles the rest.
You say "this endpoint returns 500 sometimes" and it:
- Starts a tracing session (
llm-trace start) - Instruments the suspect code with
trace(),span(), andcheckpoint() - Runs the code to trigger the bug
- Reads the trace — actual values at each step, which span failed, the error
- Fixes the root cause based on what it saw
- Cleans up instrumentation and stops the session
Three primitives, all the LLM needs:
import { trace } from "llm-trace";
await trace("checkout", async (handle) => {
// span — time a step, nest arbitrarily
await handle.span("load-cart", async (h) => {
const cart = await db.getCart(userId);
// checkpoint — snapshot runtime values
h.checkpoint("cart", cart);
return cart;
});
});trace(name, fn) — wraps a complete operation. Captures start, end, duration, errors.
handle.span(name, fn) — a timed step within a trace. Nests to any depth.
handle.checkpoint(name, data?) — snapshots a value at a point in time (truncated at 64KB).
Errors are captured automatically — if anything throws, the trace records the error and stack.
llm-trace start # begin session
llm-trace list # all traces (JSON by default)
llm-trace list --errors # just failures
llm-trace show <id> # full trace tree
llm-trace tail # watch live
llm-trace stop # end session, delete tracesOutput is JSON by default (for LLM consumption). Add --human for readable output.
The LLM writes trace() / span() / checkpoint() calls into your code. When the code runs, events stream over HTTP to a local server that writes .ndjson files. The LLM reads those files via the CLI. After debugging, everything gets cleaned up — traces are ephemeral.
No dependencies. No config. Nothing persisted after stop.
| Variable | Default | Description |
|---|---|---|
LLM_TRACE_PORT |
13579 |
HTTP server port |
Issues and PRs welcome at github.com/moondef/llm-trace.