Codexometer is a small, retro terminal dashboard for your current
Codex quota.
Keep it open in a second terminal window or pane and you can see every active
usage window, its remaining capacity, and its reset time without repeatedly
opening /status in your working Codex session.
█▀▀ █▀█ █▀▄ █▀▀ ▀▄▀ █▀█ █▀▄▀█ █▀▀ ▀█▀ █▀▀ █▀█
█▄▄ █▄█ █▄▀ ██▄ █ █ █▄█ █ ▀ █ ██▄ █ ██▄ █▀▄
◉ QUOTA TELEMETRY CONSOLE · VERSION <CURRENT>
Hacker theme showing Codex and GPT-5.3-Codex-Spark quota windows.
Codexometer refreshes once a minute by default. Its quota dashboard is read-only. The optional Benchmark tab starts model turns only when you explicitly click its run button; those trials consume Codex quota.
Codex already exposes quota information through /status, but that view lives
inside the session you are using. Codexometer is designed as a companion
display:
┌──────────────────────────────┬──────────────────────────┐
│ Codex session │ Codexometer │
│ │ │
│ Editing, reviewing, coding │ 5-hour window 62% │
│ │ Weekly window 37% │
│ No need to interrupt work │ Next reset 02:17:00 │
└──────────────────────────────┴──────────────────────────┘
It works particularly well in:
- another Windows Terminal tab or split pane;
- a second Terminal/iTerm window on macOS;
- a tmux, Zellij, or terminal-multiplexer pane;
- an Ubuntu terminal beside the Codex CLI.
- Every rate-limit bucket and window returned by the current Codex account, plus the effective monthly credit limit when supplied.
- Used and free percentages for each window.
- The duration of each window, such as five hours or one week.
- A live countdown and local clock time for each reset.
- On every Quota view, a separate reset-cycle gauge comparing elapsed window time with quota consumed. It uses the same active colour as its quota meter.
- A learned standard API-equivalent estimate for primary Codex windows of both quota consumed and inferred 100% capacity, including a range, sample count, and deliberately conservative confidence level.
- The current ChatGPT plan when Codex supplies it.
- Spend-control hard stops and available account-credit balance when supplied.
- Available earned reset credits when present.
- Online, refreshing, stale-data, and error states, with the limiting window named in warning states and a celebratory fresh-reset signal at 0% usage.
- A countdown to the next automatic refresh.
- An always-on Monitor view that measures local token activity while Codexometer is running, with Pause/Resume and Reset controls. Each independent local root session gets its own metrics and 30-second graph; explicitly linked spawned agents are included with their root.
- Highlighted per-session attention badges. A shared Codex app-server supplies
exact
INPUT NEEDEDandAPPROVAL NEEDEDstates. Without it, a completed open turn is definiteINPUT NEEDED; an otherwise active session with no rollout activity for three minutes is cautiously labelledCHECK SESSION. For a root with linked agents, fresh activity from any member suppresses that uncertain fallback; definite input or approval signals still propagate from the member that raised them. - An opt-in deterministic coding benchmark comparing a selectable scope of
visible Codex models and supported reasoning efforts by correctness, elapsed
time, token use, and estimated standard API-equivalent cost. The current trial appears immediately
as an
IN PROGRESSrow; select or click any row to inspect its benchmark-only prompt, structured response, verifier outcome, and telemetry.
Codexometer does not assume that every account has the same windows. Some accounts expose a shorter rolling window and a weekly window; plans and backend configuration can differ. The UI renders whatever the current Codex account actually returns.
- The
codexCLI installed and available onPATH. - A current ChatGPT login in Codex.
- A modern terminal with ANSI color and Unicode support.
Go is required only when installing from source. A compiled Codexometer binary does not require a Go runtime.
The release installer downloads the pre-built binary for the current operating system and architecture, verifies its published SHA-256 checksum, confirms the binary reports the requested version, and then installs it. Go is not required.
On macOS or Linux:
curl -fsSL https://raw.githubusercontent.com/merefield/codexometer/main/install-release.sh | shThe default destination is /usr/local/bin; the installer uses sudo only
when that directory is not writable. To install without elevation:
curl -fsSL https://raw.githubusercontent.com/merefield/codexometer/main/install-release.sh | \
CODEXOMETER_BIN_DIR="$HOME/.local/bin" shTo install a specific release, replace vX.Y.Z with its tag and add
CODEXOMETER_VERSION=vX.Y.Z beside the bin-directory setting, or download the
script and pass --version vX.Y.Z.
On Windows, download and run the PowerShell installer:
$installer = Join-Path ([IO.Path]::GetTempPath()) "install-codexometer.ps1"
Invoke-WebRequest https://raw.githubusercontent.com/merefield/codexometer/main/install-release.ps1 -OutFile $installer
Set-ExecutionPolicy -Scope Process Bypass -Force
& $installer
Remove-Item $installerThe execution-policy override applies only to that PowerShell process. Inspect the downloaded script before running it if required by your security policy.
It installs into %LOCALAPPDATA%\Programs\codexometer\bin by default. Override
that with CODEXOMETER_BIN_DIR or -BinDir; use -Version vX.Y.Z to select a
release. Both installers print a reminder if the destination is not already on
PATH. Re-running the same command safely upgrades or reinstalls Codexometer.
The installer scripts are ordinary text files in this repository and can be downloaded and inspected before execution.
Developers with a current Go toolchain can build and install from source:
go install github.com/merefield/codexometer@latestgo install builds locally and places the executable in GOBIN, or in the
bin directory under GOPATH when GOBIN is empty. That directory must be on
PATH.
To build the current checkout:
git clone https://github.com/merefield/codexometer.git
cd codexometer
make buildUse go build -trimpath -o codexometer . directly if Make is unavailable; on
Windows, use -o codexometer.exe. Confirm any installation with:
codexometer --versionStart the dashboard:
codexometerConfirm that Codexometer can use the prevailing Codex login without opening the interface:
codexometer --check-authPreview all UI features using simulated quota data:
codexometer --demoCodexometer works with an ordinary Codex CLI process, but connecting your CLI sessions through one shared app-server daemon unlocks its most accurate live telemetry on macOS, Linux, and WSL:
- Definite attention states — Monitor can distinguish
INPUT NEEDEDfromAPPROVAL NEEDEDusing live per-thread status instead of eventually showing the cautiousCHECK SESSIONinactivity fallback. - Resolved-model API equivalents — live model-reroute and response-usage events let Codexometer price a positively matched call using the model that actually served it, rather than relying only on the requested model saved in the rollout.
- Better multi-session visibility — every connected CLI tab or pane remains a separate Monitor session while sharing the same accurate status source; explicitly linked subagents are still folded into their root session.
- No extra Codexometer authentication — the daemon, CLI clients, and
Codexometer continue to use the prevailing Codex login under the same
CODEX_HOME. - Safe degradation — sessions not connected to the daemon continue to use all core quota features with requested-model pricing, rollout lifecycle signals, and writer-lock attention detection.
Set up the recommended arrangement as follows.
-
Confirm that the current standalone Codex CLI and Codexometer see the same login and
CODEX_HOME:codex --version codexometer --check-auth
-
Start the managed daemon and confirm that it is ready:
codex app-server daemon start codex app-server daemon version
-
Launch each working Codex CLI terminal against the daemon's default Unix control socket:
codex --remote unix://
Run this client command separately in every terminal tab or pane that Codexometer should monitor through the shared daemon.
-
Start Codexometer in an adjacent window or split pane before beginning work that you want attributed:
codexometer
Starting it first matters because transient model-reroute events cannot be reconstructed after the fact. No additional Codexometer option is required; it automatically probes the same default socket under
CODEX_HOME. -
Leave Codexometer running while you work. The Monitor starts automatically; use Reset when you want a fresh measured interval, and keep unrelated Codex activity quiet while running Benchmarks if you want the cleanest comparisons.
Codexometer subscribes only to thread IDs that are already loaded by the daemon; it does not load unrelated historical sessions.
Manage or stop the daemon with:
codex app-server daemon restart
codex app-server daemon stopThe managed daemon lifecycle is currently experimental, Unix-only, and expects the standalone Codex installation. Native Windows and other ordinary CLI sessions remain fully usable through the fallback described above. The app-server also supports a local WebSocket listener, including on Windows:
codex app-server --listen ws://127.0.0.1:4500
codex --remote ws://127.0.0.1:4500Plain WebSockets should be used only on localhost or through an SSH tunnel. Codexometer currently auto-detects only the default Unix daemon socket, so WebSocket-connected sessions use its fallback attention detection for now. See the official Codex app-server documentation for custom socket paths, secure remote connections, and authentication.
Codexometer starts codex app-server as a short-lived child process and asks
its account API for the current rate limits and account identity. The identity
is immediately reduced to the process-local fingerprint described below. The
child inherits the prevailing environment, including CODEX_HOME, so it uses
the same ChatGPT account and credential-refresh behavior as the installed Codex
CLI.
Codexometer deliberately does not:
- read or copy Codex credential/token files;
- implement a separate OAuth flow;
- store access or refresh tokens;
- send Codex credentials to another service;
- invoke a model merely to discover quota information.
The Monitor and observed quota estimator additionally read locally persisted
Codex rollout files under $CODEX_HOME/sessions (normally
~/.codex/sessions). They decode token_count totals, each last response's
input/cache/cache-write/output counts, requested model name, timestamps, and
content-free turn timing,
plus the minimum session metadata needed for grouping: thread ID, parent thread
ID, source classification, working directory, and the inherited-history
boundary. It also reads lifecycle event names and blocking flags to identify an
explicit unresolved input or approval request. To distinguish an open CLI
waiting at its prompt from a closed historical session, it inspects the lock
state—not the contents—of Codex's per-thread writer lock. Message text—including
the final response carried beside timing metadata—reasoning, commands, tool
results, and credentials are ignored and never retained from ordinary Codex
sessions. The sole content-reading exception is a benchmark turn explicitly
started by Codexometer. Its Codexometer-authored policy and prompt, visible
structured response, and—only for DigBench—sanitized game-tool requests and
responses are kept in bounded process memory for the Benchmark run detail view.
Reasoning events, platform instructions, credentials, request headers,
temporary paths, local scratch-work commands, and internal thread, turn, call,
or response IDs are not captured.
When the managed shared daemon is available, Codexometer also keeps a local app-server subscription for already-loaded thread IDs. From that stream it retains only runtime status flags and content-free model-reroute/token-usage correlations needed for the features above. It ignores prompts, responses, reasoning, tool payloads, and server requests, and never sends a turn or an approval response through this connection.
If you use a nonstandard Codex executable, pass it explicitly:
codexometer --codex /path/to/codex| Key | Action |
|---|---|
t |
Cycle color themes |
Tab |
Select the next top-level tab: Quota, Monitor, or Benchmark |
Shift+Tab |
Select the previous top-level tab |
r |
Refresh quota data immediately |
v |
Cycle the active Quota view |
s |
Reset the Monitor baseline, or open Benchmark Scope |
p |
Pause or resume live monitoring (Monitor view only) |
b |
Run the selected benchmark scope (Benchmark view only) |
a |
Arm, then confirm, Run All (Benchmark view only) |
x |
Close the selected Monitor session row, or stop the active benchmark suite and retain its incomplete trial |
d |
Close the Benchmark Scope screen |
[ / ], Left / Right |
Select the previous or next benchmark suite |
f |
Show all, passed, or failed benchmark results |
w |
Cycle Cost, Balanced, and Speed benchmark ranking weights |
Up / Down |
Select a Monitor session row or Benchmark row, or scroll open Benchmark detail |
Enter / Space |
Open a selected result, or toggle a Benchmark Scope checkbox |
c |
Copy the Benchmark result matrix as Markdown, or copy the complete open run detail |
Page Up / Page Down |
Scroll Monitor session rows or Benchmark result pages |
q |
Quit |
Esc |
Return from Benchmark detail or Scope; otherwise quit |
Ctrl+C |
Quit |
The responsive top rail below the account status selects Quota, Monitor, or
Benchmark by mouse, Tab, or Shift+Tab. Quota adds a second rail for Bars,
Consumption Pace, Pie, and Fuel Tank; select these with the mouse or cycle them
with v. Codexometer remembers the selected Quota view when you leave
and return. Both rails condense automatically as the terminal narrows.
The footer presents the remaining actions as clickable buttons, including View
only while Quota is active. Move the pointer over a tab or button to highlight
it, or click it to activate it. Controls pulse briefly when activated by mouse
or keyboard. The keyboard assignments remain available in terminals without
mouse support. Theme and tab changes are immediate and do not trigger a network
refresh. Theme, Quota view, benchmark result filter, and benchmark ranking
weight are restored on the next launch.
The top-right signal keeps ONLINE in the selected theme color while its dot
and quota-health label use fixed semantic colors. Warning labels identify the
meter responsible, for example 5 HOURS // WATCH, MONTHLY // NEAR, or
SPEND // EXHAUSTED:
- green
RESET FRESH // GO!— every returned meter currently reports 0% used; - green
QUOTA CLEAR— consumption is keeping pace with, or trailing, elapsed window time; - blue
QUOTA WATCH— the current average burn rate would exhaust at least one quota window before it resets; - amber
LIMIT NEAR— excess pace projects exhaustion within the first quarter of the time still remaining, or no more than 5% remains while over pace; - red
QUOTA EXHAUSTED— a window is at 100%, Codex explicitly reports its rate limit reached, or account spend control reports a hard stop.
Codexometer reports the worst state among all returned rolling windows and the effective monthly credit limit. If reset timing or cycle duration is unavailable, it conservatively falls back to remaining capacity: Watch at 20% and Near at 5%. The monthly limit supplies a reset time but no cycle start, so Codexometer never invents monthly elapsed progress. Scanning and stale-signal states take precedence while quota health cannot be evaluated reliably.
For each window with valid duration and reset data, Codexometer calculates:
U, the used quota fraction (usedPercent / 100);E, the elapsed window fraction, usingreset time - window durationas the window start;- remaining quota
1 - Uand remaining time1 - E; - projected time to exhaustion, as a fraction of the complete window:
E × (1 - U) / U.
It then applies these rules in severity order:
- Exhausted if
usedPercentis 100, Codex explicitly reports that a rate limit has been reached, orspendControlReachedis true. - Fresh if every returned used percentage is zero.
- Clear if
U <= E: quota consumption is no further advanced than the reset cycle. - Limit Near when over pace and either no more than 5% quota remains, or projected exhaustion is within the first 25% of the time remaining to reset.
- Watch for every other over-pace window (
U > E).
This means 10% remaining can correctly stay Clear when less than 10% of the window remains: quota is low, but reset is closer than exhaustion at the observed average pace. Conversely, a window with plenty remaining can reach Watch or Limit Near if it is being consumed very early and projects exhaustion well before reset. Percentages are clamped to 0–100 before classification. If duration or reset data is missing or invalid, pace cannot be calculated, so the fallback is Clear above 20% remaining, Watch at 20% or less, Limit Near at 5% or less, and Exhausted at 0%.
Every Quota presentation also learns an observed standard API-equivalent
for the primary codex rate-limit windows. Additional/model-specific limits
show LIMIT ATTRIBUTION UNKNOWN, because the rate-limit API does not say which
local model calls consumed those buckets. The primary windows show two estimates:
SPEND/NOW— the inferred API-equivalent value of the percentage consumed in the current window;100%/FULL— the inferred API-equivalent value represented by an entire window under the workload Codexometer observed.
These figures are not an account balance, subscription valuation, token allowance, invoice, or claim about OpenAI's private quota formula. They answer a narrower question: “At published standard API text-token prices, roughly what would this observed mix of model work cost when mapped onto the movement in my quota meter?”
Codexometer normally prices each newly completed local model call using the
requested model durably recorded in its turn context. Current Codex rollout
files do not persist transient model-reroute events, so a reroute cannot be
reconstructed from that source alone. When Codexometer and the CLI share the
managed daemon described above, Codexometer keeps a live subscription and
matches reroute and token-usage events to rollout calls by thread ID, turn ID,
cumulative token checkpoint, and the complete response token breakdown. For a
subscribed thread, costing waits for one refresh when that exact match is not
yet available; a matching notification uses the resolved model, otherwise the
call safely returns to requested-model pricing. A call awaiting that decision
is kept in a separate pending count and does not enter the cumulative priced or
unpriced totals. This makes finalized accounting monotonic; a quota observation
that overlaps pending or newly finalized accounting is deferred instead of
silently moving its learning baseline. Late attachment, disconnects,
ordinary non-daemon clients, and already historical reroutes also retain
requested-model pricing rather than being guessed; these remaining coverage
limits are one reason confidence never rises above Medium. Ordinary input, cached input,
cache-write input, and output are priced separately; requests above the
published 272,000-input-token threshold use the corresponding long-context
rates where OpenAI publishes them. Unknown models or missing price classes fail
closed as UNPRICED MODEL MIX rather than being guessed or treated as free.
Core, Extended, and DigBench trials use ephemeral threads that intentionally do
not appear in normal persisted session telemetry. While a subscription-funded
benchmark suite is active, Quota views replace the numeric API-equivalent
estimate with SUBSCRIPTION BENCHMARK ACTIVE instead of presenting partial
accounting. When each trial finishes, its authoritative benchmark usage is
folded into the same process-local accounting used for quota learning; missing
or unpriceable benchmark usage fails closed and restarts the learning anchor.
Benchmarks funded by CODEXOMETER_BENCHMARK_API_KEY are excluded because they
do not consume the displayed subscription quota. Benchmark threads remain
hidden from Monitor; hiding presentation does not exclude their aggregate
subscription impact from Quota views.
The embedded rates come from the
official OpenAI API pricing page
and were retrieved on 2026-08-23.
Every Quota presentation repeats that retrieval date and a terminal hyperlink
to the source in its footer when the terminal is wide enough, matching the
Benchmark view and making stale compiled pricing conspicuous wherever a priced
figure appears.
Each refresh brackets the account quota request with local accounting reads.
If their cost, finalized-call, or pending-call counters differ—or a call is
still pending—OBSERVATION DEFERRED is shown and no sample is taken, preventing
a response completed during the request from being paired with the wrong quota
snapshot. Learning starts with a stable quota percentage and cumulative local
API-equivalent cost anchor. A pause in activity does not expire or reduce clean
movement. The backend may revise an upcoming rolling-window reset timestamp;
Codexometer retains the earliest observed boundary and does not restart merely
because that future timestamp moved. Once the same window advances by at least
five displayed percentage points without a reset or an unpriced call, a sample
is calculated:
central 100% estimate = observed API-equivalent cost × 100 / percentage-point movement
lower bound = observed API-equivalent cost × 100 / (movement + 1)
upper bound = observed API-equivalent cost × 100 / (movement - 1)
current spend range = 100% range × current used percentage
The ±1 denominator reflects the integer granularity of the quota percentage.
For multiple samples the UI reports the median lower and upper bounds. One or
two clean samples are LOW confidence; at least three samples spanning 15 or
more percentage points can reach MED only when both their rounding ranges and
their central capacity estimates agree within conservative spread limits.
Confidence is intentionally capped at Medium because local telemetry cannot
prove that no other machine, cloud task, unobserved client, or server-side model
reroute outside the shared-daemon subscription also affected the account quota.
An interval is discarded and re-anchored if its earliest reset boundary passes,
used quota falls, the account or window definition changes, finalized counters
regress, the quota moves five points without any matching priced local call, or
an unknown/unpriced model occurs. The learning readout retains the reason, for
example RESTARTED: WINDOW RESET, WINDOW DEFINITION CHANGED, LOCAL ACCOUNTING REBASED, UNPRICED MODEL MIX, or LOCAL COVERAGE GAP, while new
clean movement accumulates. It never silently returns to 0/5PP. Even a valid
estimate can still vary with reasoning effort, model mix, caching, prompt
shape, and backend quota weighting, so compare ranges and sample counts rather
than treating the midpoint as a fixed entitlement.
Samples remain process-local and are never written to the preferences file, so
evidence cannot leak from one login into another on a later run. During a run,
Codexometer requests the current account email from the same local app-server,
immediately reduces it to an in-memory one-way fingerprint, and uses that only
to separate account observations. The email and fingerprint are not persisted.
If an older app-server cannot provide an account identity, the estimate fails
closed as ACCOUNT ATTRIBUTION UNKNOWN rather than mixing indistinguishable
accounts.
The privacy trade-off is that quitting Codexometer discards every learned
sample and quota anchor. On restart it can reconstruct cumulative priced usage
from local rollout telemetry, but the current quota percentage and cost become
a new baseline: the display returns to LEARNING and needs another five clean
percentage points of movement before producing an estimate. Medium confidence
must also be earned again from three qualifying samples spanning at least 15
percentage points. Frequent restarts can therefore delay an estimate
substantially, especially for a slowly moving weekly window.
At most 12 samples per account/window are retained in memory and samples older
than 45 days are ignored. No token event, model-call record, prompt, response,
session ID, email, or account ID is stored. Run codexometer --demo, then
refresh once with r, to preview a learned estimate without consuming quota.
Press t to cycle:
- Hacker — the default green CRT telemetry console.
- Rust — a warm amber monitor with weathered brown shadows.
- Blue Steel — cool blue instruments on a dark slate background.
- Ultraviolet — purple phosphor with magenta highlights and plum shadows.
- Nightshade — vivid royal-purple instruments on a deep plum screen.
The default remains the original green hacker-terminal presentation.
The top-level tabs are Quota, Monitor, and Benchmark. Within Quota,
choose one of these four views with its sub-tab or v:
- Bars — chunky quota bars, with one full-width rate-limit window per row.
- Pie — clockwise-filled circles rendered on a 2×4 sub-cell Braille canvas for clean curves at any size.
- Consumption Pace — a signed horizontal scale comparing elapsed window
time with quota consumed. Positive headroom means consumption is behind
elapsed time; a negative deficit means quota is being used too quickly. A
clearly labelled linear projection reports
SAFE THROUGH RESETor estimates how long remains until exhaustion and how early that is relative to reset. - Fuel Tank — a reverse gauge whose bright segment shows remaining range and whose dark segment shows consumed capacity, labelled from Empty to Full; one full-width tank appears per row. Its reset-cycle comparison also drains backward and aligns exactly with the tank's first and last inner cells.
The other top-level views are:
- Monitor — automatically establishes a zero baseline across locally active
Codex sessions when Codexometer starts. A large readout follows newly appended
token telemetry and shows total observed tokens, elapsed time, and average
rate; clickable Pause/Resume and Reset controls sit beside it. Active sessions
are checked once per second and the idle cadence relaxes to five seconds.
The Monitor tab light and status label pulse between bright and dim amber
whenever any session needs input, approval, or a check. With nothing waiting,
they pulse green while at least one session is working and remain steady green
while the Codex runtime is healthy but idle. They turn red only when local
runtime health is observable and Codex is down, and remain dim while paused
or when runtime health cannot be established. Below,
every independent root session has a metrics box and its own graph.
Spawned-agent descendants with an explicit Codex parent link are recursively
aggregated into the root row and reported as
ROOT + n AGENTS. Each row compactly shows model calls and latest activity, latest/peak time to first token, and latest/peak output size. All graphs add one thin vertical block bar on the same 30-second tick, after a fresh boundary read. The companion readout records each account quota window at the current baseline and tracks its observed change while monitoring. Every session row shows its exact share of locally observed tokens and an explicitly labelled, local-only estimate of the first quota window's movement, apportioned by that share. A root discovered part-way through an interval gets an honestly labelled partial first bar and its rate uses that root's own observed lifetime. New bars enter on the right, older bars move left, and each Y axis automatically rescales to its visible samples. An open root or linked child whose latest durable lifecycle event says its turn completed receives an amberINPUT NEEDEDbadge and border until a new turn starts or the CLI closes. When Codexometer finds the default shared Codex app-server socket, it reads the server's per-thread runtime status and uses the exactwaitingOnApprovalandwaitingOnUserInputflags forAPPROVAL NEEDEDandINPUT NEEDED. If no shared server is available, an otherwise active open session with no new token or rollout activity for three minutes receivesCHECK SESSION: a deliberately uncertain prompt that can also mean a long-running local tool. Subsequent activity from the root or any linked agent clears the uncertain group-level warning. Codexometer never guessesAPPROVAL NEEDEDfrom inactivity. Closing the CLI releases its per-thread writer lock and clears every attention badge. A session already included in the current Monitor recording can remain as anIDLEhistorical row so its completed metrics and graph are not discarded. Click the themed[×]in a session metrics box to hide that row for the current run without closing or altering the Codex session. Codexometer keeps collecting its telemetry while hidden and restores the row automatically when tokens, model calls, turn timing, durable activity, or attention moves forward, or when an inactive session becomes active again. An alert already visible when[×]is clicked is dismissed with its row; a later new or changed alert restores it. Resetting the Monitor also restores every dismissed row. With the keyboard,Downinitially selects the top row,Upinitially selects the bottom row, subsequent arrow presses move the highlight, andxcloses the selected row. When the terminal cannot fit every root, use Page Up, Page Down, or the mouse wheel to page through the rows. Pause performs an immediate final local read instead of relying on the latest graph sample. Resume preserves the recorded totals while excluding tokens and elapsed time from the paused interval. - Benchmark — runs the selected scope from the active Core, Extended, or conditional DigBench suite, or the active suite's complete catalog, against the selected or complete set of compatible model/reasoning-effort pairs. Results arrive sequentially in a ranked table with task, outcome, wall time, tokens, and estimated standard API-equivalent cost. Filter the table to all, passed, or failed trials. Scroll a long result matrix with Page Up, Page Down, or the mouse wheel. Click any column-heading button to sort by that field; click it again to reverse the order.
The layout responds to both terminal dimensions and the number of rate limits
returned by Codex. Header, status, errors, footer, and meter grid divide the
available rectangle proportionally. Bars, Consumption Pace, and Fuel Tank flow
one meter per row. Codexometer does not hardcode the currently returned window
set: it renders every primary and secondary window from every limit bucket,
including a 300-minute window as 5 HOURS, plus an effective monthly credit
limit when present. When more limits arrive,
horizontal views remove decorative row gaps before compressing the cards, while
Pie adds rows or columns only when each radial card retains a useful width.
Meter rows always use identical heights; indivisible spare rows become quiet
space above the footer instead of stretching one quota block more than another.
Pie uses at least two columns when multiple limits exist, adding rows when that
preserves more radial detail and adding columns when the terminal is wide
enough. Consumption Pace calculates elapsed window % - quota used %, placing
under-budget consumption on the positive side and over-budget consumption on
the negative side. Its linear projection assumes the average burn observed
since the calculated cycle start continues unchanged: remaining time is
elapsed time × (1 - U) / U. It reports safe when the resulting exhaustion
time falls at or after reset, and hides the projection when timing is
insufficient. This is a trend estimate, not a backend forecast. Every Quota view
also shows a RESET CYCLE comparison:
its label and countdown occupy one line, while its progress bar occupies a
separate line with the same width and active colour as the main visualization.
Its percentage is elapsed time from the calculated window start
(reset - duration) to the next reset. When Codex supplies a monthly reset but
not a cycle start, the card says CYCLE START UNAVAILABLE, shows the known
countdown, and leaves the comparison bar unfilled. Every visualization
receives its card's remaining width and height, and resizing the terminal
immediately reflows and rescales it. The underlying values and reset information
never change with presentation.
The Monitor is deliberately separate from the percentage gauges: no token
ceiling is exposed for those quota windows, so a percentage-based bar would be
misleading. It follows the local token telemetry underlying Codex's live
thread/tokenUsage/updated
data, rather than the delayed account activity
summary. A separate process cannot subscribe to another Codex process's
app-server connection, so Codexometer incrementally observes the equivalent
token_count records written to local rollout files.
This is local activity telemetry, not account-wide billing data. It can combine
multiple sessions using the same local CODEX_HOME, but it cannot see Codex
activity on another computer, in a different Codex home, or in a cloud session
that is not writing locally. Token totals normally appear when Codex emits usage
for a model response, not token-by-token while a response is streaming. Raw token
counts also do not reveal or reproduce the backend's quota-weighting rules, so
they should not be converted directly into the percentage gauges.
Session rows represent recently active rollout roots plus open CLI sessions
waiting for input, not a guaranteed list of every terminal process. Two
independent CLI tabs have different root thread IDs and therefore remain
separate rows.
thread_spawn descendants,
including nested descendants, are folded into their root by following persisted
parent IDs. Review, compact, or other internal work that lacks an explicit
parent is never guessed onto a root; if observed, it appears in an
UNATTRIBUTED // INTERNAL row. When Codex records inherited child history, the
Monitor honors its ownership boundary so copied parent telemetry is not counted
twice. Legacy spawned-agent rollouts without an ordinal boundary are separated
at the child session timestamp: inherited cumulative totals establish the child
counter baseline but are not reported as new usage.
Attention detection reads only content-free lifecycle metadata, per-thread
writer-lock state, and—when available—the shared app-server's runtime thread
status. A held writer lock plus a completed turn reliably identifies an open
CLI waiting at its prompt. Without a shared server, three minutes without any
new rollout-file activity produces only CHECK SESSION, because persisted data
cannot distinguish an approval wait from every long-running local tool. The
Monitor does not retain the input question, approval text, response, or
conversation content. A linked child's attention state is folded into its root
so one remote Monitor row identifies the CLI session that needs intervention.
A definite approval signal takes precedence, then definite input, then the
inferred check state when linked members have mixed states. Because CHECK SESSION is only an inactivity inference, fresh activity anywhere in the group
suppresses a stale sibling's check; definite input and approval are never
suppressed this way.
CALLS counts upstream model-response cycles observed after the current Monitor
baseline, not complete user turns. A single Codex turn can make several calls while using
tools or progressing through an agent loop. LAST OUT is the provider-reported
output-token count for the latest such call. TTFT comes from the completed
turn's persisted time-to-first-token measurement; older Codex rollouts that do
not contain it display N/A. Spawned descendants contribute these pulses to
the same root row as their token activity.
The Monitor's per-session quota figure is an estimate, not API attribution.
Codex exposes account-level quota percentages and local per-session token
telemetry separately; it does not report which session consumed each percentage
point. Codexometer therefore multiplies the observed account-wide change by a
session's share of locally observed tokens. This assumes that no activity from
another computer, cloud session, different CODEX_HOME, or otherwise invisible
client changes the account quota during the recording; if it does, its movement
cannot be separated and will contaminate the estimate. Model choice, reasoning
effort, cache behavior, and private backend weighting can also make equal token
counts affect quota differently.
The UI calls this EST LOCAL-ONLY, uses percentage points (PP), and never
presents finer precision than the whole-number quota percentage returned by
Codex. NO INTEGER Δ means no whole-point movement was observed, not necessarily
zero consumption; a smaller apportioned estimate is shown as <1PP. Stale,
missing, late-baseline, and reset-crossing windows do not produce a per-session
number.
Starting, resuming, or resetting reads quota before establishing the local token
baseline, while Pause reads local tokens before the final quota snapshot, so the
account observation brackets each monitored segment. These operations are not
atomic, so unrelated account activity during either short boundary read remains
another source of uncertainty.
Codexometer stores only the selected theme, Quota view, benchmark filter, and benchmark ranking weight. No quota estimate or snapshot, raw session telemetry, benchmark result, message content, credential, session ID, email, account fingerprint, or account ID is written. The small JSON file uses the platform-standard user configuration directory:
- Linux:
$XDG_CONFIG_HOME/codexometer/preferences.json, normally~/.config/codexometer/preferences.json; - macOS:
~/Library/Application Support/codexometer/preferences.json; - Windows:
%AppData%\codexometer\preferences.json.
Missing, unreadable, or malformed preferences never prevent startup; Codexometer falls back to its safe defaults.
Important
Codexometer's benchmarks are intended for a person running the local client with their own Codex authentication and quota. They are not a way to convert a ChatGPT subscription into general API traffic, re-serve model access, or share one person's included usage with other users. Do not deploy a shared benchmark service backed by one person's subscription. You remain responsible for complying with the terms and policies of OpenAI and each external benchmark provider; this project cannot guarantee that guidance or enforcement will remain unchanged. If you choose to run a benchmark with Sign in with ChatGPT subscription authentication, you do so at your own risk.
The justification for supporting the prevailing Codex login is that OpenAI's authentication documentation expressly distinguishes Sign in with ChatGPT for subscription access from API-key authentication for usage-based access. OpenAI also documents Codex app-server as the interface for embedding Codex into another product, including its ChatGPT login flows. A public clarification from OpenAI's Codex and ChatGPT lead further says that using included subscription usage through Sign in with ChatGPT is fine in official or OSS clients; it identifies converting a subscription into API traffic for re-serving or sharing across users as the unsupported pattern. That post is useful operational guidance, not a contractual guarantee.
Codexometer stays on the client side of that boundary: it invokes the official local Codex app-server for the authenticated user, runs bounded user-triggered trials, and reports results locally. It does not expose an inference API, forward ChatGPT credentials, or offer another user access to the account. For unattended automation, CI, or a centrally hosted benchmark service, use an appropriately owned API-key-authenticated setup instead; OpenAI recommends API key authentication for programmatic Codex CLI workflows and the Codex SDK for automated jobs and CI. The separate DigBench token described below authorizes only DigBench and does not change how Codex itself is authenticated.
For a clearer billing boundary, supply your own OpenAI API key. A dedicated key takes precedence over the prevailing ChatGPT login for all benchmark model discovery and runs, including DigBench:
export CODEXOMETER_BENCHMARK_API_KEY="<openai-api-key>"
codexometerOPENAI_API_KEY is accepted as a fallback when the dedicated variable is not
set. Codexometer removes both variables from its normal child environment and
passes the selected value only in the documented account/login/start request
to a benchmark-only app-server. That server uses a temporary CODEX_HOME and
ephemeral in-memory credential storage, so it neither replaces the normal Codex
login nor persists the key. API-authenticated trials use standard usage-based
API billing; quota monitoring continues to use the prevailing Codex login.
Environment variables may still be visible to other processes running as the
same operating-system user, so supply secrets only on a trusted local machine.
Neither key is written to preferences or accepted as a command-line argument.
Codexometer includes an experimental integration for
DigBench, an external benchmark of discovering unknown
rules in interactive text games. Supplying DIGBENCH_API_TOKEN adds
DIGBENCH to the Benchmark tab's Suite selector alongside the always
available CODEXOMETER CORE and CODEXOMETER EXTENDED suites. At launch,
Codexometer calls
authenticated GET /games and uses every game name returned by DigBench; no
P-x catalog is compiled into Codexometer. Select the DigBench suite, open
Scope, and use its game, model, and reasoning-level checkboxes to check all,
clear all, or choose any subset. Run Scope executes every selected game
against every selected compatible model/reasoning-effort pair. Run All
executes every discovered game against every compatible pair. Both controls
display the exact remote-session count and require a second confirmation before
creating those sessions, because every game/pair invocation creates a persisted
remote session with a random seed.
Create a token from the DigBench token page (sign-in is a passwordless email link) and place it in the environment:
export DIGBENCH_API_TOKEN="<token>"
codexometerThe existing headless form remains available for a named exploratory game:
codexometer --digbench-game P-1The published Codex condition is the default: gpt-5.6-sol with high
reasoning effort. DigBench Scope labels both sides of that exact pairing, while
xhigh is identified as an enhanced Codexometer experiment and not a paper
condition. Codexometer allows two hours per game by default because
discovery runs can be substantially longer than ordinary coding benchmarks.
The headless form can set another finite boundary explicitly; for example:
codexometer --digbench-game P-3 \
--digbench-model gpt-5.6-terra \
--digbench-effort medium \
--digbench-timeout 12hThe command creates a fresh remote DigBench session, so invoking it is an
external write as well as a model run that consumes either Codex subscription
quota or usage-billed API tokens, according to the authentication choice above.
DigBench persists sessions and currently exposes no deletion endpoint. The
token is read only
from DIGBENCH_API_TOKEN, is never written to Codexometer preferences, and is
removed from the process environment before Codex is spawned. It is used only
by Codexometer's native HTTPS client to start the session. Codex sees only
session-scoped get_session and step tools, not the account token.
The game runs in one ephemeral Codex app-server thread with a writable temporary
workspace and no approval prompts. The model may use its normal local tools for
notes, matching DigBench's agentic-harness design, but its only game access is
the scoped dynamic-tool bridge. Step calls are safely retried using DigBench's
idempotent step_index protocol; session creation is never automatically
retried because that endpoint does not document idempotency.
The model-facing instructions retain Codexometer's session-isolation and useful
scratch-note guidance while following the agentic prompt published in the
DigBench paper. Codex receives the API's task
description, including any objective or special-action guidance that does not
reveal the rules, plus creative_toggle when the state supplies it. Every move
is explicitly an observe → reason → one-action cycle: Codex is told to wait for
and inspect the authoritative result before choosing another move, including
when deliberately testing a sequence. Tool results sent back into the model are
compact game-state slices so repeated session metadata and schemas do not crowd
out useful history. This compaction does not discard game observations, legal
actions, limits, transitions, progress, or creative-mode state. The derived
levels_beaten score stays in the operator-facing transcript and UI rather than
being supplied to the model.
In the TUI, each selected game run appears immediately in the existing result
table and can be opened while it is in progress. Its benchmark-only detail view
shows every Codexometer-authored developer instruction, the complete game prompt
with the session ID redacted, and the dynamic-tool definitions. It then presents
each game exchange as a sanitized Tool Request and full Tool Response,
followed by the concise Move and authoritative State representation, so
the solving workflow remains readable without losing protocol detail. The full
recorded response intentionally remains richer than the compact state returned
to the model. The final
model response completes the visible
Policy → Prompt → Tools → Tool Request → Tool Response → Move → State → Final Response
workflow. The Copy control exports that complete captured view. DigBench
session IDs, credentials, request headers,
temporary paths, local scratch-work commands, internal app-server context, Codex
platform instructions, and Codex reasoning are never included. Stop requests
interruption of the active Codex turn, retains the captured transcript, and marks
the row stopped.
The headless command prints the selected game, model, effort, and billing source before connecting. It then reports remote-session creation, Codex-turn startup, authoritative level/step/status updates after successful game-tool calls, and a content-free elapsed-time heartbeat every 15 seconds while Codex is working.
The final line reports WIN, LOSS, or INCOMPLETE, levels beaten, total game
steps, duration, tokens, and estimated standard API-equivalent cost. A win
requires the authoritative terminal combination done: true and
state.status: "completed"; game_over is a loss. Contradictory terminal
fields fail as a protocol error. DigBench assigns a random game seed and does
not currently accept a requested seed. Codexometer still assigns an
observed-run rank to completed DigBench rows, calculated independently from
Core and Extended results with the same correctness-first cost/time formula
described below. A win counts as a pass; a loss or incomplete attempt counts as
a failure; stopped rows remain unranked. Levels beaten, steps, and token counts
remain visible diagnostics but do not affect the rank.
This rank compares the attempts Codexometer actually observed; it is not a controlled or definitive model ranking. Different model/effort combinations may receive game instances whose difficulty varies with their server-assigned seed, and the API cannot currently pair combinations on the same seed. Treat a single run as exploratory, and use repeated runs with aggregate outcomes when drawing broader conclusions. Rankings shown while a suite is running are also provisional because combinations may temporarily have different numbers of completed games.
The Benchmark tab groups its built-in deterministic challenges into two always-available suites: CODEXOMETER CORE contains the original Easy and Moderate set, while CODEXOMETER EXTENDED contains the later Hard set. The Suite arrows therefore always switch between at least two choices. A third DIGBENCH choice appears when its credentials and launch-time catalog are available. The selector reserves a stable responsive track for the longest suite name, so its controls do not move as the selection changes.
Codexometer discovers models visible to the active benchmark authentication and
their supported reasoning efforts through model/list. Initially every
benchmark in each built-in suite and every compatible model/effort pair is
selected. Press s or click Scope to open a separate selection screen:
every benchmark in the active suite, model, and reasoning level has its own
checkbox, and each group has a Check All control that changes to Clear
All when the whole group is selected. Core and Extended retain independent
benchmark selections when you switch between them.
The supported reasoning levels shown beside each model dim immediately when
they fall outside the selected scope. Click a row, or use Up/Down and
Space/Enter, then click Done or press d/Esc to return. Unsupported
model/effort intersections are never counted or run.
Press b or click Run Scope to execute each selected benchmark against
every selected compatible model/effort pair. The button is enabled whenever
that scope contains at least one benchmark and one compatible pair, and its
label shows the resulting turn count. Run All deliberately ignores the
scope and executes every benchmark in the active suite against every compatible
model/effort pair. Codexometer displays that exact total and requires a second
confirmation within five seconds. A fresh, ephemeral, read-only app-server
thread is used for each built-in trial, so benchmark history does not clutter
normal Codex sessions. The turns still consume the same account quota shown by
Codexometer unless a benchmark API key is supplied; with a key, they use
standard usage-based API billing instead.
Each model/effort trial has a five-minute deadline. If an in-flight turn reaches
that deadline, Codexometer requests turn/interrupt, waits for the matching
turn/completed event, records that combination as FAIL, and continues with
the remaining combinations. App-server transport failure or failure to confirm
timeout interruption still stops the suite because the server's state is then
unsafe or unknown.
The Stop control remains visible but disabled until a suite starts. Press
x or click Stop to request turn/interrupt for the current trial and wait
for its matching completion before the temporary app-server is closed.
Completed results are retained, the current row becomes STOPPED, remaining
trials are not started, and the status reports how many planned trials were
complete. A stopped row is incomplete rather than failed, so it appears under
All but not the Fail filter or rankings. If remote interruption cannot
be confirmed before cleanup, the stopped result reports that uncertainty as a
Stop Issue.
The current trial appears in the existing Result Matrix immediately as an
IN PROGRESS row, before any result has completed. Click that or any completed
row, or use Up/Down followed by Enter, to replace the matrix with the
run's scrollable detail. An open live detail updates as safe benchmark events
arrive, then changes in place to the final PASS, FAIL, or STOPPED result. It shows the
requested and actual model, effort, task, outcome, live duration, token classes,
API-equivalent cost, exact benchmark prompt, visible structured response
(including the submitted Starlark), policy events, and deterministic-verifier
result. In the matrix, press c or click Copy at the lower right to export
a clean Markdown table containing only the eight column headings and every data
row. The export includes filtered and off-screen rows, retains the current sort
and rank weighting, and excludes the Show and Rank controls.
Esc returns to the same selected matrix row. Page keys, arrow keys, and the
mouse wheel scroll a long detail. With a detail open, press c or click
Copy at the lower right to copy the complete unstyled detail, including
interactions below the visible scroll window. Both copy actions use the
terminal's OSC 52 clipboard support, which is not available in every terminal.
This transcript is deliberately benchmark-only. It is populated directly by
the ephemeral thread that Codexometer created for that trial, bounded to 4,096
entries of at most 64 KiB each and 1 MiB total, retained only in process
memory, and discarded when a new suite starts or Codexometer exits. It does not
subscribe to or read ordinary Codex conversations, and it excludes reasoning
events, credentials, request headers, and internal app-server IDs.
Codexometer sends result data or that bounded transcript to the system clipboard
only when you explicitly press c or click Copy; the clipboard then falls
under your operating system and terminal's normal retention behavior.
Every trial asks the model to return one named Starlark function:
| Suite | Challenge | Difficulty | Required behavior | Verification set |
|---|---|---|---|---|
| Core | Merge Ranges | Easy | Sort inclusive integer ranges and merge every overlapping or adjacent pair into a canonical union. It must handle empty input, duplicates, nesting, negatives, and arbitrary order. | 8 hand-written edge cases + 48 reproducibly generated cases |
| Core | LRU Cache | Moderate | Process integer put and get operations, update recency, evict the least-recently-used entry, and return both get results and final entries in most-recently-used order. Capacity zero is valid. |
5 hand-written edge cases + 40 reproducibly generated cases |
| Core | Expression | Moderate | Evaluate tokenized non-negative integers with +, -, *, parentheses, normal precedence, and left associativity—without eval. |
8 hand-written edge cases + 40 reproducibly generated expressions |
| Core | Shortest Path | Moderate | Return the minimum four-direction move count through a rectangular blocked/open grid, or -1 when no route exists. |
5 hand-written edge cases + 40 reproducibly generated mazes |
| Extended | Dependency Scheduler | Hard | Find the minimum makespan for a small dependency DAG with job durations and a limited number of identical workers. Correct solutions must reason about precedence, concurrency, and cases where immediately starting every available job is not optimal. | 6 hand-written edge cases + 8 reproducibly generated DAGs |
| Extended | Version Resolver | Hard | Select one version per package while satisfying inclusive dependency ranges and exact conflicts, then return the lexicographically greatest valid solution. | 5 hand-written edge cases + 12 reproducibly generated catalogs |
| Extended | Event Processor | Hard | Reorder ledger events by sequence and apply idempotency, transfers, freezes, reversals, failure precedence, and a canonical audit result. | 5 hand-written edge cases + 10 reproducibly generated event streams |
The difficulty labels are documentation rather than part of the terminal names. Hard challenges deliberately combine more rules or require bounded search, which should create more separation between models and reasoning efforts than simply making the easier inputs larger.
The RANK column is an overall ranking for each model/reasoning-effort
combination across every completed row currently in the result matrix. It uses
ordinal cost and time positions—not raw dollars and seconds—so the distance
between first and second place on either axis is always one rank position,
regardless of the difference in the underlying measurements.
Rankings are isolated by benchmark provider: deterministic Core/Extended
results and randomized DigBench results are never combined. For DigBench,
PASS and FAIL in the algorithm below mean WIN and LOSS/INCOMPLETE, and
the seed disclaimer in the DigBench section applies.
The algorithm is:
-
Group completed rows by requested model ID and reasoning effort. A reported model reroute remains part of the requested combination that produced it.
-
For each combination, count passes and failures, sum non-negative wall time, and sum API-equivalent cost. Cost is complete only when every row in that combination has a finite, non-negative cost measurement.
-
Partition combinations into correctness tiers with identical pass and failure counts. Within each tier, rank combinations independently by ascending total cost and ascending total wall time. Equal measurements share a competition rank: for example,
1, 2, 2, 4. Every incomplete-cost combination ties on the cost axis after every cost-complete peer in its tier. -
Calculate a lower-is-better weighted score from cost rank
Cand time rankTaccording to the selected mode:Mode Formula Equivalent weighting Cost 3C + T75% cost / 25% time Balanced C + T50% cost / 50% time Speed C + 3T25% cost / 75% time -
Produce the final order lexicographically: more passes first, then fewer failures, then lower weighted score. Correctness therefore always dominates efficiency; a cheap, fast failure cannot outrank a combination with more passes. Combinations equal on all three comparisons share a competition rank.
Click Cost, Bal, or Speed in the Result Matrix control row, or press
w to cycle them. The ranking is recomputed immediately without rerunning any
trial. Token counts remain visible diagnostics but do not affect rank. The same
overall rank is repeated on each task row for that combination, and the rank
heading is clickable like the other sortable headings.
Missing cost is penalized on the cost axis, but it does not automatically force the combination to the bottom of the final table. A sufficiently strong time rank can still compensate in Balanced or Speed mode. If every combination lacks cost, they all tie on the cost axis and the final efficiency order is determined by time in every mode. If only part of a combination's cost ledger is missing, its known costs are not used to infer a partial position: the whole combination is treated as cost-incomplete.
Rankings update as results arrive, so they are provisional until a run finishes. Cost and time axes are recalculated among peers in the same current correctness tier. During a task-major Run All execution, one combination can temporarily have one more completed row than the others, so an in-progress rank should not be compared with the final result. They inherit the API-equivalent caveats below; in particular, unknown prices sort behind complete measurements on the cost axis and prompt-cache order can affect that axis. Correctness remains the dominant criterion.
There is no LLM judge and no subjective scoring. Codexometer loads the returned function into its embedded Starlark interpreter, runs every case for that challenge, computes the expected result with a separate Go reference implementation, and compares the values exactly. It also snapshots the input and rejects a solution that mutates it.
A row is PASS only when all of the following are true:
- the turn completes and returns the required strict JSON object containing Starlark source;
- the source loads, defines the correctly named callable, and stays within the 64 KiB source limit and the difficulty-appropriate per-case execution budget: 250,000 steps for Easy/Moderate challenges or 2,000,000 steps for Hard challenges;
- every hand-written and generated case returns the exact reference answer with the required type and bounded shape; and
- the turn does not emit a tool-use item; and
- none of the supplied inputs are mutated.
Any syntax/runtime error, timeout, malformed response, wrong type or value,
mutation, safety/size-limit violation, or failed case produces FAIL. The first
failure is retained as the row's diagnostic. The test data is deterministic, so
the same Codexometer version judges every model/effort combination identically.
Starlark is a deliberately small, Python-like embedded language. Every prompt
includes the same compact language contract—available statements and built-ins,
plus the absence of while, recursion, imports, load, and eval—to reduce
advantage from prior syntax familiarity. It cannot remove that advantage
entirely: these results measure algorithmic coding through Starlark and may
favor models stronger at Python-like languages. They are not a language-neutral
measure of general model quality.
Codexometer links the Starlark interpreter into the standalone binary and exposes no filesystem, process, network, clock, or environment capabilities to submitted code. Restricted return types and bounded result sizes add further containment.
Codexometer asks the local app-server for its opt-in rawResponse/completed
telemetry and, when a complete valid ledger is available, sums the exact usage
reported for each upstream response in the turn. Because that event is an
internal experimental Codex interface, older app-servers may reject or omit it;
Codexometer then falls back automatically to the final cumulative
thread/tokenUsage/updated value for the fresh one-turn thread. Both event types
are matched to the expected thread and turn IDs so activity from another trial
or Codex session is not included.
Before displaying either source, Codexometer checks that all token fields are
non-negative, cached plus cache-write input does not exceed total input,
reasoning output does not exceed output, total equals input plus output, and
cumulative updates never regress. When both complete raw-response and cumulative
telemetry are present, their totals must agree. A valid cumulative total can
stand in for an omitted raw usage payload; otherwise missing, duplicate, or
inconsistent telemetry displays N/A. It is never silently converted to zero
or clamped into a plausible value, and the status panel retains the reason.
The displayed total includes all reported input tokens—including cached input and cache-write input—and all reported output tokens. Reasoning tokens are already included in the output-token total and are not added a second time.
API EQ is an estimated standard text-token API equivalent,
not a bill, a ChatGPT subscription charge, or a prediction of how much account
quota the turn consumed. Codexometer separates ordinary input, cached input,
cache-write input, and output, then applies the per-million-token prices known
to this Codexometer release. Usage availability and price availability are
tracked separately: a valid token total can still have API EQ shown as N/A
for an unknown model or a token class whose price was not published when the
release was built. Codexometer does not inherit or guess such a price. Pricing
can change after a binary is released; consult the
official OpenAI API pricing page
for current values. The rates compiled into this version were retrieved from
that page on 2026-08-23; every pricing-bearing Quota or Benchmark footer
displays both the retrieval date and a terminal hyperlink to the source when
space permits, so stale embedded pricing is visible while interpreting results.
The figures are useful for comparing these particular observed trials, but they have important limitations:
- They do not reveal the private quota-weighting rules used by ChatGPT plans, and should not be converted into quota percentages or treated as dollars actually charged.
- Prompt-cache state can depend on earlier activity and benchmark order. A later trial may receive cheaper cached input or incur a cache write that an otherwise identical trial would not, so observed API-equivalent cost is not a cache-neutral ranking.
- When exact per-response usage is present, long-context price thresholds are
applied to each response independently. A cumulative-only turn beyond the
threshold displays
N/A, because its response boundaries cannot be proven. The raw event still does not associate a distinct model with each response. - If Codex reroutes a turn, usage is priced using the final reported model. A turn that actually spans differently priced models cannot be reconstructed exactly without a response-to-model association.
- Tool use is prohibited for these hermetic trials. If a tool-use item is
observed, the row is forced to
FAILandAPI EQisN/A, even when valid text-token telemetry was also reported. - Exact raw-response telemetry is an internal experimental app-server facility and may change independently of Codexometer. The validated cumulative path is retained for compatibility, but it does not preserve a response-by-response ledger.
- Model-specific Codex instructions and tool descriptions are part of reported input usage. That is appropriate when comparing the real Codex experience, but it is not a measurement of the challenge prompt in isolation.
PASS/FAIL evaluation is independent of these measurements: incomplete or ambiguous token telemetry does not make an incorrect program pass, and a valid program can still have an unavailable or approximate cost.
The measurement path is deliberately fail-closed. Its current hardening status is:
| Priority | Safeguard | Status |
|---|---|---|
| P0 | Distinguish missing telemetry from a genuine observed zero | Complete |
| P0 | Reject negative, inconsistent, regressing, or overflowing token data | Complete |
| P0 | Track token availability independently from price availability and retain the reason for N/A |
Complete |
| P1 | Prefer a validated per-response ledger, with a validated cumulative compatibility fallback | Complete |
| P1 | Detect prohibited tool-use items, force the trial to FAIL, and invalidate API EQ |
Complete |
| P1 | Apply the correct pricing tier to long-context responses | Complete for exact per-response telemetry; ambiguous cumulative-only long contexts fail closed |
| P2 | Reduce cache-order bias with balanced warm-ups, randomized ordering, or repeated trials | Open |
| P2 | Report a cache-neutral comparison alongside the observed cached cost | Open |
| P2 | Price mixed-model reroutes from a response-to-model association | Open; the current raw event does not expose that association |
| P2 | Record pricing-table provenance and make stale compiled pricing conspicuous | Complete; every pricing-bearing Quota or Benchmark footer shows its source and retrieval date when space permits |
| P2 | Add explicit compatibility diagnostics for future experimental-event schema changes | Complete for usage objects; unknown token fields fail closed and older servers retain the cumulative fallback |
Future accounting changes should preserve these rules:
- Never treat absent or invalid telemetry as zero, and never clamp malformed fields into a plausible value.
- Validate individual responses, overflow-safe aggregates, cumulative monotonicity, and raw-versus-cumulative agreement before setting usage as available.
- Keep correctness, usage availability, and cost availability as independent states. An unavailable price must not erase a valid token count, and a measurement problem must not change the deterministic Starlark verdict.
- Prefer exact response telemetry only when response IDs are present and unique; retain the cumulative path for compatible older app-servers.
- Do not infer prices for unknown models or unpublished token classes. Unknown usage fields must make costing unavailable. Update the compiled table only from published OpenAI pricing, and update its source retrieval date at the same time.
- Treat any tool-use item as a benchmark protocol violation. Text-token pricing alone cannot represent separately priced or externally executed work.
- Cover missing fields, invalid invariants, integer overflow, duplicate events, event regression, source disagreement, tool use, and experimental-protocol fallback in tests. Keep race-enabled CI green on Linux, macOS, and Windows.
Correct mixed-model reroute costing will require each upstream response to be associated with the model that actually served it. Cache-neutral or repeated-trial reporting would improve comparison quality without changing the deterministic PASS/FAIL verifier.
--codex PATH path to the Codex CLI (default: codex)
--check-auth verify the current Codex login and exit
--demo use simulated quota data
--inline render inline instead of using the alternate screen
--refresh DURATION refresh interval (default: 1m)
-v, --version print the version and exit
Examples:
# Refresh every 30 seconds
codexometer --refresh 30s
# Keep output in terminal scrollback rather than using a full-screen buffer
codexometer --inline
# Use a separately installed Codex build
codexometer --codex ~/bin/codexGoReleaser builds Linux, macOS, and Windows archives for AMD64 and ARM64 with
CGo disabled. Unix releases are .tar.gz; Windows releases are .zip; every
release also includes checksums.txt.
make release-snapshotThat local snapshot requires GoReleaser. Publishing is deliberately confined to
the Release GitHub Actions workflow: a semantic v* tag must resolve to a
commit reachable from main, pass the full Linux/macOS/Windows test matrix, and
remain unchanged between validation and publication.
Codexometer follows semantic versioning. The maintained source version lives in
internal/version/VERSION, and the release workflow
requires its Git tag to match. Go automatically embeds an exact tag in binaries
built with go install github.com/merefield/codexometer@vX.Y.Z.
The resolver uses the first version available in this order:
- a link-time value, such as the nearest Git description injected by
make build; - Go's embedded module version—an exact tag for a release build or, when Go
supplies one, a pseudo-version such as
X.Y.Z-0.<timestamp>-<commit>[+dirty]; - for a local checkout whose module version is
(devel), a VCS fallback in the explicit form<source-version>-dev+<commit>[.dirty]; - the maintained value in
internal/version/VERSIONwhen no build or VCS identity is available.
The leading v used by Git tags and Go module versions is removed in every
case. The VCS fallback is a Codexometer development identity, not a Go
pseudo-version.
The dashboard masthead, app-server client metadata, and both CLI flags all use that one resolved value. The flags report it and exit without starting the interface:
codexometer -v
codexometer --versionRelease automation can override the source-build fallback without editing code:
go build -ldflags="-s -w -X github.com/merefield/codexometer/internal/version.buildVersion=vX.Y.Z" .At startup and on each refresh, Codexometer:
- starts
codex app-server --stdio; - performs the app-server initialization handshake;
- requests
account/rateLimits/read; - renders every returned limit bucket and window;
- shuts down the short-lived app-server process.
Automatic refreshes occur once a minute unless --refresh changes the
interval. Pressing r refreshes immediately. If a refresh fails after valid
data has already been displayed, Codexometer retains the last snapshot and
marks it as stale instead of blanking the dashboard.
The Monitor starts with Codexometer and checks appended local token telemetry once per second while sessions are active, relaxing to once every five seconds when none are active. It groups explicit agent descendants under their root and rolls each root's observed deltas into synchronized graph buckets. It also updates the three compact response-cycle statistics without retaining response content. A bucket closes only after the boundary telemetry read completes; its heading reports the actual observed duration when scheduling or first-session detection makes it shorter or longer than 30 seconds. These reads do not contact OpenAI or invoke a model. On Unix systems, these reads also probe the default shared app-server control socket. Exact thread-status results are cached for five seconds to avoid repeating the same per-thread requests on every active poll. When present, its loaded-thread runtime statuses make attention badges exact; when absent or unreachable, Codexometer silently uses the local rollout and writer-lock fallback described above. Graph history is bounded to the latest 4,096 samples. Pressing Pause performs one immediate final local read and forces complete session discovery, including Codex sessions resumed from older rollout directories. Resume rebases counters so activity during the pause is excluded; Reset clears the measurement and graphs without changing the paused/running state.
Confirm that codex --version works in the same shell. Otherwise use
--codex PATH.
Run:
codex login status
codexometer --check-authCodex rate-limit data requires a ChatGPT-backed Codex login. An API-key login uses API billing and rate limits instead of ChatGPT subscription windows.
Use a terminal with true-color and Unicode support, such as Windows Terminal, the current macOS Terminal, iTerm2, or a modern Linux terminal. Ensure the selected font includes block, arrow, and emoji glyphs.
Codexometer adapts its header and meter widths, but rich gauges need enough
rows to display every quota window. Increase the pane height or press v in
Quota to return to the compact default Bars view.
The Monitor observes rollout telemetry under the same CODEX_HOME visible to
the Codexometer process. Confirm that the Codex session doing work is local and
uses that home. A native Windows Codex session and a native Windows Codexometer
normally share the same user profile; WSL and native Windows have different
homes unless CODEX_HOME is deliberately shared. Cloud activity and sessions on
other machines are not visible. Usage is generally appended after a model
response reports its token totals, so a currently streaming response may not
appear until its next telemetry event.
Format, test, and vet the project:
gofmt -w .
go test ./...
go vet ./...Measure test coverage:
go test -cover ./...Codexometer uses:
- Go 1.26.6+
- Bubble Tea v2 for the terminal event loop and declarative terminal modes
- Lip Gloss v2 for adaptive ANSI styling and layout
- Starlark for deterministic, hermetic benchmark-code evaluation
- Codex app-server JSON-RPC for authenticated quota data
- Local Codex rollout
token_countrecords for live Monitor telemetry
Codexometer is available under the MIT License.
