@tangle-network/traces 0.8.18 → 0.8.20

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,6 +1,6 @@
1
1
  # traces
2
2
 
3
- > Point `traces` at the session logs your coding agent already writes to disk — Claude Code, Codex, OpenCode, Gemini, and more — and get failure-mode + efficiency findings. **Zero instrumentation.** A CLI *and* an SDK.
3
+ > Point `traces` at the session logs your coding agent already writes to disk: Claude Code, Codex, OpenCode, Gemini, and more. Get failure-mode and efficiency findings with zero instrumentation. A CLI *and* an SDK.
4
4
 
5
5
  ![traces analyzing a real Claude Code session](https://raw.githubusercontent.com/tangle-network/traces/main/docs/demo.gif)
6
6
 
@@ -8,7 +8,7 @@
8
8
  [![license](https://img.shields.io/npm/l/@tangle-network/traces.svg)](./LICENSE)
9
9
  [![node](https://img.shields.io/node/v/@tangle-network/traces.svg)](https://nodejs.org)
10
10
 
11
- It reads the transcripts your harness leaves on disk, reconstructs the run as spans, and reports where the agent got stuck, burned tokens, or stopped checking its own work — locally, with no API key and no cost for the deterministic pass.
11
+ It reads the transcripts your harness leaves on disk, reconstructs the run as spans, and reports where the agent got stuck, burned tokens, or stopped checking its own work. The deterministic pass runs locally, with no API key and no cost.
12
12
 
13
13
  ## Contents
14
14
 
@@ -46,16 +46,16 @@ Requires Node ≥ 22.
46
46
  traces analyze --harness claude-code --last 1
47
47
  traces improve --harness claude-code --last 5 --dir .traces/improvement
48
48
  traces watch --all
49
- traces stream --all --no-spans
49
+ traces stream --all --mode findings
50
50
  ```
51
51
 
52
- That's the command in the demo above. The **deterministic pass** — stuck loops, token growth, output decay, missing self-verification, tool monoculture — needs no API key and costs nothing.
52
+ That's the command in the demo above. The **deterministic pass** checks stuck loops, token growth, output decay, missing self-verification, and tool monoculture. It needs no API key and costs nothing.
53
53
 
54
54
  Add `--llm` for the **agentic analysts** (failure-mode / knowledge-gap / knowledge-poisoning / improvement); they call OpenAI and respect `--budget <usd>`.
55
55
 
56
- Every run also writes a **canonical OpenInference JSONL artifact**, so you can run external engines like [HALO](https://github.com/context-labs/halo) over it directly with `--analyzer halo` — see [External engines](#external-engines-bring-your-own). Analysis is never locked to one engine.
56
+ Every run also writes a **canonical OpenInference JSONL artifact**, so you can run external engines like [HALO](https://github.com/context-labs/halo) over it directly with `--analyzer halo`. See [External engines](#external-engines-bring-your-own). Analysis is never locked to one engine.
57
57
 
58
- `traces improve` is the reviewable action path. It writes typed artifacts — findings, recommendations, evidence rows, claims, report, and before/after replay metadata — so another agent, CI job, or hosted product can consume the result without scraping prose.
58
+ `traces improve` is the reviewable action path. It writes typed artifacts: findings, recommendations, evidence rows, claims, report, and before/after replay metadata. Another agent, CI job, or hosted product can consume the result without scraping prose.
59
59
 
60
60
  ## What it finds
61
61
 
@@ -64,10 +64,10 @@ The deterministic pass (free, no key) surfaces:
64
64
  | Finding | Meaning |
65
65
  |---|---|
66
66
  | **Stuck loops** | the same tool called N× with identical args and no state change |
67
- | **Monotonic input growth** | full history re-sent every step — context never compressed |
67
+ | **Monotonic input growth** | full history re-sent every step; context never compressed |
68
68
  | **Output-length decay** | planning/reasoning per step shrinking as context grows |
69
69
  | **No self-verification** | state-mutating actions never followed by an eval/inspect/check |
70
- | **Tool monoculture / retry / error rates** | the shape of how the agent actually spent its calls |
70
+ | **Tool mix / retry / error rates** | repeated, retried, and failed tool calls |
71
71
 
72
72
  `--llm` adds agentic analysts that read the conversation and cluster higher-order failure and improvement signals.
73
73
 
@@ -88,7 +88,7 @@ The deterministic pass (free, no key) surfaces:
88
88
  | `github-copilot` (`copilot`) | `~/.copilot/session-state/<id>/events.jsonl` | fixture |
89
89
  | `forge` (`forgecode`) | `/dump` JSON exports | fixture |
90
90
 
91
- Every adapter captures the full conversation — the **user's prompt** and the **assistant's response** text, plus tool calls/results and token usage. (`github-copilot` is the one exception: its log format carries no user prompt.) Factory stores token totals in `.settings.json`, not per turn. Forge reads `/dump` JSON exports (live SQLite is a follow-up). ACP-only bridges may not persist a local transcript.
91
+ Every adapter captures the full conversation: the **user's prompt** and the **assistant's response** text, plus tool calls/results and token usage. (`github-copilot` is the one exception: its log format carries no user prompt.) Factory stores token totals in `.settings.json`, not per turn. Forge reads `/dump` JSON exports (live SQLite is a follow-up). ACP-only bridges may not persist a local transcript.
92
92
 
93
93
  ## CLI reference
94
94
 
@@ -104,7 +104,8 @@ traces inspect session-index.json --out inspection-report.md
104
104
  traces evidence --harness codex --last 20 --out policy-evidence.jsonl
105
105
  traces export policy-evidence.jsonl --out spans.openinference.jsonl
106
106
  traces watch --all # live observer; loops + semantic findings
107
- traces stream --all --no-spans # live JSONL events for dashboards/visualizers
107
+ traces stream --all --mode findings # low-volume semantic feed
108
+ traces stream --all --mode agent # findings + deterministic report events
108
109
  traces stream spans.openinference.jsonl --format openinference --no-spans
109
110
  traces upload --since 1h --dry-run # redact + dedup + preview, no network
110
111
  traces upload --since 24h # upload last day to the Intelligence Platform
@@ -117,18 +118,19 @@ traces upload --since 24h # upload last day to the Inte
117
118
  | `--last <n>` | Most-recent N sessions |
118
119
  | `--session <path>` | One explicit session file |
119
120
  | `--cwd <dir>` | Filter by working directory |
120
- | `--since <t>` | `upload`: window — `30m`/`2h`/`7d` or ISO (default 24h); `analyze`: ISO cutoff |
121
+ | `--since <t>` | `upload`: window, `30m`/`2h`/`7d` or ISO (default 24h); `analyze`: ISO cutoff |
121
122
  | `--out <path>` | Write the report to a file |
122
123
  | `--dir <path>` | `improve`: write the full artifact pack to this directory |
123
124
  | `--otlp <path>` | OTLP artifact path (also evidence provenance / dry-run upload preview) |
124
125
  | `--format <kind>` | `export` / file `stream`: `auto`, `policy-evidence`, `sandbox-events`, or `openinference` |
125
126
  | `--llm` / `--budget <usd>` | Enable agentic analysts (needs `OPENAI_API_KEY`) / cap their spend |
126
- | `--config <path>` | `investigate` / `improve`: load BYO analysts, external analyzers, and proposal adapters |
127
+ | `--config <path>` | `investigate` / `improve` / `stream`: load BYO analysts, live analysts, external analyzers, and proposal adapters |
127
128
  | `--interval <s>` / `--window <m>` | `watch` / live `stream`: poll seconds (default 5) / active-session window minutes (default 30) |
128
129
  | `--min-loop <n>` | Identical repeated calls before flagging a loop (default 3) |
130
+ | `--mode <kind>` | `stream`: `visualizer` (spans + findings), `findings` (low-volume), or `agent` (findings + reports) |
129
131
  | `--replay` / `--once` | `stream`: scan once, then exit |
130
132
  | `--no-spans` / `--no-findings` | `stream`: suppress raw span rows / finding rows |
131
- | `--no-content` | `upload`: send metadata only — strip all prompt/response text |
133
+ | `--no-content` | `upload`: send metadata only; strip all prompt/response text |
132
134
  | `--dry-run` / `--yes` | `upload`: preview without sending / skip the confirm prompt |
133
135
 
134
136
  ## Live stream
@@ -141,13 +143,42 @@ It emits newline-delimited JSON events that a dashboard, art visualizer, local w
141
143
 
142
144
  ```bash
143
145
  traces stream --all
144
- traces stream --all --no-spans
146
+ traces stream --all --mode findings
147
+ traces stream --all --mode agent --config traces.config.mjs
145
148
  traces stream spans.openinference.jsonl --format openinference --no-spans
146
149
  ```
147
150
 
148
- The stream emits `session`, `span`, `analysis_batch`, `finding`, and `tick` events.
151
+ Live streaming emits `session`, `span`, `analysis_batch`, `finding`, and `tick` events; `--mode agent` also emits `report` events.
149
152
  The semantic findings currently cover repeated failing commands, verification churn without code/config changes, completion claims without later verification, and high tool-error rates.
150
- Use `--no-spans` when you want the low-volume meaning layer; keep spans on for real-time visualizers that need motion, timing, and tool-call texture.
153
+ Use `--mode findings` when you want the low-volume meaning layer; keep `visualizer` for real-time views that need motion, timing, and tool-call texture.
154
+ Use `--mode agent` when another agent needs deterministic loop/tool-use reports alongside the findings.
155
+
156
+ Custom online analysts use the same config file as `investigate` and `improve`:
157
+
158
+ ```js
159
+ export default {
160
+ liveAnalysts: [{
161
+ id: 'my-live-rule',
162
+ analyze(context) {
163
+ return context.actions.some((action) => action.kind === 'claim') ? [{
164
+ schemaVersion: 1,
165
+ kind: 'traces.live_finding',
166
+ id: `live.my-live-rule.${context.session.sessionId}`,
167
+ ruleId: 'my-live-rule',
168
+ fingerprint: `my-live-rule.${context.session.sessionId}`,
169
+ severity: 'info',
170
+ title: 'Completion claim seen',
171
+ claim: 'A claim-like assistant message appeared in the live trace.',
172
+ action: 'Require the next stream batch to include a verification action.',
173
+ check: 'A later finding or batch should show a test/build/typecheck action.',
174
+ evidence: [{ kind: 'metric', label: 'actions', value: String(context.actions.length) }],
175
+ session: context.session,
176
+ observedAt: context.generatedAt,
177
+ }] : []
178
+ },
179
+ }],
180
+ }
181
+ ```
151
182
 
152
183
  ## Improvement engine
153
184
 
@@ -177,6 +208,7 @@ traces improve --last 5 --config examples/improvement-config.mjs --dir .traces/i
177
208
  The config can export:
178
209
 
179
210
  - `analysts`: deterministic or LLM analysts that implement the `agent-eval` `Analyst` contract
211
+ - `liveAnalysts`: deterministic online analysts that implement the `TraceLiveAnalyst` contract for `traces stream`
180
212
  - `registry`: a prebuilt `AnalystRegistry`
181
213
  - `externalAnalyzers`: HALO or any command/model adapter that reads the OTLP artifact
182
214
  - `improvementAdapter`: a proposal writer that maps recommendations to patches, profile edits, prompts, or validation commands
@@ -224,7 +256,7 @@ That boundary matters. `agent-lab` campaign `cells.jsonl` says "arm X beat arm Y
224
256
 
225
257
  ### Export existing evidence/events to OpenInference
226
258
 
227
- If you already have compact evidence or Sandbox/OpenCode event captures on disk, convert them to the same OpenInference JSONL shape that `traces analyze --analyzer halo` uses:
259
+ If you already have compact evidence or event captures on disk, convert them to the same OpenInference JSONL shape that `traces analyze --analyzer halo` uses:
228
260
 
229
261
  ```bash
230
262
  traces export policy-evidence.jsonl --out spans.openinference.jsonl
@@ -235,7 +267,7 @@ halo spans.openinference.jsonl --prompt "Analyze this trace slice" --max-turns 1
235
267
  `traces export` accepts:
236
268
 
237
269
  - compact `traces.policy_evidence.session` JSONL from `traces evidence`
238
- - Sandbox/OpenCode JSON arrays with `start`, `raw`, `result`, `done`, and `error` events
270
+ - JSON arrays with `start`, `raw`, `result`, `done`, and `error` events
239
271
  - existing OpenInference JSONL, rewritten through the local redaction path
240
272
 
241
273
  Run `traces export --help` for the full command reference.
@@ -245,28 +277,28 @@ Run `traces export --help` for the full command reference.
245
277
  `upload` **redacts locally before anything leaves the machine**, dedups against already-uploaded sessions, and tags each with metadata (harness, cwd, git branch, host).
246
278
 
247
279
  ```bash
248
- traces upload --since 24h --dry-run # see exactly what would be sent — no network
249
- traces upload --since 24h --no-content # send metadata only — drop all prompt/response text
280
+ traces upload --since 24h --dry-run # see exactly what would be sent; no network
281
+ traces upload --since 24h --no-content # send metadata only; drop all prompt/response text
250
282
  traces upload --since 24h # send it
251
283
  ```
252
284
 
253
285
  It needs `TANGLE_INGEST_URL` (or `TANGLE_ORCHESTRATOR_URL`), `TANGLE_INGEST_API_KEY` (or `TANGLE_API_KEY`), and `TANGLE_TENANT_ID`. Without them, `--dry-run` still works fully.
254
286
 
255
- ### Redaction scope — read this before uploading prose
287
+ ### Redaction scope: read this before uploading prose
256
288
 
257
289
  Redaction is **best-effort regex** for *structured* secrets and credentials: API keys, GitHub/cloud tokens, JWTs, bearer headers, private-key blocks, `KEY=secret` assignments, and credentials embedded in URLs. It runs over every span attribute, including the captured prompt/response text.
258
290
 
259
- It does **not** catch free-form PII — names, postal addresses, phone numbers in prose — which needs a context-aware model. Three postures, strongest first:
291
+ It does **not** catch free-form PII such as names, postal addresses, or phone numbers in prose. Those need a context-aware model. Three postures, strongest first:
260
292
 
261
- 1. **`--no-content`** — upload metadata only (tool calls, tokens, timing, loop signal); no prose leaves the machine.
293
+ 1. **`--no-content`**: upload metadata only (tool calls, tokens, timing, loop signal); no prose leaves the machine.
262
294
  2. Run an ML PII scrubber (e.g. [`openai/privacy-filter`](https://github.com/openai/privacy-filter)) on the platform ingest side as defense-in-depth.
263
- 3. Default — regex redaction of structured secrets.
295
+ 3. Default: regex redaction of structured secrets.
264
296
 
265
297
  Always `--dry-run` first to see exactly what would be sent.
266
298
 
267
299
  ## External engines (bring your own)
268
300
 
269
- `traces` hosts analysis engines and PII scrubbers it does **not** bundle — you install the tool, `traces` drives it over a thin command adapter. Same pattern for any future engine or model.
301
+ `traces` hosts analysis engines and PII scrubbers it does **not** bundle. You install the tool; `traces` drives it over a thin command adapter. Same pattern for any future engine or model.
270
302
 
271
303
  **Analyzers** run over the emitted OTLP artifact as peers to the built-in analysts:
272
304
 
@@ -276,7 +308,7 @@ traces analyze --last 1 --analyzer halo --analyzer-prompt "find token waste"
276
308
  traces analyze --last 1 --analyzer halo --analyzer my-engine # repeatable
277
309
  ```
278
310
 
279
- Our OTLP artifact is **canonical OpenInference** (top-level `kind`, `resource`, `scope`), so HALO reads it directly — no conversion. HALO runs its *own* LLM (OpenAI client — set `OPENAI_BASE_URL` / `OPENAI_API_KEY`, or use HALO's provider); `--model` is forwarded to it. traces supplies the trace and drives the CLI; it doesn't pay for or configure HALO's model.
311
+ Our OTLP artifact is **canonical OpenInference** (top-level `kind`, `resource`, `scope`), so HALO reads it directly with no conversion. HALO runs its *own* LLM. Set `OPENAI_BASE_URL` / `OPENAI_API_KEY`, or use HALO's provider; `--model` is forwarded to it. `traces` supplies the trace and drives the CLI; it does not pay for or configure HALO's model.
280
312
 
281
313
  **Redactors** scrub prompt/response prose with an external PII model (catching names/addresses the regex pass can't), running *after* the built-in redaction:
282
314
 
@@ -287,7 +319,7 @@ traces upload --since 24h --dry-run --redactor "my-pii-scrubber"
287
319
 
288
320
  In the SDK these are the `ExternalAnalyzer` and `Redactor` interfaces (`haloAnalyzer`, `commandAnalyzer`, `commandRedactor`, `applyRedactor`, `runExternalAnalyzers`). See [`examples/external-engines.ts`](./examples/external-engines.ts).
289
321
 
290
- > For the built-in agentic analysts (`--llm`), set `OPENAI_API_KEY` — or point at any OpenAI-compatible gateway with `OPENAI_BASE_URL` (e.g. an internal router) to use a non-OpenAI key.
322
+ > For the built-in agentic analysts (`--llm`), set `OPENAI_API_KEY`, or point at any OpenAI-compatible gateway with `OPENAI_BASE_URL` (e.g. an internal router) to use a non-OpenAI key.
291
323
 
292
324
  ## Release automation
293
325
 
@@ -307,7 +339,7 @@ The CLI is a thin consumer of these exports.
307
339
 
308
340
  | Export | Signature | Use |
309
341
  |---|---|---|
310
- | `analyzeSpans` | `(spans, { registry?, ai?, budgetUsd? }) → AnalyzeResult` | run analysts — built-in, or **your own** via `registry` |
342
+ | `analyzeSpans` | `(spans, { registry?, ai?, budgetUsd? }) → AnalyzeResult` | run built-in analysts, or **your own** via `registry` |
311
343
  | `runTraceInvestigation` | `(TraceInvestigationOptions) → TraceInvestigationResult` | typed findings, recommendations, claims, external analyzer output, and report |
312
344
  | `runTraceImprovementLoop` | `(TraceImprovementOptions) → TraceImprovementResult` | writes the full improvement artifact pack and optional proposal output |
313
345
  | `buildTraceFindingPacket` | `({ findings }) → TraceFindingPacket` | turn any `AnalystFinding[]` into recommendations, claims, and a report |
@@ -317,6 +349,8 @@ The CLI is a thin consumer of these exports.
317
349
  | `streamSessions` | `(TraceStreamOptions) → Promise<void>` | live JSONL-ready event stream over active sessions |
318
350
  | `traceStreamEventsFromSpans` | `(spans, opts?) → TraceStreamEvent[]` | replay an existing span list as stream events |
319
351
  | `analyzeLiveBatch` | `(spans, opts?) → TraceLiveBatch` | compute semantic online findings for one batch |
352
+ | `classifyLiveActions` | `(spans) → TraceLiveAction[]` | classify spans once as read/edit/verify/claim/tool/other |
353
+ | `defaultTraceLiveAnalysts` | `TraceLiveAnalyst[]` | the built-in online analysts; extend or replace them |
320
354
  | `collectSessionIndex` | `(ScanOptions) → TraceSessionIndex` | scan sessions and return a reusable JSON-ready catalog |
321
355
  | `inspectSessionIndex` | `(TraceSessionIndex) → TraceInspectionReport` | rank improvement findings from an index without rescanning sessions |
322
356
  | `buildPolicyEvidenceRecord` | `(ref, spans, opts?) → PolicyEvidenceRecord` | summarize one session for downstream policy mining |
@@ -359,7 +393,7 @@ Runnable, in [`examples/`](./examples):
359
393
  |---|---|
360
394
  | [`observe-and-alert.ts`](./examples/observe-and-alert.ts) | tail live sessions and alert on stuck loops |
361
395
  | [`custom-analyst.ts`](./examples/custom-analyst.ts) | register and run your own analyst |
362
- | [`improvement-config.mjs`](./examples/improvement-config.mjs) | plug in BYO analysts and proposal generation for `traces improve` |
396
+ | [`improvement-config.mjs`](./examples/improvement-config.mjs) | plug in BYO analysts for `traces stream` / `traces improve` |
363
397
  | [`custom-backend.ts`](./examples/custom-backend.ts) | redact + dedup + upload to your own sink |
364
398
  | [`register-harness.ts`](./examples/register-harness.ts) | add a new harness by implementing `HarnessTraceAdapter` |
365
399
  | [`external-engines.ts`](./examples/external-engines.ts) | drive HALO + an external PII scrubber you install yourself |
@@ -371,5 +405,5 @@ pnpm install
371
405
  pnpm dev analyze --harness claude-code --last 1 # run from source via tsx
372
406
  pnpm test
373
407
  pnpm typecheck
374
- pnpm build # → dist/index.js (SDK) + dist/cli.js (bin) + .d.ts
408
+ pnpm build # dist/index.js (SDK) + dist/cli.js (bin) + .d.ts
375
409
  ```