acpmux: a Codex chat's plan usage limits (5-hour, weekly, credits) are its usageLimits, as a Claude chat's
Leo, 2026-11-04: "are we able to disable the context thing on the bottom right? i want to be able to right click disable it. what's its name?" and "likewise, i guess we can turn that into a 5h/weekly usage type thing instead as well for some people. i suppose it'd be relevant sometimes for SOME people to have that surfaced e.g in their session info thing."
References: Codex's ring popover ("Usage source: Your Pro plan / Weekly limit 10% left / Credits 56,766 credits / Manage usage") and Claude desktop's ("Plan usage limits 路 Ultra / 5-hour limit Resets at 10:00 PM 22% / Weekly 路 all models Resets Mon 3:00 PM 41%").
This is the acpmux half: the data. The composer ring's plan-usage mode, its popover and the Session Info section come in a follow-up web PR that reads this.
What changed
- A Claude chat already kept its plan limits as the session detail's
usageLimits(claude_stdio/usage_limits.rs, from Claude Code'srate_limit_event). A Codex chat now does too:codex app-server'saccount/rateLimits/updated, which cmux-codex-acp passes on as_meta.codexAppServer.rateLimits, is normalized (codex_app_server/usage_limits.rs) into the same shape:{windows: [{id, usedPercent, resetsAt?, windowMins?}], plan?, credits?}. The 5-hour window issessionand the weekweekly, as Claude's; any other length is named by its minutes.planis Codex'splanType;creditsis{balance}or{unlimited: true}, only when the account holds some. - Nothing reported is nothing (no window and no credits gives no
usageLimits), never a 0%. A snapshot for another limit id thancodexis not the plan's and is ignored. - Workflow activities treated any reported
usageLimitsas "waiting on a limit". Every Claude Code chat reports limits, so its activities were always held as waiting, and Codex chats would now be too. They now read a limit as reached only when a window is used up (usage_limit_reached: a window at 100%). - No new reads, no scraping, no new auth: only what the harness already sends.
Tests
codex_app_server::usage_limits_tests(normalizer: Pro 5h+weekly+credits, weekly-only with unlimited credits, other window lengths, nothing reported is nothing, credits alone).claude_stdio::usage_limits_tests::only_a_used_up_window_is_a_limit_reached.hub_integrationcodex_usage_limits::a_codex_chat_keeps_its_accounts_usage_limits: the fake app-server ("codex-limits") sends two updates in a turn; the session detail holds the newest, and a chat with none has none.
Red: 6455e4f (tests only; the normalizer and helper do not exist). Green: the head.
Observed / Not run
- Observed: the focused tests through the fleet runner on this PR's head (results in a comment below).
- Not run: a live Codex session against a real account in a DEV build (comes with the web PR's verification).
Changelog
none (the data is shown by the follow-up web PR)
Agent session: agent session
馃 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith 路 Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Makes a Codex chat's plan usage limits (5-hour, weekly, credits) available as its usageLimits, matching how a Claude chat's are kept, so the composer ring and Session Info read one shape for both.
- Normalizes Codex's
account/rateLimits/updated, passed on by cmux-codex-acp as_meta.codexAppServer.rateLimits, intousageLimits: the 5-hour window becomessessionand the weekweekly, plusplanandcredits. - Nothing reported is nothing (never a 0%), and snapshots for a limit id other than
codexare ignored; an empty plan snapshot clears the limits saved so far. - Workflow activities now treat a limit as reached only when a window is used up (100%) and has not reset; every Claude Code chat reports limits, which previously held its activities as waiting.