Skip to content

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

@DevVig

Description

@DevVig

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions