Expose rate-limit reset times, balance, plan as status_line tokens
Summary
The CLI status_line exposes five-hour-limit and weekly-limit as percentages only. The underlying rate-limit data is richer — account/rateLimits/read returns resetsAt, windowDurationMins, credits.balance, planType — but those fields aren't reachable via status_line tokens.
Missing tokens (as of 0.133.0)
five-hour-limit-reset— formatted local time ofprimary.resetsAtweekly-limit-reset— formatted local time ofsecondary.resetsAtcredits-balance—credits.balance(e.g.$766.76) whencredits.hasCredits && !credits.unlimitedplan-type—planType(e.g.prolite)- (optional)
rate-limit-window-primary/-secondary—windowDurationMinsformatted
Use case
Mirrors Claude Code's statusline which shows percentage + reset time. Without reset times the bare percentage is hard to act on — "5h 80%" doesn't tell you whether you have 10 minutes or 3 hours of breathing room. With it:
... · 5h 80% @11:36pm · weekly 83% @5/27 5:40am · ...
Workaround
Spawn codex app-server from outside, JSON-RPC handshake, call account/rateLimits/read, parse, render. Works but adds ~3-5s subprocess startup per query and requires users to build their own caching layer. The data is already there inside the running CLI; surfacing it as a token is a small change.
Verified data shape (0.133.0)
account/rateLimits/read returns:
{
"rateLimits": {
"limitId": "codex",
"primary": { "usedPercent": 25, "windowDurationMins": 300, "resetsAt": 1779459394 },
"secondary": { "usedPercent": 18, "windowDurationMins": 10080, "resetsAt": 1779826837 },
"credits": { "hasCredits": true, "unlimited": false, "balance": "766.76..." },
"planType": "prolite",
"rateLimitReachedType": null
},
"rateLimitsByLimitId": { ... }
}
Acceptance
Adding these to the existing config:
status_line = ["model-with-reasoning", "codex-version", "context-remaining",
"five-hour-limit", "five-hour-limit-reset",
"weekly-limit", "weekly-limit-reset",
"credits-balance", "project", "git-branch"]
Produces:
gpt-5.5 high · 0.133.0 · Context 28% left · 5h 25% @11:36pm · weekly 18% @5/27 5:40am · $766.76 · self-service-workbench · main
Thanks for the great CLI.
10 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Two related UX observations from building a workaround:
1. TUI rate-limit display doesn't auto-refresh
The
StatusRateLimitStatein the TUI updates only when:rate_limits)account/rateLimits/updatednotification firesThere's no periodic poll. For long-running idle sessions, the displayed values freeze at whatever was last seen until the user sends a new prompt.
Concrete impact: open a Codex session at noon when 5h is at 50%, work for 4 hours, idle for 1 hour. The 5h window has now rolled past your earlier usage and you genuinely have ~95% headroom again, but the TUI keeps showing 50% until you next prompt.
Would be helpful if either (a) the TUI polled
account/rateLimits/readon a slow cadence (e.g. every 5 minutes when idle), or (b) thestatus_linetokens proposed in the issue body got auto-refreshed independently of TokenCount events.2.
usedPercentvs displayed-remaining naming mismatchThe API field is
RateLimitWindow.usedPercent(inaccount/rateLimits/readandTokenCountEvent). The TUI display shows100 - usedPercent("5h 94%" when 6% is used).This is a footgun for anyone integrating against the data. Either:
remainingPercentfield to the API response so integrators don't have to do the conversion (and don't display the same number with opposite meaning by accident), orwindowUsedPercent).Burned about an hour debugging an apparent mismatch between an external integration showing
usedPercentand the TUI showing remaining; both were live and correct, just inversely framed.Thanks again.
On the
usedPercentvs displayed-remaining footgun, which is a real one: I builtaistat, and callingaccount/rateLimits/readfrom outside the CLI I hit the same trap, so it emits both fields rather than picking one.It surfaces most of what you listed — both reset times (
primary/secondary.resetsAt), the plan (planType), and used + remaining percentages, recomputed againstnoweach call. Two caveats: it doesn't exposecredits.balancetoday, and the window duration shows up as the window label (five_hour/seven_day) rather than a rawwindowDurationMins. Human view:and the full JSON:
reset_after_secondssidesteps the "freeze at last seen value" problem — recomputed againstnowon every call, so any polling cadence gives a fresh "in N minutes" string. 90s file cache makes aggressive statusline refresh safe. Same binary covers Claude/Copilot.https://github.com/drogers0/aistat
Adding another user data point: the current statusline can show
5h 60% left · weekly 84% left, but it still does not show the reset timestamp for either window. That makes the percentages hard to act on because 60% left is very different if the 5h window resets in 10 minutes versus several hours. This is a pretty important usability gap for terminal-first users; the Claude Code ecosystem already has many statusline plugins that show usage together with reset timing, so users coming from that workflow expect this information to be visible directly in the CLI footer. Adding the reset time next to each existing limit token, for example5h 60% left (resets 14:30)andweekly 84% left (resets Mon 03:00), would make the current tokens much more actionable.+1 to @Jasonzh8 ’s point. The current statusline percentages are useful, but without reset timing they’re hard to act on.
Adding one macOS-side data point: I built Agent Island because I wanted the same reset/usage information visible without keeping a Codex TUI focused.
https://github.com/tristan666666/agent-island
It reads Claude/Codex usage + reset state and puts it in the MacBook notch. It also shows per-session state (
running,waiting for you,stuck) and can auto-resume a selected long session when it can continue.Still +1 for native
status_linetokens. External UI/CLI workarounds are useful, but the source of truth should be easy to surface from the running Codex client.the token split reads clean in config but it leaks the moment the 5h window rolls between two status_line refreshes. five-hour-limit and five-hour-limit-reset get rendered on separate ticks, so you can briefly show 80% next to a resetsAt that already fired, which is exactly the case the reset time was supposed to fix. they both come off one rateLimits/read snapshot, so the fix is reading usedPercent and resetsAt from the same fetch and rendering them as one unit, not two independent tokens that can desync.
we hit the same desync reading claude's quota off the same endpoint settings/usage renders, ended up pinning percent and resetsAt to one fetch: https://claude-meter.com/r/kqh8mw3f
@m13v agreed. For usage/reset display, separate tokens are nice for composability but dangerous if they are evaluated independently.
The safer API shape is probably a compound token or structured statusline field rendered from one
rateLimits/readsnapshot, for example:five-hour-limit-status->{ usedPercent, remainingPercent, resetsAt, resetAfterSeconds, windowDurationMins }weekly-limit-status-> same shapeThen the renderer can choose text format, but the data stays atomic. It also lets clients avoid the "reset just fired but percent is from the previous window" problem by comparing
checked_at/resetsAtfrom the same sample.For external monitors, this same rule matters: percent, reset time, and plan/window metadata need to be pinned to one fetch, cached together, and invalidated together.
Adding my voice as a paying ChatGPT subscriber. The official Codex pricing documentation still says local messages and cloud tasks share a five-hour window, with additional weekly limits potentially applying. However, the current
/statusoutput does not show the five-hour reset time, so users cannot tell when that included allowance refreshes or reliably distinguish the five-hour and weekly limits.Please restore clear visibility of both quota windows in
/statusand the status line, including:If the five-hour allowance has been removed, reduced, or replaced by a weekly-only system for any accounts, OpenAI should state that plainly and notify affected subscribers before the change. Hiding or omitting reset information materially reduces transparency and the value of a paid subscription.