Proposal: Add precise usage logging fields to JSONL for burn/window forecasting

Resolved 💬 2 comments Opened Aug 31, 2025 by DevVig Closed Nov 28, 2025

Proposal: Add Precise Usage Logging to Codex CLI

This proposal adds small, backward-compatible fields to Codex’s session JSONL logs so tools can compute accurate burn rates, window usage, and per-model cost — without heuristics.

Problem

Many tools (including CodexUsage) aim to answer three questions:

  • How much have I burned in the current billing window?
  • How much is left (vs cap), and what’s my tokens/min?
  • Will I burn through before the window resets?

Today, Codex’s logs often lack per-entry timestamps and token usage. Without that, tools must guess (e.g., treat the last N appended lines as “now” and approximate tokens from line size). It works, but it’s noisy and less trustworthy.

Proposal

Emit a minimal set of fields per JSONL line:

  • timestamp (string, ISO-8601 UTC)
  • Example: "2025-08-31T09:05:27.123Z"
  • sessionId (string)
  • Stable id for the session/file (already implicit in path; explicit helps dedupe/merge).
  • message (object)
  • usage (object)
  • input_tokens (number)
  • output_tokens (number)
  • cache_creation_input_tokens (number, optional)
  • cache_read_input_tokens (number, optional)
  • model (string) — e.g., "gpt-4o-mini"
  • id (string) — message id
  • requestId (string) — paired with message.id for deduplication

Optional but highly valuable:

  • costUSD (number) — if the backend computes it
  • isLimitEvent (boolean)
  • resetEpochSeconds (number) — only on limit events; anchors the billing window end precisely (example: 1725105600)

Example lines

{"timestamp":"2025-08-31T09:05:27.123Z","sessionId":"a-uuid","message":{"usage":{"input_tokens":1200,"output_tokens":350},"model":"gpt-4o-mini","id":"msg_123"},"requestId":"req_abc"}
{"timestamp":"2025-08-31T09:10:00.500Z","sessionId":"a-uuid","message":{"usage":{"input_tokens":100,"output_tokens":25,"cache_read_input_tokens":300},"model":"gpt-4o-mini","id":"msg_124"},"requestId":"req_def"}
{"timestamp":"2025-08-31T10:55:00.000Z","isLimitEvent":true,"resetEpochSeconds":1725105600,"message":{"id":"evt_1"}}

Rationale

  • timestamp — enables precise window-restricted aggregation and trends.
  • message.usage — exact tokens without guessing.
  • model — unlocks per-model cost breakdowns when paired with pricing.
  • resetEpochSeconds — anchors the end of the current window so forecasts compare ETA vs time-to-reset correctly.
  • requestId + message.id — dedupe across files/rotations.

Backward Compatibility

These fields are additive; older tools can ignore them. If absent, tools can fall back to heuristics. When present, dashboards become precise and stable without user configuration.

Implementation Notes

  • The fields can be populated where Codex generates each log event (e.g., at message streaming completion or post-request hooks).
  • timestamp from a monotonic clock synchronized to UTC.
  • resetEpochSeconds is only needed when a limit/reset is signaled by the provider; the rest of the windowing uses epoch-aligned blocks if this is absent.

Outcomes

  • Users see clear answers:
  • Tokens used in current window, tokens remaining vs cap
  • Reliable tokens/min and trend
  • ETA to cap vs time to reset (overrun risk)
  • Less support overhead from ambiguous windows/burn.

If the Codex team is supportive, I can open a small PR that threads these fields through the JSONL writer, plus a doc page pointing to consumers.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗