usage-limits
Running out of limit halfway through a job is a scheduling failure, not bad luck. The numbers are on disk before the work starts. Read them, size the job against them, and either commit to finishing or cut the job down until it fits.
1. Measure
node scripts/usage.js
Paths here are relative to this skill's own directory, not the project you are working in. Run them from there, or prefix them with the skill's path.
This works the same in Claude Code and in Codex. The host is detected from the
environment; add --host codex or --host claude if a machine has both
installed and the wrong one is picked. Everything below applies to both unless
it says otherwise.
It prints the real percentages and reset times from the CLI's own cache, plus a pace measured from the local session transcripts:
Window Used Resets in Left Turns left
5-hour 62% 1h 40m $46.0 ~88
weekly 75% 2d 4h $124 ~240 <- binding
Recent pace 15 turns in the last hour, $0.164 per turn, effort xhigh
Turns left is the number that matters. It is the remaining headroom divided
by what a turn has actually been costing over the last hour, on this account,
at this effort level. Add --json when you want the raw fields.
If it says no snapshot was found, run /usage once in Claude Code and try
again. That populates the cache the script reads. In Codex the equivalent is
node scripts/usage.js --refresh, which asks Codex itself for a live reading
instead of using the newest one it happened to write.
Left is money, so it only appears under Claude Code. Codex meters a share of
an allowance and never quotes a price, so its report has no money column and
its percentages are exactly what they say they are.
The last line names the plan (Pro, Max 5x, Max 20x, Team, Enterprise) and what it means for spending. Pro has the least room and the 5-hour window usually binds first; Max 20x rarely binds at all. Take that line into account before deciding how careful to be.
2. Size the job before starting it
Count the work in turns, not in tasks. A rough scale that holds up in practice:
| Work | Turns |
|---|---|
| Read and answer a question about existing code | 1 to 2 |
| One edit plus the check that it worked | 2 to 4 |
| A feature touching three or four files | 10 to 20 |
| Debugging something with an unknown cause | 15 or more, and unpredictable |
Then compare against Turns left and hold back a reserve. Reserve about a
fifth of the budget for landing the work: the test run, the commit, and the
handoff note. Work that gets cut off just before the commit is worth nothing,
so the reserve is not optional.
3. Decide, out loud
Tell the user which of these applies before doing anything expensive.
It fits. Say so with the number, then work normally. Do not slow down out of caution when there is room. Cheapness is not a virtue when the budget is not tight.
It fits only if nothing goes wrong. Say so, switch to low power for the run, and reorder the work so the valuable part lands first.
It does not fit. Say so in one line before starting, and name the wall-clock time the window resets so the user knows when the rest can happen. Then do the whole thing anyway, ordered so that being cut off costs as little as possible.
That is the part to get right, because the tempting move is the wrong one. Deciding on the user's behalf to do less of what they asked spends their request to protect a budget that expires regardless, and they did not ask for that trade. Scaling the work down is their call, not yours.
So take the whole request, and make a cutoff cheap instead:
- Order it so the most valuable part lands first.
- Save at clean boundaries as you go, rather than once at the end.
- Keep a short running note of what is done, what is next, and which files are mid-change, so stopping at any moment loses nothing.
Half a feature, committed and working, still beats a whole one abandoned mid-edit. The difference is that you get there by sequencing the work, not by refusing part of it.
The window resets first. If the reset lands before the budget runs out, the limit is not the constraint. Say that and stop optimising for it.
The budget line ages during a turn
The hook runs when a prompt is submitted, so the figures you were given are from the start of the turn. A message sent while you are already working does not fire it again: it arrives without a budget line, and the numbers you are holding are now older than they look.
The reading itself is kept fresh: the hook takes the same reading Claude Code
takes for /usage when the one on disk is older than three minutes, and the
mid-turn pulse does the same every two minutes through a long turn. So the
figures are as good as /usage at those moments. What no hook can do is fire
between them, and a burst of parallel agents can spend a great deal in the
gap: eight workflow agents once emptied half a 5-hour window in five minutes.
Spawn agents knowing that each fresh context re-reads what you already hold.
That matters most when it is the one thing you are about to assert. Re-check before saying a job fits, if any of these are true:
- the turn has run long, or through many tool calls
- more requests arrived while you were working
- other sessions are active, so the budget is draining without you
node scripts/usage.js --status
That is one cheap read of a small file, no transcript scan, and it costs far less than promising to finish something and stopping halfway. If you have no budget line at all this turn, you are mid-turn: use the last one you were given and treat it as a ceiling, not a reading.
When messages stack up
Every message sent while work is already running starts another turn, and every turn re-sends the whole conversation. Three follow-ups during one task can cost more than the task did.
So when several additions arrive while you are still working and the binding window is tight, say it once, then keep going:
I have got all three. While the weekly window is this tight, sending them together costs a good deal less than one at a time, so I will fold these in and carry on. Send the rest in one go if you can.
Four rules keep that from being obnoxious, and they matter more than the saving.
Ask once per stretch of work. A second reminder costs more goodwill than the tokens it saves.
Only when the budget is actually tight. With room to spare, asking someone to hold their thoughts is rude for no gain. Say nothing.
Never discourage a correction, a stop, or a bug report. Those are the messages that save the most work. Someone interrupting to say the approach is wrong has just paid for their own interruption many times over, and a rule that trains people out of that is far more expensive than the turns it saves. Only additive scope, the "also do X" and "and can you Y", is worth batching.
Never make it about you. The cost lands on their limit, not yours. Frame it as their budget, offer the saving, and let them decide. Then work. Do not stop to negotiate about whether to stop.
Credits
The Credits line in the report says what actually happens at the limit, and
the two cases need opposite handling.
Off. Work stops dead at the limit. Nothing spills over. This is the case to plan hardest around, because there is no way to buy your way through it.
On. The limit is a cost boundary rather than a hard stop, so a job that does not fit can still be finished, for money. Do not warn about the crossover yourself: Claude Code announces it and asks before drawing on credits, and repeating that only adds noise. Just factor it into the plan, and take the user's answer to that prompt as the decision.
Opening with the budget
Start every reply with one line saying where the budget stands and whether what was asked fits. The hook puts the numbers in front of you before the prompt, so there is nothing to go and look up.
When there is room, one line, then get on with it:
The 5-hour window is the binding one: 47% used, about 75 turns of headroom. This fits easily.
When it does not fit, that line becomes the plan:
The weekly window has about 22 turns left. That covers the parser change and its tests, but not the migration or the docs pass, so I will do the first two and leave the rest for after the reset at 09:00.
What makes the second one useful is the split, not the percentage. "78% used" is not something anyone can act on. "This fits, that does not, here is the order" is.
Keep it to one line unless the work genuinely does not fit. The budget note is a header, not a section, and it must never push the actual answer down the page.
Which window binds is about what stops you soonest, not what stopping costs. Those differ: a 5-hour window comes back in hours, the weekly one in days. So when a window that is not binding sits near its wall, say so and weigh it. The hook flags those. Running the weekly out to save a few turns of the 5-hour window is a bad trade even though the 5-hour is what runs out first.
The exception is a weekly that caps one model. weekly (Fable) at 88 per cent
is not your wall while you are working on Opus - nothing you do moves it, and
doing less work will not un-spend it. The report marks those not in use and
the hook leaves them out of what it asks you to weigh. Do not weigh them back
in. They matter again the moment you switch to that model, and that is when
they come back.
That cuts both ways, and the second half is the useful one: when the window that binds is a per-model weekly, the same work on another model draws on a different window. The report's Model headroom table says what the room left buys in turns of each model, priced from what that model has really cost here. Moving mechanical bulk onto a model with room is not doing less work - it is the same work against a wall that is further away, which is the one economy worth making. A model with no turn count in that table has only ever run as a subagent; its errands are not turns, so there is nothing to project from.
One thing to get right: quote the binding window, not the roomiest one. Two windows run at once and they are rarely in the same place. The turns of headroom and the reset time belong to whichever runs out first. Putting the other window's percentage next to those figures claims far more room than exists, and that is how a session ends mid-edit while the weekly number still looks comfortable.
Pricing the job before starting it
Size the work in turns using the table above, then price it:
node scripts/usage.js --forecast 15
That converts turns into points of each window using what turns have really cost on this account, and reports a range rather than a single number, because a turn that reads three files costs many times one that answers from context. The upper end is the honest one for a long run, since turns get dearer as the context grows.
Reach for it whenever the answer to "will this finish" is not obvious.
Closing with what it cost
The budget line opens the reply; the cost closes it. When a reply completes what was asked, or wraps up the session, end it with one plain line:
Spent this session: 48 turns, 3.1M tokens, about $12.40.
The figures come from the This session: part of the budget line, so there is
nothing to run. They are exact as of the start of this turn, and the Stop hook
prints the up-to-date figure to the user the moment you finish, so do not go
and re-measure for the closing line.
Three rules keep it useful rather than noisy:
- Finished work only. A progress note mid-task, a clarifying question, or a reply that ends with "shall I go on" is not the moment. The line marks a goal reached or a session wrapped up.
- One line, at the end. It is a footer, not a section, and it never replaces the recap of what was actually done.
- Plain text. No symbols, no formatting tricks. The number is the point.
The user can also ask any time with /usage-limits:session, or run
node scripts/usage.js --session last for the full breakdown and
--sessions for the history of recent sessions on this machine.
Budget modes
How hard this plugin leans, and what it costs to say it. Four modes, set by the user and read by every hook:
node scripts/mode.js # which one, where it came from, what it changes
node scripts/mode.js max # set it
node scripts/mode.js --list # all four, and the aliases
node scripts/mode.js --explain high # one mode's full record
| mode | one line |
|---|---|
max |
fewest tokens that can still finish the job: one terse line, readings every ten minutes, silent when nothing a decision depends on has moved |
high |
full capability, re-measured every two minutes mid-turn, and said only when the answer changes |
standard |
what the plugin does today, unchanged. The default |
off |
nothing injected at all; every hook returns before reading anything, including the end-of-reply tally |
Aliases: ultra, ultra-efficient, maxtoken, maxefficient map to max;
smart, high-efficient to high; efficient, token-efficient, default,
on to standard; none, quiet, silent, ignore to off.
normal is not an alias for either. To some people it means "the plugin
working as usual" (standard) and to others "the plugin stays out of the way"
(off) - opposite instructions, so a silent guess is wrong half the time. If
the user says "normal", ask which they meant and say what each one does. The
script answers the same way.
auto picks from how full the binding window is - standard under 50 per cent
used, high from 50 to 79, max at 80 or above - and always reports itself as
what it resolved to (auto -> max). It reads the snapshot already on disk
rather than scanning, because the mode has to be settled before anything
expensive runs, and with no readable window it stays on standard rather than
guessing. It never picks off: turning the plugin off is a decision a person
makes.
off means off, including at 100 per cent. That is deliberate. If the user
wants one line at the wall and nothing else, node scripts/mode.js off --guard 95
is it.
Two rules hold in every mode, and they are not negotiable:
- A mode never lowers the quality of the work. When things are tight you change the ORDER of the work, never the amount or the quality. The savings come from ceremony - speculative reads, re-reads, preamble, subagents nobody needed, workflows that cost more context than they save.
- The modes govern the agent plane only, and never write
settings.json.
Two planes, and the conversation between them
The user plane is settings.json (model, effortLevel), the /effort
and /model pickers, and lowpower.js. It is the user saying what they want
for themselves. It is theirs.
The agent plane is the tier actually running this turn, and the tier of everything this turn spawns. That is what costs money.
What is actually yours to move, stated exactly, because a claim beyond this would be a lie the user cannot check:
- The model on an
Agentcall is yours.model: "sonnet" | "opus" | "haiku" | "fable"on any Agent call, and it overrides both the agent definition and the configured default. It is ignored forsubagent_type: "fork", which always inherits the parent model. - Model and effort inside a
Workflowscript are yours, peragent()call:opts.modelandopts.effort(low|medium|high|xhigh|max). The host's own advice is to omitopts.modelunless you are confident, and to useopts.effort: 'low'for mechanical stages - so lean on effort rather than model when sizing what you spawn. - Your own model and effort are NOT yours to change mid-session. Nothing a
hook can emit changes them: there is no such field anywhere in the hook
output contract, and
PreModelSwitchcan only veto a switch someone else started./modeland/effortare typed by a person andCLAUDE_CODE_EFFORT_LEVELis read at launch. So say the exact command in one line and let the user run it. Never imply you changed it yourself. xhighandmaxare refused outright when thinking is disabled, so never point at either without that being true.
The two planes talk to each other, in both directions, through the conversation. The whole rule in one line:
You may RECOMMEND a user-plane change. You may MAKE one when asked. You may never make one unasked.
Recommending, when you do it:
- Evidence or silence. Cite a measurement - what this account has actually
measured, from
usage.js --recommend, the fit line in the budget briefing, orscripts/drift.js. "Recommended" with no number is nagging. - At most one per session, and none at all in
off. The plugin enforces this; do not route around it. - A declined recommendation is not raised again. When the user says no,
record it -
node scripts/mode.js --decline- and it is never volunteered again, in this session or any later one.--adviceshows what is pending. - Name the exact command, the plane it changes, and when it takes effect.
When the user asks you to change something, or says "change it back": read
node scripts/mode.js --history first, say out loud what you are reverting and
to what, then do it. Never infer a target that is not in the log. node scripts/mode.js undo reverses the last change the plugin owns and names it
first; for a change to the user's own settings it names the command and leaves
the file alone, because that plane is not the plugin's to write.
The surprise to head off, every time: a user-plane change does not move the
session already running. If the user says "turn low power on" and you do it,
nothing about this session changes - lowpower.js says so itself ("Applies to
new sessions. For the session you are in, run /effort X"). Relay that in your
own words whenever you make one, and the same in reverse: putting the baseline
back does not restore this session's tier either.
Bounds the user can set
node scripts/mode.js --floor sonnet/medium # never point below this, even in max
node scripts/mode.js --ceiling opus/xhigh # nor above it, even on the hard part
node scripts/mode.js --pin # do not self-switch at all: report only
Under --pin the plugin reports the gap between the baseline and what is
running and suggests nothing. Respect it in your own words too: report, do not
switch.
Stepping back up
The efficient modes are two-directional, and that matters more than it sounds. Having dropped to a cheap tier for a mechanical stretch, say so when the work turns hard again and point back at the baseline. A one-way ratchet down is how a long session quietly degrades, which is the thing the quality rule forbids.
4. Low power
Two halves, and the second one is the half that actually binds.
The setting:
node scripts/lowpower.js on # effortLevel -> low, old value saved
node scripts/lowpower.js on --effort medium --model sonnet
node scripts/lowpower.js off # restores exactly what was there
In a headless run (claude -p) there are no slash commands, so the script is
the only lever there.
effortLevel is what the /effort picker writes. Reasoning is billed as
output tokens, the most expensive tokens in the request, so dropping xhigh
to low is the largest per-turn saving available without changing model or
scope. The file change applies to new sessions; for the session already
running, /effort low takes effect immediately.
Choosing the level
Do not guess which effort or model the budget calls for; the report can say:
node scripts/usage.js --recommend # against the headroom in general
node scripts/usage.js --recommend 15 # against a 15 turn job
It weighs the binding window, the measured cost of a turn, and how much of
the output is actually reasoning, then names the posture (roomy, tight,
critical, or reset-first) and the exact commands. When there is room it says
to keep everything as it is, out loud, so cheapness never becomes a habit.
Add --json for the decision as fields.
The three levers it recommends across belong to different hands, and keeping that straight is the whole trick:
| Lever | Whose hand | When it acts |
|---|---|---|
/effort, /model |
the user's only | this session, immediately |
lowpower.js on (writes settings.json) |
yours, right now | new sessions, at launch |
| subagent model and effort | yours, freely | that dispatch, immediately |
The running session's own model and effort cannot be changed by any script or
hook: settings.json is read at launch and hook output has no model field. So
when the recommendation says /effort low, put that in front of the user as
one short line and keep working; do not wait on it. What can be done without
asking anyone is the other two rows: write the next session's settings with
lowpower.js, and send self-contained mechanical bulk to a subagent on a
cheaper model at low effort, which is a change of model that needs nobody's
permission. The cold start still costs (see references/tactics.md on
subagents), so delegate work that is big and mechanical, not quick questions.
One catch to know about: settings.json does not accept max, so a saved
effort level tops out at xhigh. max only survives through /effort or the
CLAUDE_CODE_EFFORT_LEVEL environment variable, and lowpower.js refuses to
write it rather than save a value the next session would silently ignore.
Do not take that on trust: the report measures it. Under the model table it says how much of the output was reasoning and what that cost, for example
Of that output, 74k was reasoning (40%, about $1.85), the part effort controls.
That share is the ceiling on what lowering effort can save, so read it before
deciding whether the saving is worth the loss of reasoning. Forty per cent of
output is worth acting on; four per cent is not, and turning effort down for it
would cost more in rework than it saves. The same figure covers reasoning asked
for per prompt, by ultrathink or any other means, because it is all the same
spend on the same meter and the transcript does not separate them.
The behaviour, which applies even at xhigh or max effort, because the effort setting does not control any of it:
- Think briefly on routine steps. Save the long reasoning for decisions that are actually hard to reverse.
- Send independent tool calls together in one message. Three calls in one turn cost one context resend; three separate turns cost three.
- Read line ranges, not whole files. Grep with a head limit. A 40k-token file read is not paid once, it is paid again on every later turn in the session.
- Never re-read a file to confirm an edit landed. The edit tool already failed if it did not.
- No subagents. A subagent starts cold and re-derives context that is already in this session.
- Nothing that was not asked for. No speculative refactor, no extra test, no drive-by cleanup.
- Fewer, denser turns. Narration between tool calls is output tokens spent on nothing.
references/tactics.md has the full list and the billing reasons behind each
one.
5. The wall is not the end of the budget: switch, do not stop
Before treating a full window as a reason to stop, check what kind of window it is. There are two, and only one of them is the account's budget.
- A per-model weekly (
weekly (Fable),weekly (Opus),weekly (Sonnet)) counts turns by that model only. It is not your budget, it is that model's. Lowering effort does not free a single point of it. Switching model retires it outright -/model opus,/model sonnet, ornode scripts/lowpower.js on --model <id>. Every other window carries on exactly as before. - A shared window (the 5-hour, the all-models weekly) follows the account
wherever the model goes, so a switch buys nothing. Here the lever is
effort:
/effort mediummeasured six times cheaper a turn than ultra on this account.node scripts/usage.js --recommendnames both levers with the commands.
The commands differ by host, and the wrong one does nothing. /model and
/effort do not exist in Codex. Under Codex, change the model and effort for
the task in hand through Codex's own controls; node scripts/lowpower.js on --host codex --effort low --model <id> only saves defaults for new sessions
and cannot change one already running. The budget line prints whichever
vocabulary the host it is running in actually understands, so use the command
it gives you rather than the one you remember.
Check the setting against the work, not against the window. Once there is evidence for it, the budget line tells you what your current effort actually costs against the cheapest level measured on this account - "ultra, measured at 6 times the cost of medium a turn (8 turns against 6)". It says this from the first prompt, at any percentage, because a mechanical hour at the top setting is waste at 10 per cent used exactly as much as at 80; the only difference is that at 80 somebody notices.
It cannot judge how hard your work is. You can. So when you see it, look at what is actually in front of you and reach for one of three levers, saying which in one line. Two of them are yours to pull; the first is not.
- Drop the effort for that stretch - a rename, a docs pass, running tests,
applying a fix you have already worked out.
/effortandsettings.jsonare the user's own baseline, so this one you offer: name the command, say why the stretch does not need the tier, and leave the pulling of it to them. - Hand the stretch to a cheaper model. Your own model is the user's setting
too, so say that in one line rather than switching - but the model on
anything you SPAWN is entirely yours: an Agent call takes a model, and a
Workflow's
agent()takes a model and an effort. Size those to the stage. - Do less of it at this setting - a fan-out multiplies the setting across every agent, so six agents at ultra is six ultra turns, not one. Yours.
Put it back when the work gets hard again. The question is asked once per setting per session, not every prompt, and never at all unless there is a real measured comparison behind it - a ratio from a price list would have you drop effort on a hunch and call it evidence.
This is worth raising early, not only at the wall. Say it whenever the current setting is dearer than the work in front of you needs, long before any window is tight: a mechanical rename, a docs pass or a mass find-and-replace does not need the model and effort a hard design decision does. An agent that only ever reads this as a wall notice runs every trivial turn at the top setting and then wonders where the window went.
And "offer it" is one line, not a stop. Naming the lever and carrying on is the whole action. Waiting for an answer before doing the work would cost more than the tier ever did.
The budget line does this arithmetic for you. Once the binding window is half gone it says which lever applies, and at the wall it says outright that you are not out of budget and must not stop as though you were. When it does, the sequence is: say in one line which command frees it and why, and carry on with the whole request at full quality. A per-model weekly is not the account's budget, and treating it as one is the error.
This is written down because it was got wrong. A session ended with the Fable weekly at 89 per cent and the line saying the budget was nearly gone - while the 5-hour sat at 46 and every other model on the account was untouched. One command would have carried it on, and naming that command costs a line. Stopping there was not caution; it was quitting with a reason that sounded like one.
Only when the switch is genuinely unavailable - no other window has room, or the user has ruled it out - does the checkpoint below apply.
6. Checkpoint before the wall
When the binding window is under roughly 10 percent, or under about ten turns of headroom, keep working and start keeping the work landable:
- Commit or otherwise save the working state, at every clean boundary rather than once at the end.
- Keep
HANDOFF.mdcurrent as you go: what is done, what is next, which files are mid-change, what the next session should read first. - Say when the window resets, as a clock time and not just a duration, plus what to run on the way back in.
The point of the handoff is that it costs almost nothing and removes the reason to stop early. With one in place, being cut off loses a turn instead of an afternoon, so there is no longer anything to buy by winding down.
The one thing not to economise on is the handoff itself. Everything else can be picked up next session; a session that ends without one cannot.
7. The relay: when the handoff picks itself up
If a relay is armed, the budget line says so, and the shape of the last hour changes. The handoff stops being a note for a person to find and becomes the prompt this conversation will be handed back a few minutes after the window reopens. So do not wind down, do not narrow the request, and do not stop to ask whether to carry on — write the continuation properly and keep working until the window actually ends.
Write it with:
node "$CLAUDE_PLUGIN_ROOT/skills/usage-limits/scripts/relay.js" note "<text>"
Write it to be acted on, not read: what is done, what is next in order, which files are mid-change, what must be verified before anything is built on it. It is delivered as a prompt, so an instruction beats a summary. If nothing is written, the relay falls back to the outstanding todo list, which is worse.
The relay is off unless the user turned it on, and it only arms while there is an unfinished todo list or an approved plan to carry. Do not turn it on for them, and do not promise behaviour it does not have:
- It cannot type into a terminal or an editor. Computer Use refuses to send input to a shell on purpose; the relay uses it only to tell whether somebody is at the keyboard, and to show a banner.
- In
notifymode — the default — it raises a notification and starts nothing. - In
resumemode it runs the CLI itself. A headless resume does not inherit the session's permission mode, so unless one was set the resumed run will sit waiting for an approval nobody is there to give. - Claude Code's own
autoContinueAtUsageLimitis better wherever it applies, because the process never dies. It does not apply to-pruns, background sessions, or a terminal that has been closed.
node scripts/relay.js with no arguments reports all of it.
Voice
The plugin keeps a small local profile of how the user writes — counters, plus at most two short lines of their own text — so that anything written as them sounds like them. It costs no model call and never leaves the machine.
Two separate things live there and they are not the same:
- The learned traits are for writing as the user. Today that is the relay prompt. Do not imitate them in your own replies.
- The instruction they typed at
/usage-limits:voice setis how they want to be talked to. It appears in the budget line and it applies to you.
If asked what it knows, run node scripts/voice.js and read it back verbatim,
including the kept lines. forget deletes it outright.
Codex, seen from Claude Code
When Codex is installed on the same machine, every display shows its meter
underneath Claude's: the panel, the status line, the budget line before each
prompt, the VS Code view and check. It is read from the rollouts Codex has
already written — no child process, no network, and nothing at all if Codex is
not installed.
It counts the other way, and that is not a bug. Codex writes what it has spent but shows what is left: its own status card prints "82% left" where Claude Code prints "62% used". So the Codex rows report what remains, their bars drain as they are spent where Claude's fill, and every figure carries the word "left" so the two can never be read as the same kind of number. The colours turn at the same real moment either way — 80% used is 20% left is yellow, 90% used is 10% left is red.
There is no mark beside it, only the word "Codex" in OpenAI's green. Codex has no mark of its own — it uses OpenAI's Blossom, and there is no Blossom codepoint in Unicode, so a terminal cannot draw one. The nearest rosette is a flower, and a flower in the slot where a logo should be is not the logo; the word is unambiguous and cannot come out as something else in a font that has never heard of it.
Running under Codex
One difference that matters for the budget modes. Every entry in Codex's
hooks.json carries an additionalContextLimit - a per-hook cap on how much
context a hook may inject, which Claude Code has no equivalent of. A long
briefing can therefore be truncated there without a word. If a line looks cut
off under Codex, that is why: node scripts/mode.js max keeps it to one line,
and high is the verbose one.
Everything above works the same. The numbers come from a different place and one thing about how they arrive is different, and both are worth knowing.
Codex writes its session rollouts to ~/.codex/sessions, one JSON object per
line, and every model request appends a record carrying both the account meter
and what that request cost in tokens. So the two things this skill needs, the
percentages and the pace, come out of the same files. Nothing is sent anywhere
and no credentials are read.
node scripts/usage.js --host codex
node scripts/usage.js --host codex --refresh
--refresh asks Codex itself for a live reading instead of the newest one it
happened to write. It starts a short-lived codex app-server, takes about a
second, and is the Codex equivalent of running /usage in Claude Code. Use it
when the report says the snapshot is old, not routinely.
The difference that matters: the budget line is not automatic until you say
so. Claude Code lets a plugin ship hooks, so it gets one on install. Codex
does not load hooks from a plugin (plugin_hooks is a removed feature), and it
runs the ones in ~/.codex/hooks.json only after a one-time review it shows
when codex starts in a terminal: "Hooks need review - Trust all and
continue". The desktop app never shows that review, so a machine using only
the app can have the hooks installed for weeks and never run them once.
install-codex-hook.js status says whether they have ever run.
What replaces it is an instruction, installed by:
node scripts/install-codex-hook.js on
That writes a marked block into ~/.codex/AGENTS.md saying to run the report at
the start of a substantial piece of work, and it stages the hooks for the build
that runs them. status says what is installed, off removes both, and neither
touches anything else in those files.
So under Codex, read the budget deliberately rather than waiting to be told it. Once at the start of a piece of work, and again if the job grows or starts looping. The rest of this skill applies unchanged.
The report has no money column under Codex. Codex meters a share of an
allowance and never quotes a price, so the percentages are exactly what they
say and there is no dollar figure to attach. scripts/lowpower.js is for Claude
Code only: it writes Claude's settings.json, so it must not be run under
Codex. Change model or effort through Codex's own controls instead.
The effort setting is the thing that empties the window
On Codex this matters more than anywhere else, because the reasoning effort is
set in ~/.codex/config.toml and then applies to everything until it is
changed:
model = "gpt-6-astra"
model_reasoning_effort = "ultra"
A percentage and a turn count do not warn you about that, and it is the single
most common way an allowance disappears. The headroom figure is built from what
a turn has cost on average, and the average is dominated by whatever effort
you were running last week. Move to a dearer one and every estimate is too
generous until enough expensive turns have landed to drag the average up — and
on a five-hour window on Plus there is no "enough", because the window is gone
first. One ordinary task at ultra on Astra can take the lot while the report
still says there is room.
So the report measures each effort separately and prices the window at the one actually set. Two things surface it:
node scripts/usage.js --host codexprints what each effort costs, measured on this machine — turns, output written per turn, and a*on the one in force.- When the current effort is materially dearer than a cheaper one on record, the budget line says so outright, with what the window really holds at this setting rather than at the blend.
The comparison is on output tokens per turn, not cost per turn. Cost per
turn mostly tracks how big the context happened to be — measured that way,
low turns on a huge context can look dearer than ultra ones on a short one,
which is exactly backwards. Output is the part the effort setting controls.
Act on it the same way as everything else here: keep the high effort where the work genuinely needs the thinking, and drop it where it does not. It changes what every turn costs, not how many turns you get.
When to skip this skill
Do not run the report on every prompt. Once at the start of a long piece of work, and again if the job grows or something starts looping. The report costs a turn, which is the thing it is trying to save.
The panel (scripts/panel.js --open, or /usage-limits:panel) and the status
line (scripts/statusline.js on) are for the person watching, not for you.
Nothing in them changes what you should do, and they draw from the same
reading the budget line already gave you, so do not open or install them
unless asked. When asked, run the command, say in one line what it did, and
stop.
Files
| Path | What it is |
|---|---|
scripts/usage.js |
The report. --json for raw fields, --status for a one-line readout that skips the transcript scan, --forecast N for what an N turn job would cost, --sessions for what recent sessions cost, --session last (or an id) for one session in full, --host codex to read Codex's limits, --refresh to ask Codex for a live figure. |
scripts/brief.js |
What the hook runs before each prompt. Not meant to be called by hand. |
scripts/pulse.js |
What runs after tool calls, to re-check the budget during a long turn. Not meant to be called by hand. |
scripts/stop.js |
What runs after each reply: shows the user what the reply and the session have cost. Not meant to be called by hand. |
scripts/sessionend.js |
What runs when the session closes: the closing line, and the session marked closed in the history. Not meant to be called by hand. |
scripts/tally.js |
The running per-session total behind those two, kept in usage-limits-sessions.json and read incrementally. |
scripts/host.js |
Works out which agent this is running inside, so one host's percentages are never reported against the other's turns. |
scripts/codex.js |
The Codex reader: the meter and the pace out of ~/.codex/sessions, plus the live --refresh call. |
scripts/install-codex-hook.js |
status, on, off. Installs the Codex-side instruction, which Claude Code does not need. |
scripts/mode.js |
The budget mode: no arguments to report it, max/high/standard/off to set it, auto, off --guard 95, --list, --explain <name>, --floor/--ceiling/--pin, `- |
…(truncated)