llm-trace 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,74 +1,76 @@
1
1
  # llm-trace
2
2
 
3
- When an LLM debugs your code, it can't see what happens at runtime. It reads your source, guesses what went wrong, and asks you to paste error messages. You end up as a middleman running code, copying output, adding print statements.
3
+ 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.
4
4
 
5
- llm-trace lets LLMs see runtime behavior directly. They instrument your code with traces, run it, inspect what happened, and fix the bug without asking you to copy-paste anything.
5
+ 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.
6
6
 
7
- ## Setup
7
+ ## Try It
8
8
 
9
9
  ```bash
10
10
  npm install llm-trace
11
11
  ```
12
12
 
13
- Add the [debugging skill](skills/debugging-with-llm-trace/SKILL.md) to your LLM tool (Claude Code, Codex, etc.) so it knows how to use llm-trace.
13
+ Add the [debugging skill](skills/debugging-with-llm-trace/SKILL.md) to Claude Code (or any LLM coding tool) and ask it to debug something. That's it the skill teaches it the workflow.
14
14
 
15
- ## How It Works
15
+ ### What happens next
16
16
 
17
- 1. LLM runs `npx llm-trace start` to begin a debugging session
18
- 2. LLM instruments your code with `trace()`, `span()`, and `checkpoint()` calls
19
- 3. You run your code (or LLM runs it)
20
- 4. LLM queries traces with `npx llm-trace list`, `show`, `tail`
21
- 5. LLM reads structured runtime data, identifies root cause, fixes the bug
22
- 6. LLM runs `npx llm-trace stop` to clean up
17
+ You tell the LLM "this endpoint returns 500 sometimes" and it:
23
18
 
24
- Traces are ephemeral they exist only during the debugging session and are deleted when it ends.
19
+ 1. Runs `npx llm-trace start`
20
+ 2. Wraps the endpoint in `trace()` with `span()` and `checkpoint()` calls
21
+ 3. Triggers the bug
22
+ 4. Reads the trace — sees actual values at each step, which span failed, the error
23
+ 5. Fixes the root cause based on what it saw
24
+ 6. Removes instrumentation, runs `npx llm-trace stop`
25
25
 
26
- ## API
27
-
28
- ### `trace(name, fn)` — wrap a complete operation
26
+ ## Three Primitives
29
27
 
30
28
  ```typescript
31
29
  import { trace } from "llm-trace";
32
30
 
33
- const result = await trace("handle-request", async (handle) => {
34
- // handle.span() and handle.checkpoint() available here
35
- return processRequest(req);
36
- });
37
- ```
31
+ await trace("checkout", async (handle) => {
38
32
 
39
- ### `handle.span(name, fn)` — time a step within a trace
33
+ // span — time a step, nest arbitrarily
34
+ await handle.span("load-cart", async (h) => {
35
+ const cart = await db.getCart(userId);
40
36
 
41
- ```typescript
42
- await handle.span("call-llm", async (h) => {
43
- const response = await llm.chat(prompt);
44
- h.checkpoint("response", response);
45
- return response;
37
+ // checkpoint — snapshot runtime values
38
+ h.checkpoint("cart", cart);
39
+
40
+ return cart;
41
+ });
46
42
  });
47
43
  ```
48
44
 
49
- ### `handle.checkpoint(name, data?)`snapshot state at a point in time
45
+ **`trace(name, fn)`**wraps a complete operation. Captures start, end, duration, errors.
50
46
 
51
- ```typescript
52
- handle.checkpoint("parsed-input", { tokens: 142 });
53
- ```
47
+ **`handle.span(name, fn)`** — a timed step within a trace. Nests to any depth.
54
48
 
55
- Spans nest arbitrarily. Errors are captured automatically. Checkpoint data is truncated at 64KB.
49
+ **`handle.checkpoint(name, data?)`** snapshots a value (truncated at 64KB).
50
+
51
+ Errors are captured automatically — if anything throws, the trace records the error and stack.
56
52
 
57
53
  ## CLI
58
54
 
59
- | Command | Description |
60
- |---------|-------------|
61
- | `llm-trace start` | Begin session, start trace server |
62
- | `llm-trace stop` | End session, delete all traces |
63
- | `llm-trace status` | Check if a session is active |
64
- | `llm-trace list` | List traces (`--errors`, `--name <glob>`, `--last <n>`, `--human`) |
65
- | `llm-trace show <id>` | Show trace tree (`--human` for readable output) |
66
- | `llm-trace tail` | Stream new traces (`--errors`, `--name <glob>`) |
55
+ ```bash
56
+ llm-trace start # begin session
57
+ llm-trace list # all traces (JSON by default)
58
+ llm-trace list --errors # just failures
59
+ llm-trace show <id> # full trace tree
60
+ llm-trace tail # watch live
61
+ llm-trace stop # end session, delete traces
62
+ ```
63
+
64
+ Output is JSON by default (for LLM consumption). Add `--human` for readable output.
65
+
66
+ ## How It Fits Together
67
+
68
+ 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 is cleaned up — traces are ephemeral.
67
69
 
68
- Default output is JSON (for LLM consumption). `--human` for readable output.
70
+ No dependencies. No config. Nothing persisted after `stop`.
69
71
 
70
72
  ## Configuration
71
73
 
72
74
  | Variable | Default | Description |
73
75
  |----------|---------|-------------|
74
- | `TRACE_AI_PORT` | `13579` | HTTP server port |
76
+ | `LLM_TRACE_PORT` | `13579` | HTTP server port |
package/dist/cli.cjs CHANGED
@@ -168,7 +168,7 @@ async function getFormattedList(logDir, options) {
168
168
  }), options.human === true);
169
169
  }
170
170
  async function runList(options) {
171
- const logDir = (0, node_path.join)(process.cwd(), ".trace-ai-logs");
171
+ const logDir = (0, node_path.join)(process.cwd(), ".llm-trace-logs");
172
172
  if (!(0, node_fs.existsSync)(logDir)) {
173
173
  console.log("No active session.");
174
174
  return;
@@ -179,7 +179,7 @@ async function runList(options) {
179
179
  //#endregion
180
180
  //#region src/cli/commands/show.ts
181
181
  async function runShow(id, options) {
182
- const logDir = (0, node_path.join)(process.cwd(), ".trace-ai-logs");
182
+ const logDir = (0, node_path.join)(process.cwd(), ".llm-trace-logs");
183
183
  if (!(0, node_fs.existsSync)(logDir)) {
184
184
  console.log("No active session.");
185
185
  return;
@@ -191,7 +191,7 @@ async function runShow(id, options) {
191
191
  //#endregion
192
192
  //#region src/cli/commands/start.ts
193
193
  async function startSession(projectDir, options = {}) {
194
- const logDir = (0, node_path.join)(projectDir, ".trace-ai-logs");
194
+ const logDir = (0, node_path.join)(projectDir, ".llm-trace-logs");
195
195
  if ((0, node_fs.existsSync)(logDir)) return {
196
196
  created: false,
197
197
  reason: "already_active"
@@ -199,17 +199,17 @@ async function startSession(projectDir, options = {}) {
199
199
  (0, node_fs.mkdirSync)(logDir, { recursive: true });
200
200
  const gitignorePath = (0, node_path.join)(projectDir, ".gitignore");
201
201
  if ((0, node_fs.existsSync)(gitignorePath)) {
202
- if (!(0, node_fs.readFileSync)(gitignorePath, "utf-8").includes(".trace-ai-logs/")) (0, node_fs.appendFileSync)(gitignorePath, "\n.trace-ai-logs/\n");
203
- } else (0, node_fs.writeFileSync)(gitignorePath, ".trace-ai-logs/\n");
202
+ if (!(0, node_fs.readFileSync)(gitignorePath, "utf-8").includes(".llm-trace-logs/")) (0, node_fs.appendFileSync)(gitignorePath, "\n.llm-trace-logs/\n");
203
+ } else (0, node_fs.writeFileSync)(gitignorePath, ".llm-trace-logs/\n");
204
204
  if (!options.skipServer) {
205
- const port = parseInt(process.env.TRACE_AI_PORT || "", 10) || 13579;
205
+ const port = parseInt(process.env.LLM_TRACE_PORT || "", 10) || 13579;
206
206
  const script = (0, node_path.join)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href), "..", "standalone.js");
207
207
  const child = (0, node_child_process.spawn)(process.execPath, [script], {
208
208
  detached: true,
209
209
  stdio: "ignore",
210
210
  env: {
211
211
  ...process.env,
212
- TRACE_AI_PORT: String(port),
212
+ LLM_TRACE_PORT: String(port),
213
213
  TRACE_AI_DIR: logDir
214
214
  }
215
215
  });
@@ -234,7 +234,7 @@ async function runStart() {
234
234
  //#endregion
235
235
  //#region src/cli/commands/status.ts
236
236
  function getSessionStatus(projectDir) {
237
- const logDir = (0, node_path.join)(projectDir, ".trace-ai-logs");
237
+ const logDir = (0, node_path.join)(projectDir, ".llm-trace-logs");
238
238
  if (!(0, node_fs.existsSync)(logDir)) return { active: false };
239
239
  const files = (0, node_fs.readdirSync)(logDir).filter((f) => f.endsWith(".ndjson"));
240
240
  let errorCount = 0;
@@ -264,7 +264,7 @@ async function runStatus() {
264
264
  //#endregion
265
265
  //#region src/cli/commands/stop.ts
266
266
  async function stopSession(projectDir) {
267
- const logDir = (0, node_path.join)(projectDir, ".trace-ai-logs");
267
+ const logDir = (0, node_path.join)(projectDir, ".llm-trace-logs");
268
268
  if (!(0, node_fs.existsSync)(logDir)) return {
269
269
  stopped: false,
270
270
  reason: "no_session"
@@ -294,7 +294,7 @@ function summarizeFile(filePath) {
294
294
  }
295
295
  }
296
296
  async function runTail(options) {
297
- const logDir = (0, node_path.join)(process.cwd(), ".trace-ai-logs");
297
+ const logDir = (0, node_path.join)(process.cwd(), ".llm-trace-logs");
298
298
  if (!(0, node_fs.existsSync)(logDir)) {
299
299
  console.log("No active session.");
300
300
  return;
@@ -343,15 +343,15 @@ function parseCliArgs(argv) {
343
343
 
344
344
  //#endregion
345
345
  //#region src/cli/index.ts
346
- const HELP = `trace-ai — Structured execution traces for LLM debugging
346
+ const HELP = `llm-trace — Structured execution traces for LLM debugging
347
347
 
348
348
  Usage:
349
- trace-ai start Begin debugging session
350
- trace-ai stop End session, delete traces
351
- trace-ai status Show session info
352
- trace-ai list [--errors] [--name <pattern>] [--last <n>] [--human]
353
- trace-ai show <id> [--human]
354
- trace-ai tail [--errors] [--name <pattern>]
349
+ llm-trace start Begin debugging session
350
+ llm-trace stop End session, delete traces
351
+ llm-trace status Show session info
352
+ llm-trace list [--errors] [--name <pattern>] [--last <n>] [--human]
353
+ llm-trace show <id> [--human]
354
+ llm-trace tail [--errors] [--name <pattern>]
355
355
  `;
356
356
  async function main() {
357
357
  const { command, id, options } = parseCliArgs(process.argv.slice(2));
@@ -362,7 +362,7 @@ async function main() {
362
362
  case "list": return runList(options);
363
363
  case "show":
364
364
  if (!id) {
365
- console.error("Usage: trace-ai show <id>");
365
+ console.error("Usage: llm-trace show <id>");
366
366
  process.exit(1);
367
367
  }
368
368
  return runShow(id, options);
package/dist/cli.js CHANGED
@@ -168,7 +168,7 @@ async function getFormattedList(logDir, options) {
168
168
  }), options.human === true);
169
169
  }
170
170
  async function runList(options) {
171
- const logDir = join(process.cwd(), ".trace-ai-logs");
171
+ const logDir = join(process.cwd(), ".llm-trace-logs");
172
172
  if (!existsSync(logDir)) {
173
173
  console.log("No active session.");
174
174
  return;
@@ -179,7 +179,7 @@ async function runList(options) {
179
179
  //#endregion
180
180
  //#region src/cli/commands/show.ts
181
181
  async function runShow(id, options) {
182
- const logDir = join(process.cwd(), ".trace-ai-logs");
182
+ const logDir = join(process.cwd(), ".llm-trace-logs");
183
183
  if (!existsSync(logDir)) {
184
184
  console.log("No active session.");
185
185
  return;
@@ -191,7 +191,7 @@ async function runShow(id, options) {
191
191
  //#endregion
192
192
  //#region src/cli/commands/start.ts
193
193
  async function startSession(projectDir, options = {}) {
194
- const logDir = join(projectDir, ".trace-ai-logs");
194
+ const logDir = join(projectDir, ".llm-trace-logs");
195
195
  if (existsSync(logDir)) return {
196
196
  created: false,
197
197
  reason: "already_active"
@@ -199,17 +199,17 @@ async function startSession(projectDir, options = {}) {
199
199
  mkdirSync(logDir, { recursive: true });
200
200
  const gitignorePath = join(projectDir, ".gitignore");
201
201
  if (existsSync(gitignorePath)) {
202
- if (!readFileSync(gitignorePath, "utf-8").includes(".trace-ai-logs/")) appendFileSync(gitignorePath, "\n.trace-ai-logs/\n");
203
- } else writeFileSync(gitignorePath, ".trace-ai-logs/\n");
202
+ if (!readFileSync(gitignorePath, "utf-8").includes(".llm-trace-logs/")) appendFileSync(gitignorePath, "\n.llm-trace-logs/\n");
203
+ } else writeFileSync(gitignorePath, ".llm-trace-logs/\n");
204
204
  if (!options.skipServer) {
205
- const port = parseInt(process.env.TRACE_AI_PORT || "", 10) || 13579;
205
+ const port = parseInt(process.env.LLM_TRACE_PORT || "", 10) || 13579;
206
206
  const script = join(fileURLToPath(import.meta.url), "..", "standalone.js");
207
207
  const child = spawn(process.execPath, [script], {
208
208
  detached: true,
209
209
  stdio: "ignore",
210
210
  env: {
211
211
  ...process.env,
212
- TRACE_AI_PORT: String(port),
212
+ LLM_TRACE_PORT: String(port),
213
213
  TRACE_AI_DIR: logDir
214
214
  }
215
215
  });
@@ -234,7 +234,7 @@ async function runStart() {
234
234
  //#endregion
235
235
  //#region src/cli/commands/status.ts
236
236
  function getSessionStatus(projectDir) {
237
- const logDir = join(projectDir, ".trace-ai-logs");
237
+ const logDir = join(projectDir, ".llm-trace-logs");
238
238
  if (!existsSync(logDir)) return { active: false };
239
239
  const files = readdirSync(logDir).filter((f) => f.endsWith(".ndjson"));
240
240
  let errorCount = 0;
@@ -264,7 +264,7 @@ async function runStatus() {
264
264
  //#endregion
265
265
  //#region src/cli/commands/stop.ts
266
266
  async function stopSession(projectDir) {
267
- const logDir = join(projectDir, ".trace-ai-logs");
267
+ const logDir = join(projectDir, ".llm-trace-logs");
268
268
  if (!existsSync(logDir)) return {
269
269
  stopped: false,
270
270
  reason: "no_session"
@@ -294,7 +294,7 @@ function summarizeFile(filePath) {
294
294
  }
295
295
  }
296
296
  async function runTail(options) {
297
- const logDir = join(process.cwd(), ".trace-ai-logs");
297
+ const logDir = join(process.cwd(), ".llm-trace-logs");
298
298
  if (!existsSync(logDir)) {
299
299
  console.log("No active session.");
300
300
  return;
@@ -343,15 +343,15 @@ function parseCliArgs(argv) {
343
343
 
344
344
  //#endregion
345
345
  //#region src/cli/index.ts
346
- const HELP = `trace-ai — Structured execution traces for LLM debugging
346
+ const HELP = `llm-trace — Structured execution traces for LLM debugging
347
347
 
348
348
  Usage:
349
- trace-ai start Begin debugging session
350
- trace-ai stop End session, delete traces
351
- trace-ai status Show session info
352
- trace-ai list [--errors] [--name <pattern>] [--last <n>] [--human]
353
- trace-ai show <id> [--human]
354
- trace-ai tail [--errors] [--name <pattern>]
349
+ llm-trace start Begin debugging session
350
+ llm-trace stop End session, delete traces
351
+ llm-trace status Show session info
352
+ llm-trace list [--errors] [--name <pattern>] [--last <n>] [--human]
353
+ llm-trace show <id> [--human]
354
+ llm-trace tail [--errors] [--name <pattern>]
355
355
  `;
356
356
  async function main() {
357
357
  const { command, id, options } = parseCliArgs(process.argv.slice(2));
@@ -362,7 +362,7 @@ async function main() {
362
362
  case "list": return runList(options);
363
363
  case "show":
364
364
  if (!id) {
365
- console.error("Usage: trace-ai show <id>");
365
+ console.error("Usage: llm-trace show <id>");
366
366
  process.exit(1);
367
367
  }
368
368
  return runShow(id, options);
package/dist/index.cjs CHANGED
@@ -157,7 +157,7 @@ function createHttpWriter(serverUrl) {
157
157
  });
158
158
  } catch {
159
159
  if (!warned) {
160
- console.warn("[trace-ai] Server not running, traces disabled.");
160
+ console.warn("[llm-trace] Server not running, traces disabled.");
161
161
  warned = true;
162
162
  }
163
163
  }
@@ -188,7 +188,7 @@ function createHttpWriter(serverUrl) {
188
188
  //#endregion
189
189
  //#region src/index.ts
190
190
  const defaultTracer = createTracer({
191
- writer: createHttpWriter(`http://127.0.0.1:${(typeof process !== "undefined" ? parseInt(process.env?.TRACE_AI_PORT || "", 10) : NaN) || 13579}`),
191
+ writer: createHttpWriter(`http://127.0.0.1:${(typeof process !== "undefined" ? parseInt(process.env?.LLM_TRACE_PORT || "", 10) : NaN) || 13579}`),
192
192
  idGenerator: createCryptoIdGenerator(),
193
193
  clock: createSystemClock()
194
194
  });
package/dist/index.js CHANGED
@@ -156,7 +156,7 @@ function createHttpWriter(serverUrl) {
156
156
  });
157
157
  } catch {
158
158
  if (!warned) {
159
- console.warn("[trace-ai] Server not running, traces disabled.");
159
+ console.warn("[llm-trace] Server not running, traces disabled.");
160
160
  warned = true;
161
161
  }
162
162
  }
@@ -187,7 +187,7 @@ function createHttpWriter(serverUrl) {
187
187
  //#endregion
188
188
  //#region src/index.ts
189
189
  const defaultTracer = createTracer({
190
- writer: createHttpWriter(`http://127.0.0.1:${(typeof process !== "undefined" ? parseInt(process.env?.TRACE_AI_PORT || "", 10) : NaN) || 13579}`),
190
+ writer: createHttpWriter(`http://127.0.0.1:${(typeof process !== "undefined" ? parseInt(process.env?.LLM_TRACE_PORT || "", 10) : NaN) || 13579}`),
191
191
  idGenerator: createCryptoIdGenerator(),
192
192
  clock: createSystemClock()
193
193
  });
@@ -65,7 +65,7 @@ function createTraceServer(logDir) {
65
65
 
66
66
  //#endregion
67
67
  //#region src/server/standalone.ts
68
- const port = parseInt(process.env.TRACE_AI_PORT || "13579", 10);
68
+ const port = parseInt(process.env.LLM_TRACE_PORT || "13579", 10);
69
69
  const logDir = process.env.TRACE_AI_DIR || "";
70
70
  if (!logDir) {
71
71
  console.error("TRACE_AI_DIR required");
@@ -65,7 +65,7 @@ function createTraceServer(logDir) {
65
65
 
66
66
  //#endregion
67
67
  //#region src/server/standalone.ts
68
- const port = parseInt(process.env.TRACE_AI_PORT || "13579", 10);
68
+ const port = parseInt(process.env.LLM_TRACE_PORT || "13579", 10);
69
69
  const logDir = process.env.TRACE_AI_DIR || "";
70
70
  if (!logDir) {
71
71
  console.error("TRACE_AI_DIR required");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-trace",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "description": "Structured execution traces for LLM debugging",
6
6
  "license": "MIT",