> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voight.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> What shipped, when.

SDK releases follow [semver](https://semver.org/). Backend and dashboard ship continuously from `main` without version tags.

## Week of 2026-06-08 — Bitfrost (Python) 0.1.0

Python joins the family. [`bitfrost`](/python/bitfrost) is a drop-in OpenTelemetry exporter for Python LLM apps — the Python counterpart to `@voightxyz/vercel-ai`. Same backend, same dashboard, different runtime; events from both land side-by-side under the same agent.

### New

* **`bitfrost` 0.1.0** — `pip install bitfrost`. One line (`bitfrost.quickstart()`) auto-detects and instruments openai / anthropic / litellm / smolagents. Built on the OpenTelemetry GenAI semantic conventions (v1.27 and v1.32+), so it works with the instrumentation libraries you already use. [Get started →](/python/bitfrost)
* **Standalone-first.** Capture to your terminal, a JSONL file, or SQLite with zero network calls — Voight is one optional backend, never a requirement. Ships five backends, four auto-instrument helpers, a rich CLI, an interactive TUI, and an offline local web dashboard (`bitfrost serve`).
* **Private by default.** Three privacy levels with in-process PII scrubbing (12 patterns + credit-card Luhn) applied before any event leaves the process.

<Note>
  Bitfrost is open source (MIT) on [GitHub](https://github.com/Voightxyz/bitfrost) and works entirely on its own. Point it at Voight only when you want hosted dashboards and per-user spend.
</Note>

## Week of 2026-05-18 — Vercel AI SDK support, install wizard, GLM provider

A short recap of what shipped this week. Per-package version notes live in the sections below.

### New

* **`@voightxyz/vercel-ai` 0.1.0** — first stable release of the [Vercel AI SDK exporter](/ai-apps/vercel-ai). Register one OpenTelemetry exporter next to `@vercel/otel` and every `streamText` / `generateText` / `streamObject` / `generateObject` call lands in your dashboard with accurate token counts, tool calls, and per-user attribution. Validated against the `vercel/ai-chatbot` reference app.
* **`@voightxyz/sdk init` now detects the Vercel AI SDK** — running `npx -y @voightxyz/sdk init` in a project that uses `ai` writes an `instrumentation.ts` that wires up the exporter automatically. Direct-wrapper projects (OpenAI / Anthropic only) get the same files as before. See the [install wizard guide](/ai-apps/wizard).
* **GLM (Z.ai / Zhipu) provider page** — new [GLM provider doc](/ai-apps/glm) walks through using GLM models behind the OpenAI wrapper, with pricing and routing notes.

### Updates

* **One-line per-user attribution** — both `@voightxyz/openai` and `@voightxyz/anthropic` now accept a `tags` map on `withTrace`. Pass `{ userId, plan, ... }` once at the request boundary and every LLM call inside the block is stamped automatically. Lights up the dashboard's [Users sub-tab](/ai-apps/overview#users-sub-tab) and [per-user spend](/concepts/per-user-spend) view.
* **Request-boundary trace grouping** — `withTrace(fn, { routeTag })` and `log(message, extra?)` are now exported from both App SDKs. Group every LLM call from one request under a single trace card, interleaved with your own log lines. Mixing OpenAI and Anthropic calls in the same trace works without extra setup.
* **`@voightxyz/anthropic` peer range loosened to `>=0.27.0`** — projects pinning older Anthropic SDK releases no longer hit `ERESOLVE` on install. Runtime verified against `0.29.2` and `0.96.0`.

### Fixes

* **Vercel AI exporter token accuracy** — outer wrapper spans are filtered out so token counts match the underlying provider's billing, and `durationMs` is rounded to an integer.

<Note>
  Already on the OpenAI or Anthropic wrapper? Adding per-user attribution is a one-line change — see the [per-user spend guide](/concepts/per-user-spend).
</Note>

Four SDKs ship from separate packages:

* **`@voightxyz/sdk`** — coding-agent hooks + library mode (autonomous bots)
* **`@voightxyz/openai`** — OpenAI Node SDK wrapper for production apps
* **`@voightxyz/anthropic`** — Anthropic Node SDK wrapper for production apps
* **`@voightxyz/vercel-ai`** — OpenTelemetry SpanExporter for the Vercel AI SDK

## `@voightxyz/vercel-ai` changelog

### 0.1.1 — 2026-05-22

**Dedup filter for wrapper-emitted spans.**

When [`@voightxyz/openai`](https://www.npmjs.com/package/@voightxyz/openai) or [`@voightxyz/anthropic`](https://www.npmjs.com/package/@voightxyz/anthropic) is wrapped with `otel: true`, every captured call would otherwise land twice in the Voight backend — once via the wrapper's direct POST, once via this exporter. 0.1.1 teaches `VoightExporter.export()` to recognise the `voight.source: 'wrapper'` attribute the wrappers stamp on those spans, and skip them cleanly. Other OTel exporters in the same process (Langfuse, Datadog, Sentry) still see the spans — the dedup is scoped to the Voight-to-Voight loop.

Spans without that marker (the canonical `streamText` / `generateText` / `streamObject` / `generateObject` spans the Vercel AI SDK emits) are unaffected.

### 0.1.0 — 2026-05-21

**First stable release.**

`@voightxyz/vercel-ai` is an OpenTelemetry `SpanExporter` for the [Vercel AI SDK](https://sdk.vercel.ai). Register it next to `@vercel/otel`, flip `experimental_telemetry: { isEnabled: true }` on your `streamText` / `generateText` / `streamObject` / `generateObject` calls, and every call lands in your Voight dashboard.

```ts theme={null}
import { registerOTel } from '@vercel/otel'
import { VoightExporter } from '@voightxyz/vercel-ai'

registerOTel({
  serviceName: 'my-app',
  traceExporter: new VoightExporter({ agent: 'production-chat-api' }),
})
```

**What lands today:**

* `streamText` / `generateText` / `streamObject` / `generateObject` capture (one event per LLM call — outer wrappers filtered out so token counts stay accurate)
* OpenAI + Anthropic provider attribution (via `gen_ai.system` / `ai.model.provider`)
* Tool calls (normalised to `{id, name, arguments}` JSON-string), token counts (input / output / cache\_read / cache\_creation), finish reason, streaming flag, sessionId
* **Per-user attribution** via `experimental_telemetry.metadata` — passing `{ metadata: { userId, plan, ... } }` activates the dashboard Users sub-tab + per-tag filter pills automatically
* Three privacy levels (`'minimal'` / `'standard'` / `'full'`) sharing the same 12-pattern PII catalogue as the other wrappers
* Coexists with other observability tools via OTel's `MultiSpanProcessor`

Validated end-to-end against the [`vercel/ai-chatbot`](https://github.com/vercel/ai-chatbot) reference app. Full setup at [ai-apps/vercel-ai](/ai-apps/vercel-ai).

## `@voightxyz/openai` changelog

### 0.1.7 — 2026-05-22

**`{ otel: true }` opt-in — OpenTelemetry side-channel.**

When set, every captured call is *also* emitted as an OpenTelemetry span with `gen_ai.*` semantic-convention attributes (plus the parallel `ai.*` namespace for Vercel cross-compatibility). The wrapper picks up whichever `TracerProvider` is registered in the host process, so you can wire it inside an OTel-mandated stack (Langfuse, Phoenix, Datadog, Sentry, [`@voightxyz/vercel-ai`](/ai-apps/vercel-ai)) without losing the direct ingestion to `api.voight.xyz`.

```ts theme={null}
const client = wrapOpenAI(new OpenAI(), { agent: 'my-app', otel: true })
```

Span name: `voight.openai.chat` (or `voight.openai.responses`). Each span carries `voight.source: 'wrapper'` so `@voightxyz/vercel-ai` ≥ 0.1.1 deduplicates them automatically.

`@opentelemetry/api` is now an **optional** peer dependency. Default `otel: false` ships byte-identical behaviour to 0.1.6 — no extra install, no runtime cost.

### 0.1.6 — 2026-05-17

**`withTrace({ tags })` — per-user / per-tenant attribution.**

`withTrace` now accepts a `tags` map alongside `routeTag`. Every wrapped LLM call inside the block gets stamped with `metadata.tags` automatically via `AsyncLocalStorage`. This is the one-line code change that lights up the dashboard's [Users sub-tab](/ai-apps/overview#users-sub-tab) and powers [per-user spend](/concepts/per-user-spend) attribution.

```ts theme={null}
await withTrace(
  async () => { /* handler */ },
  { tags: { userId: req.user.id, plan: req.user.plan } },
)
```

Tags propagate to both Chat Completions and Responses events. Missing or empty tags are a no-op — no behaviour change for callers not using the feature.

### 0.1.5 — 2026-05-17

**`withTrace` + `log` — request-boundary trace grouping.**

New exports:

* `withTrace(fn, { routeTag })` opens a logical trace; every wrapped LLM call inside the block is grouped under one trace card in the dashboard.
* `log(message, extra?)` emits a free-form event inside the current trace — interleaved with LLM calls in the timeline.

Backed by Node's `AsyncLocalStorage` — no signature threading, no middleware required. Mixes cleanly with `@voightxyz/anthropic` (same backing store across both packages).

### 0.1.0 — 2026-05-15

**Initial release.**

OpenAI Node SDK wrapper. Captures:

* Chat Completions (`client.chat.completions.create`) — non-streaming + streaming, tool calling
* Responses API (`client.responses.create`) — non-streaming + streaming, function calling, reasoning models
* Token breakdown (input / output / cache reads / reasoning)
* Tool calls (full array per event)
* Latency, finish reason, error capture

Three privacy levels (Minimal / Standard / Full) with local PII scrubbing on Standard.

## `@voightxyz/anthropic` changelog

### 0.1.8 — 2026-05-22

**`{ otel: true }` opt-in — OpenTelemetry side-channel.**

Mirror of [`@voightxyz/openai@0.1.7`](#017--2026-05-22) — same flag, same `gen_ai.*` + `ai.*` attribute shape, same `voight.source: 'wrapper'` dedup marker, same optional peer on `@opentelemetry/api`. Span name: `voight.anthropic.messages`. `gen_ai.system` resolves to `'anthropic'`.

Default `otel: false` ships byte-identical behaviour to 0.1.7.

### 0.1.7 — 2026-05-17

**Loosen `@anthropic-ai/sdk` peer-dependency from `>=0.30.0` to `>=0.27.0`.**

Real-world projects on older SDK versions hit `ERESOLVE` on install (Anthropic's own `customer-support-agent` quickstart pins `^0.27.1`; `financial-data-analyst` pinned `^0.29.0` — both rejected `0.1.6`). The `0.30.0` floor was overly conservative — the wrapper consumes the SDK purely structurally (no type imports, only runtime field reads with defensive fallbacks), so older releases work fine.

Runtime verified against `@anthropic-ai/sdk` 0.29.2 and 0.96.0. 92/92 tests still green. No code changes — peer-dependency metadata only.

### 0.1.6 — 2026-05-17

**`withTrace({ tags })` — per-user / per-tenant attribution.**

Mirror of `@voightxyz/openai` 0.1.6. Every wrapped `messages.create` call inside a `withTrace` block gets `metadata.tags` stamped automatically. Powers the dashboard's [Users sub-tab](/ai-apps/overview#users-sub-tab) and [per-user spend](/concepts/per-user-spend) attribution.

```ts theme={null}
await withTrace(
  async () => { /* handler */ },
  { tags: { userId: req.user.id, plan: req.user.plan } },
)
```

### 0.1.5 — 2026-05-17

**`withTrace` + `log` — request-boundary trace grouping.**

Mirror of `@voightxyz/openai` 0.1.5. Same async-context store under the hood — import `withTrace` from either package; mixing providers in one trace works without setup.

### 0.1.0 — 2026-05-15

**Initial release.**

Anthropic Node SDK wrapper. Captures:

* `messages.create` — non-streaming + streaming, tool use
* Token breakdown (input / output / cache reads / cache creations)
* Path-A cache pricing (1.25× creation, 0.10× read applied server-side)
* Tool calls (flattened to `{ id, name, arguments }` matching the OpenAI wrapper)
* Latency, stop reason, error capture

Three privacy levels (Minimal / Standard / Full) with local PII scrubbing on Standard.

## `@voightxyz/sdk` changelog

### 0.6.5 — 2026-05-21

**`init` wizard now detects the Vercel AI SDK.**

If your `package.json` lists `ai` (Vercel AI SDK), the wizard takes a new third path: instead of writing `src/lib/voight.ts` with wrapped clients, it writes an `instrumentation.ts` that registers [`@voightxyz/vercel-ai`](/ai-apps/vercel-ai) with `@vercel/otel`. The Vercel AI SDK emits OpenTelemetry spans natively, so every `streamText` / `generateText` / `streamObject` / `generateObject` call carrying `experimental_telemetry: { isEnabled: true }` lands in your Voight dashboard with the same shape as direct-wrapper events.

Mixed projects (both `ai` and a direct provider in deps) take the Vercel path with an explicit message — the OTel exporter covers every underlying provider via `gen_ai.*` semconv normalisation.

Strictly additive: zero edits to the `setup` flow (Claude Code / Cursor / Codex hooks) or to the direct-wrapper path. A project that has only `openai` or `@anthropic-ai/sdk` (no `ai`) gets exactly the same files the 0.6.4 wizard produced — verified byte-for-byte via the registry-level smoke test before `@latest` promotion.

Same install command (`npx -y @voightxyz/sdk init`), same prompts (privacy + key + agent), framework-aware usage snippet, pm-tailored install command (`pnpm add @voightxyz/vercel-ai @vercel/otel` for the Vercel path).

### 0.6.4 — 2026-05-17

**New `init` sub-command — scaffold Voight into a production app with one wizard.**

For projects that already use the OpenAI or Anthropic Node SDK in production, `init` automates the install:

```bash theme={null}
cd your-app
npx -y @voightxyz/sdk init
```

The wizard:

1. Reads `package.json` and detects `openai` and/or `@anthropic-ai/sdk` already in your deps. Aborts cleanly if neither is present.
2. Detects your package manager (pnpm / yarn / bun / npm) and your framework (Next.js or vanilla) to tailor the install command + usage snippet at the end.
3. Prompts for privacy level (Standard recommended for customer-facing apps), Voight API key, and agent name.
4. Validates the key against `api.voight.xyz` before writing anything — typo'd keys get caught now instead of in production.
5. Generates `src/lib/voight.ts` with the wrapped clients for the providers it detected, plus a header comment explaining how to adjust if your provider keys come from AWS Secrets Manager / Vault / Doppler instead of env vars.
6. Appends `VOIGHT_KEY` to `.env.local`. Provider keys (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) are never asked for — they belong to your app, the Voight wrapper never sees them.
7. Prints the right install command for your package manager + a usage snippet (Next.js Route Handler or Express, depending on what's in your deps).

### Safety guarantees

`init` lives in a new file `src/init.ts` with **zero edits to `setup.ts`, `hook.ts`, or any other module**. It never touches `~/.claude`, `~/.cursor`, or `~/.codex` — only writes inside `process.cwd()`. Users of `setup` get byte-identical behaviour to 0.6.3; 256 tests green (was 214 + 42 new for `init`).

If you'd rather wire things up manually (no wizard), the package pages for [OpenAI](/ai-apps/openai) and [Anthropic](/ai-apps/anthropic) walk through the same install in three commands.

### 0.6.3 — 2026-05-14

**Fix: Codex plugin install lands in the right cache dir + valid auth enum.**

Two last-mile Codex setup bugs. The plugin now installs into the location Codex actually loads from, and the authentication value matches Codex's accepted enum so the wrapper no longer rejects it at startup.

### 0.6.2 — 2026-05-14

**Fix: install the SDK locally so hooks fire inside the Codex sandbox.**

Codex runs hooks inside a sandboxed environment that can't reach globally-installed packages. Setup now drops the SDK into the project so the hook script resolves correctly on first run.

### 0.6.1 — 2026-05-14

**Fix: `VOIGHT_SOURCE` disambiguates Codex from Claude Code.**

Both adapters share a hook entry point. The wrapper now sets `VOIGHT_SOURCE` so events route through the correct mapper instead of being misattributed.

### 0.6.0 — 2026-05-14

**Codex support (verified target).**

Voight now wires into [Codex](/quickstart) the same way it wires into Claude Code and Cursor — one `setup` command drops a local marketplace plugin that registers the hooks. Events show up in the live timeline with the same shape as other targets. See the [quickstart](/quickstart) for the install steps.

### 0.5.2 — 2026-05-14

**Fix: route Cursor response and thought text through metadata.**

Cursor's response and reasoning fields are now carried in `metadata` instead of top-level event fields. The dashboard masks them by default with the same eye-toggle reveal used for Claude Code transcripts.

### 0.5.1 — 2026-05-14

**Fix: normalise Cursor `model: 'default'` to `cursor-auto`.**

Cursor reports `default` for its auto-routing mode, which doesn't tell you which model actually ran the turn. The SDK now rewrites it to `cursor-auto` so the dashboard's model column is honest about what happened.

### 0.5.0 — 2026-05-14

**Cursor support + framework-agnostic setup.**

Voight is no longer Claude-Code-only. Highlights:

* **Cursor adapter** — `setup` wires Cursor's `hooks.json` + wrapper script, captures 5 extended hook events, and ships prompts and outcomes in the reasoning payload so the timeline renders Cursor turns end-to-end
* **Auto-detect the coding agent** — run `setup` with no `--target` flag and the CLI picks Claude Code, Cursor, or Codex based on your environment
* **`frameworkName` helper** — installer and runtime messages now reflect whichever agent you're wiring in
* **`traceId` lifted into metadata** — every event carries the trace ID the dashboard groups by, regardless of source
* **Apache-2.0** — the SDK is now Apache-2.0 licensed (was MIT). README rewritten to drop Claude-only framing

See the [quickstart](/quickstart) for the new multi-target flow and [events](/concepts/events) for the shared payload shape.

### 0.4.2 — 2026-05-10

**Fix: explicit `--privacy=N` example in non-TTY welcome menu.**

After 0.4.1 shipped, an alpha tester's friend tried to install via Claude Code chat and the AI agent reading the wizard output didn't know how to chain commands. The welcome menu now includes:

```
Pick a number (1, 2, or 3) or a name (minimal / standard / full),
then re-run with that choice as a flag. For example, to pick Standard:

  npx -y @voightxyz/sdk setup --privacy=2
```

Six lines of code, unblocks the AI-agent install flow.

### 0.4.1 — 2026-05-08

**3-step progressive flow for non-TTY (Claude Code chat).**

The 0.4.0 wizard relied on readline. Inside Claude Code chat (or any non-TTY shell) it silently defaulted to `standard` privacy, never showed the welcome menu, and gave users no way to choose. 0.4.1 reshapes the non-TTY path:

* Step 1 — print welcome + privacy menu, exit
* Step 2 — accept `--privacy=N`, print API key instructions, exit
* Step 3 — accept both `--privacy` and `--key`, write settings.json, show done message

Each step prints clear instructions. AI agents in chat can chain them automatically. Also dropped the "Restart Claude Code" line from the done message — Claude Code hot-reloads `settings.json` on most modern versions.

### 0.4.0 — 2026-05-08

**3-level privacy capture + local PII scrubbing.**

The biggest release since the SDK was first published. New capabilities:

* **Three privacy levels** picked at install (Minimal / Standard / Full), via the setup wizard or `VOIGHT_PRIVACY` env var
* **`scrubPii()`** — 12 PII patterns + Luhn-validated credit cards, run on every string in every event under Standard mode, before the SDK transmits anything
* **`applyPrivacy(payload, level)`** — single integration point in `hook.ts`, allowlist-based for Minimal (forward-compat), deep-scrub for Standard
* **Per-event `metadata.privacyLevel` stamp** — every event ships with its level chip so the dashboard can audit retroactively
* **77 new unit tests** (61 → 138 SDK suite)
* **E2E verified** against the actual subprocess flow + wire capture, not just unit mocks

See [privacy overview](/privacy/overview) and [PII patterns](/privacy/pii-patterns).

### 0.3.10 — 2026-05-06

**Fix: match real Claude Code rejection phrasing in denial detector.**

The 0.3.9 denial-detection patterns were synthetic. 0.3.10 corrects them against captured rejection logs. **Architectural caveat**: PostToolUse doesn't fire on user\_rejected — that path is dead code in production. We're sitting on this until we can capture the right hook flow.

### 0.3.9 — 2026-05-06

**Permission-denial classification (5 patterns).**

Added a denial classifier that promotes failed tool calls to a distinct `denial` type when the failure shape matches a known pattern (user rejected, settings blocked, sandbox denied, requires approval, hook blocked). The dashboard renders these with a `DENIED` badge separate from real runtime errors.

**Post-mortem**: shipped against invented patterns. See architectural caveat above.

### 0.3.8 — 2026-05-05

**Git context capture.**

Every event now carries `metadata.git = { branch, sha, shortSha, remote, dirty }` when running inside a git repo. Cached 30s per cwd to avoid spawning git on every event. Captures the exact code state that produced the trace.

### 0.3.7 — 2026-05-05

**`ScheduleWakeup` recognition.**

When the agent calls `ScheduleWakeup`, the SDK records the parameters. The next `UserPromptSubmit` that matches gets tagged `promptSource: 'system'` so the dashboard can distinguish autonomous loop ticks from real user prompts. Renders as a `SYSTEM` badge in the timeline.

### 0.3.5 — 2026-05-05

**Agent response capture.**

The Stop hook now reads the local transcript backward to find the agent's final text + stop reason + last thinking block. Surfaces them in the dashboard's event detail panel (masked by default, eye toggle to reveal).

### 0.3.4 — 2026-05-04

**Marker file (`.voight-agent-id`) for rename-proof identity.**

Server returns the agent's CUID on every event response. SDK writes it to `<cwd>/.voight-agent-id`. Future events match by primary key — rename-proof, folder-rename-proof.

### 0.3.3 — 2026-05-04

**Explicit `metadata.tokensBreakdown` for exact pricing.**

The flat `tokens.input` field conflates `inputBase`, `cacheCreation`, and `cacheRead` at the full rate. New breakdown field gives the backend exact prices (cache\_read at 0.10×, cache\_creation at 1.25×, input at 1.00×).

### 0.3.2 — 2026-05-04

**ESM fs imports (fix silent fail on transcripts >4MB).**

### 0.3.1 — 2026-05-03

**Lenient transcript matcher** (handles edge cases in attribution).

### 0.3.0 — 2026-05-03

**Transcript-based token capture.**

The SDK now walks the local transcript JSONL on every PostToolUse, finds the assistant message that initiated the current tool, and pulls real token usage. Dedup via assistant message UUID — 1 message → N tools attributes once.

## Earlier versions

0.1.x and 0.2.x were the initial integration drafts. Not documented here — start at 0.3.0.

## Stay updated

* npm: [`@voightxyz/sdk`](https://www.npmjs.com/package/@voightxyz/sdk) · [`@voightxyz/openai`](https://www.npmjs.com/package/@voightxyz/openai) · [`@voightxyz/anthropic`](https://www.npmjs.com/package/@voightxyz/anthropic)
* GitHub: [`voightxyz/voight-sdk`](https://github.com/Voightxyz/voight-sdk) · [`voightxyz/voight-openai`](https://github.com/Voightxyz/voight-openai) · [`voightxyz/voight-anthropic`](https://github.com/Voightxyz/voight-anthropic) (releases tagged)
* Twitter: [@voightxyz](https://x.com/voightxyz)
