npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@marginfront/code-cost-clarity

v0.8.0

Published

See your Claude Code and Codex spend in MarginFront. One command wires your coding-agent usage telemetry through a local collector into MarginFront, priced per developer, per model, with accurate prompt-cache token splitting and automatic billable tool-ca

Readme

@marginfront/code-cost-clarity

See your Claude Code and Codex spend in MarginFront. One command wires your coding-agent usage telemetry through a local collector and into MarginFront, priced per developer, per model, with accurate prompt-cache token splitting. One package, three modes: Claude Code only, Codex only, or both.

⚠️ Beta (pilot software). Under active development - pin a version, expect rough edges, and report issues.

Use npx, not npm install. This is a CLI tool, not a library. Installing it into a project pulls in its dependencies and can surface unrelated audit warnings. Run it with npx @marginfront/code-cost-clarity@latest init (@latest skips a stale npx cache). The npm i ... box on npmjs.com is npm's auto-generated default for every package and is not the intended usage here.

📖 Full documentation: https://docs.marginfront.com/tools/code-cost-clarity

This is internal cost visibility, not billing and not a spend cap. The installing company watches its own AI coding spend (per developer, per model, R&D-vs-COGS). It does not charge developers and it does not cut anyone off.

Your LLM keys stay yours. This tool never reads, needs, or transmits your Anthropic or OpenAI API key. The only credential it uses is your MarginFront key (the secret mf_sk_*), and only to send usage to MarginFront.


What this does (one sentence)

Every time a developer runs Claude Code, this connector captures the token usage and sends it to MarginFront as a usage event, so you can see who used what, on which model, and how much it cost.

The mental model (read this first)

Think of it like a cash-register receipt system:

  1. Claude Code is the register. As it works, it broadcasts receipts (OpenTelemetry exports): how many tokens, which model, which developer.
  2. The collector (otelcol-contrib, open source) is the catcher. It runs in the background, catches the receipts, and writes them to a file.
  3. The forwarder (our glue, inside this package) reads those receipts and sends each one to MarginFront.
  4. MarginFront records the event, prices it, and shows it under the developer's email.
Claude Code (your task)
    |  broadcasts usage on a timer (you choose the interval) + once at session end
    v
Collector (otelcol-contrib, local)  --- converts cumulative->delta so we don't double-count
    |  writes OTLP/JSON lines to live-otlp.jsonl
    v
Forwarder (this package, `run`)
    |  POST /v1/sdk/usage/record
    v
MarginFront (cost dashboard)

How often does it report? It's timer-based, not per-message. Claude Code flushes usage on the export interval (OTEL_METRIC_EXPORT_INTERVAL) plus a final flush when the session ends. The package ships this at 5 minutes, batched, so you get roughly one event per turn without a long wait. Lower it (e.g. 60s or 5s) for a more live drip, or raise it (e.g. 10 min) to batch harder. The collector's delta conversion keeps repeated reports from double-counting.


Quick start

Get your MarginFront key first. Sign in at app.marginfront.com, go to Build -> API keys -> "Create key pair", and copy the secret key (mf_sk_*). Direct link: https://app.marginfront.com/build?tab=keys

Setup is one step now. init does everything:

npx @marginfront/code-cost-clarity init

init walks you through it:

  1. It downloads the collector (~360 MB, one time) and creates ~/.marginfront-ccc/.
  2. It prompts you to paste your MarginFront SECRET key (mf_sk_*) and saves it to ~/.marginfront-ccc/.env for you (mode 600). A publishable key (mf_pk_*) is rejected on send, so use the secret one.
  3. It shows you exactly what it will change in your global config and asks for a y/N (defaults to No). See the Privacy section for the full list. On yes it:
    • adds seven telemetry settings to ~/.claude/settings.json,
    • adds a small [otel] block to ~/.codex/config.toml, and
    • installs a tiny background helper (a macOS LaunchAgent) that runs the meter.

Then just code:

claude          # or: codex   (or open the Claude/Codex desktop apps)

Already running Claude or Codex? Quit and reopen them after init - and start a fresh terminal session. The desktop apps and each terminal session read the telemetry config when they launch, so anything that was already open won't emit until it's reopened.

That's it. No source, no second terminal. Your spend shows up in MarginFront under your developer email, automatically, and the background meter restarts itself at every login.

There is no code-cost-clarity command. init installs no binary on your PATH — typing code-cost-clarity status will say "command not found" and nothing is wrong. Every command runs through npx, always.

Check on it anytime:

npx @marginfront/code-cost-clarity status

Prefer a live terminal view instead of the background meter? After init, run npx @marginfront/code-cost-clarity run to stream spend in your terminal (Ctrl-C stops it). You'll see a line per turn like:

[14:22:07] recorded [email protected] · in=3210 out=287 · server=$0.0232 · cc=$0.0236 event=9f0c2a71-...

CI / scripted installs: add --no-prompt to init to skip BOTH questions (the key paste and the consent prompt) and proceed. It will wire your global config as listed above. Paste your key into ~/.marginfront-ccc/.env separately.


The background meter (always on, no terminal)

init (and start) install the forwarder as a macOS LaunchAgent, a small background helper macOS manages for you. This is what makes "just code" work:

  • It starts at login. No terminal to keep open, nothing to remember.
  • It restarts itself if it ever stops (and survives a reboot).
  • It needs no key in your shell. It reads your saved key from ~/.marginfront-ccc/.env, so a fresh login Just Works.

Manage it with three commands:

| Command | What it does | | -------- | ----------------------------------------------------------------------------------------------------------- | | start | (Re)installs + starts the background meter. init already does this; use it to bring it back after stop. | | status | Tells you whether the meter is running, and shows the last lines of its output + error logs. | | stop | Pauses the meter (the background daemon and any foreground run). start brings it back. |

What gets captured, and what doesn't. CCC meters the coding agents: it reads the claude_code.* and codex.* telemetry that Claude Code and Codex emit to the local collector. init wires telemetry into both places these agents look, so it captures them in the terminal and the desktop apps:

  • Terminal / CLI (claude, codex) and local IDE coding sessions read the env from ~/.claude/settings.json / ~/.codex/config.toml.
  • The Claude Code and Codex desktop apps don't read that env block and never see your shell, so init also writes the same vars into the macOS launchd GUI-session env (launchctl setenv), which Dock-launched apps inherit. Quit and reopen a desktop app after init so it reads them at launch. (All four surfaces were confirmed capturing live.)

It does not capture:

  • The Claude consumer chat app (the chat window) - the general assistant, not Claude Code, so it never emits the coding-agent telemetry CCC reads (it also runs in a sandbox separate from your machine).
  • Anything in a cloud sandbox or not connected to this device - a cloud session, or a remote / devcontainer / SSH setup where the agent can't reach the local collector at 127.0.0.1:4318. If a surface doesn't run here and emit to the local collector, CCC can't see it.

The commands

| Command | What it does | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | init | The one setup command. Downloads the collector, prompts you to paste your MarginFront secret key (mf_sk_*), then, after a y/N consent prompt, wires telemetry into ~/.claude/settings.json + ~/.codex/config.toml and installs the background meter. Safe to re-run (never re-asks for a saved key, never clobbers your settings). --no-prompt skips both questions and proceeds (CI / scripts). | | start | (Re)installs + starts the background meter (the LaunchAgent). init already runs this; use it to bring the meter back after stop. | | status | Is the background meter running? Shows recent activity + the last lines of its error log. | | preview <capture.json> | Prints the exact record it would send for one captured snapshot. Needs no MarginFront key, great for a dry run. | | run | Streams your live spend in this terminal instead of the background daemon (Ctrl-C stops it + the collector). Add --fold-cache only for an unpriced model (see below). | | stop | Pauses the meter: the background daemon and any foreground run. | | uninstall | Stops everything, undoes every config change (the telemetry keys in settings.json, the Codex [otel] block, the background helper), and deletes the collector binary + runtime files (reclaims the ~360 MB). Keeps your settings. Add --purge to also delete your settings + MarginFront key. | | help, version | The usual. |


Per-developer attribution is automatic

What makes "who spent what" work is user.email, and Claude Code puts it in the telemetry on its own. It's the developer's logged-in Claude account email. There is no manual email config. Each developer loads the telemetry settings and runs Claude Code normally.

Works whether the developer signs in with an org-managed seat or an interactive login. On org-managed Claude seats the email is stamped for free. If an developer's sign-in doesn't surface an email, the connector doesn't drop the usage. It attributes it to a clearly labeled placeholder customer (claude-code-no-identity) and prints how to fix it (sign in with an org-managed seat, or attach a customer mapping). You'll see the placeholder in preview/run output if it ever kicks in.

The MarginFront API key is separate from the developer's identity: it's the connector's own credential for posting to MarginFront. run needs it; preview does not.


Shared one login across the team? Set a per-machine developer (CCC_DEVELOPER_EMAIL)

Some teams share one Claude/Codex login across the whole team. When that happens, every developer's telemetry carries the same user.email, so all the AI cost collapses onto one person and per-developer attribution breaks. CCC fixes this without any change to how you log in, because CCC runs locally on each laptop - so each laptop can carry its own developer identity.

During init we ask one question: which developer this machine's AI cost should be attributed to. The prompt is pre-filled with your global git email (git config --global user.email), which is usually the right person sitting at this laptop. You have three choices:

  • Press Enter to accept the pre-filled email.
  • Type a different email to attribute this machine to someone else.
  • Clear it and leave it blank to keep the old behavior - auto-detect from whatever email the coding-agent login reports.

Whatever you choose is saved as CCC_DEVELOPER_EMAIL in ~/.marginfront-ccc/.env (mode 600, right next to your key). To change it later, edit that one line and then stop + start (or just re-run init).

Precedence at send time (highest wins):

  1. CCC_DEVELOPER_EMAIL (this machine's developer) - if set, it wins for every record this machine sends, Claude and Codex, token turns and tool calls.
  2. Otherwise the email the coding-agent login reports (user.email).
  3. Otherwise the no-identity placeholder (claude-code-no-identity / codex-no-identity).

If you don't set it (leave it blank), nothing changes - attribution is byte-for-byte what it was before this feature: the login's own user.email, then the placeholder.

This is internal cost visibility only. CCC_DEVELOPER_EMAIL re-labels which developer the cost shows up under in your MarginFront - it does not change who pays or any customer's bill. The --no-prompt (CI / scripted) install skips this question and leaves CCC_DEVELOPER_EMAIL unset.


Privacy (read this)

This tool is internal cost visibility, and being honest about what it turns on matters, so here is the full picture in plain English.

Your developer email travels in the telemetry, in plaintext, on purpose. That's the whole point: per-developer cost attribution needs to know who ran the turn. Claude Code stamps user.email (your logged-in account email) onto the usage telemetry, the local collector writes it to a file on your machine, and the forwarder POSTs it to MarginFront so the spend lands under your name. It is not hashed or anonymized. If you don't want the email attached, sign in with a login that doesn't surface one, and the usage falls back to the claude-code-no-identity placeholder instead.

Telemetry becomes always-on, globally, for every Claude session. When you say "yes" to the consent prompt, init writes seven telemetry settings into ~/.claude/settings.json. Both the claude command line and the Claude Desktop app read that file, so from then on every Claude session on this computer broadcasts usage to the local collector, not just the terminal you set it up in. That's deliberate (it's what makes "just code" work and what captures Desktop), but it's a real, persistent, machine-wide change, which is exactly why init asks first and defaults to No.

The exact things init changes (and nothing else):

  1. ~/.claude/settings.json: adds these seven keys to the "env" block: CLAUDE_CODE_ENABLE_TELEMETRY, OTEL_METRICS_EXPORTER, OTEL_LOGS_EXPORTER, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_METRIC_EXPORT_INTERVAL, OTEL_LOGS_EXPORT_INTERVAL. It backs the file up first and never overwrites a value you'd already set.
  2. ~/.codex/config.toml: adds one fenced [otel] block (or, if you already have your own [otel], leaves it alone and prints the block to paste).
  3. ~/Library/LaunchAgents/ai.marginfront.ccc.plist + a copy of the meter program (the background helper).

Your MarginFront secret key is the one thing that never leaves ~/.marginfront-ccc/.env (mode 600). It is never written into settings.json, config.toml, or any telemetry payload.

uninstall reverses every one of those changes:

  • removes the LaunchAgent and the copied meter program,
  • removes only the seven telemetry keys it added to settings.json, and only if the value still matches what it wrote, so anything you changed survives,
  • removes only its own fenced [otel] block from config.toml,
  • deletes the collector binary + runtime files.

It keeps your saved key unless you add --purge. The one thing it will not touch is your ~/.zshrc: if an older (0.4.x) setup left a source ~/.marginfront-ccc/.env line there, uninstall reminds you about it but never edits your shell file silently.


Cache pricing

Claude Code reports four kinds of tokens (fresh input, output, cache-read, and cache-creation), and Anthropic prices them differently. This connector splits them into their correct typed fields (cacheReadTokens / cacheWriteTokens) so MarginFront can price each at its own cache rate instead of lumping everything into one input number. That token split is accurate by default.

  • Default (recommended). Cache tokens go in the typed cacheReadTokens / cacheWriteTokens fields; MarginFront prices each at the model's catalog rate.
  • --fold-cache (emergency round-up only): for a model MarginFront can't price yet, this rolls the cache tokens into billed input at the fresh-input rate, pushing the number up toward reality so it's never silently low, a conservative ceiling. Use it only when a model has no cache price; otherwise the default is more accurate.

The dollar figure uses your MarginFront catalog's rate for each model. If a model isn't priced yet, its usage lands NEEDS_COST_BACKFILL (a visible gap, never a silent $0), and one click in MarginFront prices it both retroactively and going forward. The raw cache numbers are also kept in metadata, and Claude Code's own cache-accurate cost is in metadata.claudeCodeCostUsd to reconcile against.

Pricing note (catalog/ops): coding agents use Anthropic's 1-hour prompt cache, so set your catalog's cache-write rate to the 1-hour rate (2× base input), not the 5-minute rate (1.25× input). Reconciling a live session against metadata.claudeCodeCostUsd confirmed the 1-hour rate matches to the cent; the 5-minute rate reads ~30-40% low on a cache-heavy session.

A long-context model id like claude-opus-4-8[1m] is normalized to claude-opus-4.8 to match MarginFront's pricing table. The raw id is kept in metadata.rawModel.


Billable tool calls (automatic)

Tokens are the bulk of coding-agent spend, but the connector also forwards billable tool calls (a paid web search, a metered MCP or API tool) as their own line items, tagged by tool name. There's no client config: MarginFront's pricing catalog decides what's billable. A tool with a price row gets priced; any other tool lands NEEDS_COST_BACKFILL (a visible gap you can price later, never a silent charge). Free built-ins (file reads, shell, grep) are forwarded too and priced $0 by the catalog, so your usage view shows the full picture of tool activity without inventing cost. Older CCC builds that still drop built-ins client-side keep working unchanged - they simply don't send those $0 lines.


Also capture Codex (second source)

The same package captures Codex too. Nothing extra to install. Codex reports to the same local collector. You get three modes for free: Claude Code only, Codex only, or both (same developer's name on all of it).

init turns it on for you when you consent, it adds this [otel] block to your ~/.codex/config.toml automatically:

[otel]
exporter = { otlp-http = { endpoint = "http://127.0.0.1:4318/v1/logs", protocol = "binary" } }

The exporter is a table, the endpoint lives inside it and ends in /v1/logs, and protocol sits in that same table. (A flat exporter = "otlp-http" with a bare top-level endpoint silently exports nothing. Verified.)

The only case init won't write it for you is if you already have your own [otel] settings. It won't rewrite your config; it just prints the block above so you can merge it by hand. Either way, then run Codex normally. The background meter (and run) already watches both sources from the one collector file; there's no extra flag. uninstall removes only the block it added.

Why Codex's numbers are computed differently

Anthropic and OpenAI count tokens differently, and getting this wrong silently mis-charges you. For Codex, two of the token counts are already nested inside the others:

  • cached_token_count is already part of input_token_count.
  • reasoning_token_count is already part of output_token_count.

So we do not add reasoning on top of output, and we do not bill input and cached separately as if they were distinct. The accurate split we send is:

| MarginFront field | From Codex | Why | | ----------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------- | | inputTokens | input_token_count - cached_token_count | the fresh, non-cached input only | | cacheReadTokens | cached_token_count | priced at the cheaper cache-read rate | | outputTokens | output_token_count | reasoning is already inside this, billed at the output rate, same as OpenAI bills it | | (no cacheWrite) | n/a | OpenAI has no cache-creation tokens |

The raw reasoning, tool, and cached counts are recorded in metadata for audit; they are never billed twice. (If you ever hit an unpriced Codex model, --fold-cache still works the same conservative way: it bills the whole input at the input rate and drops the cache-read field, so the number reads high, never low.)

Identity by sign-in mode (org seat vs ChatGPT login)

Per-developer attribution rides on user.email from Codex's telemetry, same idea as Claude Code. Whether that email surfaces depends on how the developer signs in to Codex (an org-managed or API-key sign-in stamps it; some interactive ChatGPT logins may not). We never read that OpenAI key; the only thing that matters here is whether the telemetry carries an email. If it doesn't surface, the usage isn't dropped. It lands under the codex-no-identity placeholder with a fix hint, exactly like the Claude path.

Edge cases to know

  • gpt-5-codex pricing row is a precondition. A full-rate row (including its cache rate) must exist in MarginFront's pricing catalog. Until it does, a Codex event lands NEEDS_COST_BACKFILL (a visible gap, safe), never a silent $0. This is an ops/catalog step, not something this package can seed.
  • codex-auto-review is excluded. It's an internal pseudo-model, not a real billable model, so we drop it rather than mis-price it.
  • codex and codex exec both export the usage logs this package reads, verified against a live session. (Separately, some Codex versions don't emit OTel metrics, and codex mcp-server telemetry has had bugs, but neither is the logs stream we use, so neither affects capture here.)
  • The [otel] block above is the verified shape. If a future Codex version changes it, keep the exporter a table pointed at the local collector on /v1/logs.

Confirm the dollar figure once. The exact Codex dollar figure should be confirmed against one real captured session: that Codex reports per-turn (not session-cumulative) token counts on the log stream, and that your developer email populates under your sign-in mode. The mapping above is the verified-safe default; one real session is enough to confirm it for your setup.


Confirm it landed (independent read-back)

KEY="<your MarginFront API key>"
curl -s -H "x-api-key: $KEY" \
  "https://api.marginfront.com/v1/[email protected]&limit=5&sortBy=usageDate&sortOrder=desc"

Maintain / shut off

  • Collector version is pinned for safety. The installer downloads one known-good, checksum-verified collector release. Moving to a newer collector ships in a package update (so the integrity check always has a fingerprint to verify against); there is no per-run version override.
  • Check on it: status says whether the background meter is running and shows the last lines of its logs.
  • Pause temporarily: stop pauses the background meter (and any foreground run). start brings it back; it also comes back on the next login.
  • Remove it: uninstall stops everything, undoes every change init made (the telemetry keys it added to ~/.claude/settings.json, its [otel] block in ~/.codex/config.toml, and the background helper) and frees the ~360 MB. It keeps your MarginFront key; uninstall --purge deletes your settings too. The one thing it won't touch is ~/.zshrc: if an older (0.4.x) setup left a source ~/.marginfront-ccc/.env line there, uninstall reminds you but never edits your shell file silently. Remove that line by hand if you like.

Troubleshooting

  • "No MARGINFRONT_API_KEY found": paste your MarginFront key into ~/.marginfront-ccc/.env, or export MARGINFRONT_API_KEY=... in the run shell. preview works without one.
  • HTTP 401/403: wrong/expired key, or you pasted a publishable key (mf_pk_*) where a secret key (mf_sk_*) is required. The forwarder POSTs usage, and publishable keys are rejected on writes. Pull a fresh secret key at app.marginfront.com → Build → API keys → "Create key pair" (https://app.marginfront.com/build?tab=keys).
  • HTTP 422 / validation error: body-shape mismatch. Run preview <capture.json> and compare the record.
  • Collector file stays empty: telemetry isn't reaching the collector. Most often that's because you skipped the consent prompt (so ~/.claude/settings.json was never wired), so re-run init and answer y, then start a fresh claude session. (Older manual setups could also be on gRPC/4317; the settings default to http/protobuf/4318, the transport that actually works with Claude Code.)
  • usageCost is null: the normalized model id didn't match the pricing table. Tokens are still recorded; the cache-accurate cost is in metadata.claudeCodeCostUsd.
  • Numbers ballooning: the collector's cumulativetodelta processor isn't running. Re-run init to rewrite the collector config.
  • Seeing claude-code-no-identity (or codex-no-identity)? Your login didn't surface an email. Use an org-managed Claude seat, or attach a customer mapping.

Security

  • This tool never reads, needs, or transmits your Anthropic or OpenAI API key. The only credential it uses is your MarginFront key, and only to send usage to MarginFront.
  • Your MarginFront key never lives in this package. It's saved only in ~/.marginfront-ccc/.env (mode 600) on your machine. The forwarder reads it from the environment only, never hardcoded, never logged. It is never written into ~/.claude/settings.json or ~/.codex/config.toml. Only the six non-secret telemetry settings go there (see Privacy).
  • The published package contains only the built code and this README. Captured telemetry, the collector binary, and your .env are all kept out (and the package .gitignore guards the source tree too).

For developers (technical appendix)

Input shape: OTLP/JSON, tree resourceMetrics[].scopeMetrics[].metrics[]. Two metrics matter: claude_code.token.usage (one datapoint per type in input/output/cacheRead/cacheCreation) and claude_code.cost.usage (USD).

Value encoding (handled both ways): the console exporter emits the value as asInt (a JSON string); the collector's file exporter emits it as asDouble (a JSON number).

Grouping key: (user.email, model, session.id) → one MarginFront record per group.

Token mapping: inputinputTokens, outputoutputTokens, cacheReadcacheReadTokens, cacheCreationcacheWriteTokens (Anthropic cache_creation_input_tokens). With --fold-cache, cache tokens are added into inputTokens instead and the typed fields are omitted (no double count).

Temporality: Claude Code emits CUMULATIVE counters and ignores the delta preference env var. The collector's cumulativetodelta processor converts to deltas; the forwarder trusts each line is already an increment.

Ingest: POST https://api.marginfront.com/v1/sdk/usage/record, headers Content-Type: application/json + x-api-key: <key> (NOT Bearer). Body envelope { records: [...] }. The endpoint auto-creates the customer (by customerExternalId) and agent (by agentCode) on first POST, and resolves your org from the MarginFront key (the body can't override it).

Codex source (the second input shape)

Input shape: OTLP/JSON logs, tree resourceLogs[].scopeLogs[].logRecords[] (a different tree than Claude Code's resourceMetrics). The usage event is named codex.sse_event; we detect it by that name (on the event.name attribute or the record body) or, failing that, by the presence of any token-count attribute.

Value encoding: log attribute values arrive as intValue (a JSON string per the protobuf int64 rule) or doubleValue (a JSON number) for token counts, and stringValue for identity fields. All three are handled.

Token fields: input_token_count, output_token_count, cached_token_count, reasoning_token_count, tool_token_count, plus model, user.email, and a session id (conversation.id / session.id). The accurate nested mapping is in the Codex section above: cached is subtracted from input, reasoning is never added to output.

Granularity: one MarginFront record per codex.sse_event (one per turn). No cumulativetodelta on the logs pipeline (that's a metrics-only processor); each Codex log record is already one turn's usage.

Identity: agentCode: "codex", signalName: "codex-turn", modelProvider: "openai", environment: "development" (R&D). Records carry metadata.source: "codex".

Routing: both sources write one JSON document per line to the same collector file. The forwarder routes each line by which tree it has (resourceMetrics → Claude Code, resourceLogs → Codex), so one watcher handles either or both.