Docs

Install (one machine, two minutes)

Grab an ingest key from Settings → Ingest keys, then:

npx tokenoscopy init
# paste your tok_… key when prompted

That writes hook entries to ~/.claude/settings.json (a backup of the previous file is kept, and re-running init is idempotent — your other hooks are never touched):

  • Live hooks — Claude Code POSTs session/tool events to Tokenoscopy directly. No local daemon, nothing in your request path.
  • Transcript flush — on Stop/SessionEnd, tokenoscopy flush parses the local transcript, computes spend, redacts, and uploads. This is the source of truth; a missed live hook loses nothing.
  • Budget guard — a PreToolUse hook asks Tokenoscopy before Bash/MCP calls. See fail-open semantics.

Verify any time with npx tokenoscopy doctor. For CI checkouts use init --project (writes ./.claude/settings.json) with TOKENOSCOPY_KEY in the environment.

Seats and keys are not the same dollar

Tokenoscopy records both, and never adds them together. Each time a session flushes, the machine reports how it pays for tokens: metered (an API key, a Console-billed OAuth account, Bedrock or Vertex) or seat (a Pro/Max subscription). Note that signing in with OAuth does not imply a subscription — Claude Code also signs into Console accounts that bill per token, so the detector checks for an actual subscription rather than assuming.

On the metered lane, the dollar figure is real money estimated at list price, and a budget cap is literally a dollar cap. On the seat lane, the same figure is what the work would have cost at API rates — nobody is invoiced for it. What actually runs out there is your plan's rolling usage limit, which is why a retry loop on a seat costs an afternoon rather than an invoice.

Every week-over-week comparison, headline number, and alert is scoped to one lane. If a machine can't tell (no readable config), it lands in unclassified and says so instead of guessing. A session that has only sent live hooks and hasn't flushed yet is also unclassified — Claude Code posts those hooks directly, with no Tokenoscopy process in the loop to read the local config. It resolves on the first flush, which is the end of the current turn.

The alert that fires before the bill

A budget alert tells you the money is gone. Tokenoscopy also watches for the thing that spends it next: a session where the agent repeated an identical call three or more times and edited code that runs unattended — a GitHub workflow, a cron directory, a scheduler file, or content with a timer in it.

That combination means an expensive pattern was rehearsed on one lane and written into the other. On a seat the repetition only cost capacity; running on the schedule it just wired up, against an API key, it bills every time the schedule fires — with nobody watching.

Both conditions must hold in the same session. A looser rule (same repo, same week) fires on coincidence, and a governance tool that cries wolf gets muted, which is the only failure mode that actually matters. The alert fires at most once per session and links straight to the replay.

Who can see whose sessions

Tokenoscopy records your engineers, not your customers — so the default posture is aggregate-first. Everyone in the workspace sees org-wide spend, the weekly report, and every rollup. Individual session replays stay with the developer who ran them, plus the workspace owner, who needs to be able to audit.

Owners can switch this off in Settings if a team has explicitly agreed to open replays. We ship it on because a tool that puts every engineer's session in front of their manager by default is a different product — and a much harder conversation with your works council or security reviewer.

What it costs you at runtime

Live hooks are async — Claude Code never waits on them. The transcript flush runs after a session ends. The only call in your critical path is the budget guard, and it's built to disappear: an allow verdict is cached locally for a few seconds, so a typical tool call costs about 75ms (process start), not a network round trip.

Install the CLI globally rather than relying on npx — a global binary skips package resolution on every call:

npm install -g tokenoscopy
tokenoscopy init   # detects the binary and wires hooks to it

What leaves the machine

Transcripts are redacted before upload, on your machine: known credential shapes (Anthropic/OpenAI/GitHub/ Slack/AWS/Google/Stripe keys), JWTs, private-key blocks, Authorization headers, connection-string passwords, KEY=value secret assignments, and email addresses in content. The server runs the same scrub as a second pass, and oversized payloads are truncated. Full local paths never leave the machine — only the repo folder name.

Costs shown everywhere are list-price estimates (the same math as Claude Code's own /usage) — labeled as such until reconciled against provider billing APIs.

Budget guard: fail-open, always

The guard hook has a hard 1500ms timeout, and every failure path allows the tool call: Tokenoscopy down, network flake, rate limit, bad response — your session never stalls on us. Only an explicit over-budget verdict blocks (or asks), and every block is recorded on the session timeline so replays show exactly what was stopped and why.

Fleet rollout (MDM / managed settings)

To enroll every machine without per-developer setup, render the hook block once and ship it via managed settings (macOS: /Library/Application Support/ClaudeCode/managed-settings.json) — managed policy can't be disabled by users:

npx tokenoscopy init --key $FLEET_KEY --print > hooks.json
# merge hooks.json into your managed-settings.json payload

OTLP intake (Claude Code native telemetry)

For per-request spend straight from Claude Code's own telemetry (and coverage for Bedrock/Vertex deployments where no transcript flush runs), point the OTLP logs exporter at us:

CLAUDE_CODE_ENABLE_TELEMETRY=1
OTEL_LOGS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_PROTOCOL=http/json
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://tokenoscopy.com/api/ingest/otlp/v1/logs
OTEL_EXPORTER_OTLP_HEADERS="X-Tokenoscopy-Key=tok_…"

The same spend fact arriving from several surfaces (live hook, transcript, OTLP) is deduplicated by request id — spend is never double-counted, and the most precise source wins.

How seats are counted

A seat is a person — or an unattributed machine — that ran at least one recorded session in the billing month. It's derived from the sessions themselves, so nothing to declare and nothing to reconcile: a teammate who installs the hook becomes a seat, and someone who stops using agents stops being one.

Sessions attribute to the machine's git identity. For CI runners and containers with no readable identity, issue a labelled ingest key in Settings and its sessions land on whoever owns it.

Recording is never limited by plan. Free covers three seats and seven days of replay, but a fourth developer's sessions are still captured in full — you're asked to upgrade, never silently dropped.

Support

Early-access support runs through the founder directly — reply to any onboarding email. Roadmap: Codex CLI & Gemini CLI parsers, Cursor hooks, billing-API reconciliation (estimated vs billed), OTLP protobuf.