Skip to content

Releases: ridelink0/claude-code-usage-limits

1.41.1: no test registers a real scheduled task

Choose a tag to compare

@ridelink0 ridelink0 released this 28 Sep 00:52

Task Scheduler is machine-wide, so a test or a sandboxed run with a fake home used to be able to book real relay wakes (8 were registered by an adversarial run on 2026-09-25, two for a live session). Every registration and cancellation now goes through one switch: a dry run under node --test, with USAGE_LIMITS_SCHEDULER=dry-run, or when the home folder is redirected; USAGE_LIMITS_SCHEDULER=real overrides. A dry run registers nothing and says why. A guard test re-creates the incident outside the test runner and checks that Windows lists no task. 944/944.

1.41.0: one relay, one terminal

Choose a tag to compare

@ridelink0 ridelink0 released this 28 Sep 00:07

A relay wake now puts exactly one terminal on the screen.

  • The wake's own console has no window. The scheduled task used PowerShell's -WindowStyle Hidden, which Windows Terminal (the Windows 11 default console host) ignores, so a stray powershell.exe window opened beside the Claude window, and closing it killed the wake. The task now runs under conhost --headless (Windows 10 1809 and later; older builds keep the PowerShell route). Verified with a real scheduled task: one window, the session.
  • No second window beside an open session. If the session the relay was armed for is still open (checked through Claude Code's per-process session files, pid and start time) and working again since the reset, which is what Claude Code's own "Continue automatically at usage limit" does, the wake stands down. An open session that stays quiet gets three minutes, then the one window. Codex relays are unchanged.
  • The brief says this, and says that the CLI does not continue a session that stopped at a cap.

937/937 tests; no temp folders left behind.

1.40.5 - everything since 1.19.0

Choose a tag to compare

@ridelink0 ridelink0 released this 26 Sep 05:59

Everything since the last Release, v1.19.0. These 34 versions were tagged but not published as GitHub Releases. The project keeps no CHANGELOG, so this lists the commits in each version, newest first.

  • v1.40.5
    • The tier line names the running version, and a newer cheaper sibling is offered once a session
    • Opus 5.5 is priced from its own row, and model ids parse into family and version
  • v1.40.4
    • The session reset is not offered while the user has said low-priority is on
    • /limit-reset is read from the flag this account really carries, and each kind is worded in its own terms
    • Low-priority: the record lapses, a failed write is never reported as saved, and the brief names the user as the one who types it
    • The wake's network preflight is a dependency, so its tests no longer need the internet
  • v1.40.3
    • A deferral to a 5-hour reset now says that waiting for it buys nothing
  • v1.40.2
    • None of Claude Code's wall features are Codex's or Antigravity's
  • v1.40.1
    • The snapshot test asserted the wrong thing, and this machine hid it
  • v1.40.0
    • Written down: which of Claude Code's wall features are readable, and which are not
    • /low-priority, and the rest of what Claude Code does at the wall
    • The temporary directories the test suite makes are gone when it exits
  • v1.39.6
    • The temporary files a refused rename or a killed hook left behind are gone
  • v1.39.5
    • 1.39.5 - the hook's ten seconds are counted from when the hook started
  • v1.39.4
    • 1.39.4 - the headroom the brief prints is the one it judges
  • v1.39.3
    • 1.39.3 - Codex and Antigravity read their own budget again
  • v1.39.2
    • 1.39.2 - a POSIX relay registration is bounded by the hook's time
    • A POSIX relay registration is bounded by the hook's time, not twenty seconds
  • v1.39.1
    • 1.39.1 - CI green on all three systems, so npm publishes again
    • CI is green on Linux, macOS and Windows again, so a release can publish
  • v1.39.0
    • 1.39.0 - the ceiling judges the window this session can spend into, and names it
    • The ceiling judges the window this session can spend into, and names it
  • v1.38.0
    • 1.38.0 - a session on an older plugin than the one installed hears so once
    • README says what the plugin runs, what it reads, and that it reads your login
  • v1.37.1
    • 1.37.1 - the status line prints the effort on a session's first line
    • The status line prints the effort on a session's first line, not its second
  • v1.37.0
    • 1.37.0 - the relay names both routes and runs from a launcher that fits schtasks
    • 1.36.0
    • The relay resumes from a folder Claude Code can trust, arms on the account's reading, and staggers two wakes
    • The brief calls an aged snapshot an estimate, keeps floor for a refused correction, and says when fast mode is on
    • Subagent transcripts are priced at the model their own records name, with the session model only as a fallback
    • The brief is said once per ninety seconds, not once per notification
    • and 3 more commits
  • v1.34.1
    • 1.34.1 - the second pass on 1.34.0
  • v1.34.0
    • 1.34.0 - the relay arms on a saved note, reaps a wake that died, and runs windowless
  • v1.33.1
    • 1.33.1 - relay bugcheck and voice actually answer
  • v1.33.0
    • 1.33.0 - the hand-off sounds like the user and asks for the two bug passes
  • v1.32.1
    • 1.32.1 - the relay window is nobody's child
  • v1.32.0
    • 1.32.0 - the resumed run is a session you can see, on screen and on Remote Control
  • v1.31.2
    • 1.31.2 - the guard's tests set the session they speak for
  • v1.31.1
    • 1.31.1 - a session may only overwrite another session's armed plan on purpose
  • v1.31.0
    • 1.31.0 - the tier line says what switching actually costs, and off is findable
  • v1.30.0
    • 1.30.0 - the continuation rides on stdin, because argv has a ceiling
  • v1.29.0
    • 1.29.0 - ultracode is reported as ultracode, not as the xhigh it resolves to
  • v1.28.0
    • 1.28.0 - the tier line asks for a decision instead of stating a fact
    • 1.27.1 - declare the package type, and record four require cycles
  • v1.27.0
    • 1.27.0 - a standing cap that outlives the session and the reset
  • v1.26.1
    • 1.26.1 - the bug-check pass found three things it introduced
  • v1.26.0
    • 1.26.0 - a wake that says it will fire, and a cap that lapses with its session
    • isolate the arming test so it cannot displace a real relay
  • v1.25.0
    • 1.25.0 - three ways an unattended wake could go wrong, found by reading the prior art
  • v1.24.0
    • 1.24.0 - the relay survives a night with the router off, and work can be put off until ten
  • v1.23.0
    • 1.23.0 - the ceiling, and a meter that was going blind a third of the time
    • Add Gemini CLI integration with Antigravity hooks and Google AI Plus tracking
    • 1.21.0 - four budget modes, and the plugin finally costs what it says it does
    • 1.20.0 - a drift ledger, a reading before long Bash calls, voice that follows the host

Full diff: v1.19.0...v1.40.5

1.19.0 - it said xhigh because ultracode IS xhigh

Choose a tag to compare

@ridelink0 ridelink0 released this 08 Sep 22:40

1.19.0 - it said xhigh because ultracode IS xhigh, and nothing on disk says which

Reported as "the usage thingy still thinks I'm on xhigh and not ultra". The
plugin was not misreading anything. Claude Code's own words, out of its binary:
"ultracode: xhigh + dynamic workflow orchestration (this session only)".

So ultracode is not a sixth effort level. It is xhigh effort plus workflow
orchestration, and it is session-scoped: settings.json keeps effortLevel at
xhigh, every one of this session's 971 transcript lines records effort xhigh,
and neither can name the MODE because the mode is never written down. Both
sources were right and neither could answer the question.

usage.effortNow() is the chain, and every reading says where it came from,
because xhigh from a stale settings file and xhigh from a live override deserve
different confidence:

  1. CLAUDE_CODE_EFFORT_LEVEL - Claude Code's own session override, which hooks
    inherit, so it is live and authoritative.
  2. An override recorded here by hand - the workaround for the one case
    nothing can see, /effort ultracode typed in the session.
  3. settings.effortLevel - the persisted default.
  4. The transcript - stamped at session start and never re-stamped.
node scripts/usage.js --effort              what it reads, and from where
node scripts/usage.js --effort ultracode    tell it what the picker did
node scripts/usage.js --effort clear        forget it

A hand-set override expires after twelve hours, because it describes one
session and left lying around it would outlive the thing it was true for. A
value that is not a real level is refused rather than stored.

634 tests.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

1.18.0 - the setting judged against the work

Choose a tag to compare

@ridelink0 ridelink0 released this 08 Sep 22:33

1.18.0 - the setting judged against the work, not against the window

Everything in this plugin has been budget-triggered: it speaks when a window is
filling. That is the wrong trigger for the question Gev actually asked - notice
the model and effort are bigger than the job needs, and act - 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.

usage.settingFit() measures what the current effort costs against the cheapest
level with real evidence behind it, on this account, and the line reports it
from the first prompt at any percentage: "ultra, measured at 6 times the cost of
medium a turn (8 turns against 6)".

The plugin cannot judge how hard the work is; only the agent reading it can. So
it supplies the measured half and asks for the judgement, naming all three
levers: drop the effort, hand the stretch to a cheaper model, or 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 rather than one. Put it back when the work
gets hard again.

Two things it will not do. It never invents a ratio: with one effort level
measured, or fewer than three turns either side, it says nothing, because a
number off a price list would have an agent drop effort on a hunch and call it
evidence. And it asks once per setting per session rather than every prompt -
the question only changes when the setting does.

Found while wiring it: settingFit read the previously-asked setting after
overwriting it, so it compared the new answer against itself and could never
have fired; and it iterated an event list that a cache hit does not have.

633 tests.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

1.17.0 - the stopping decision, checked exhaustively

Choose a tag to compare

@ridelink0 ridelink0 released this 08 Sep 22:28

1.17.0 - the stopping decision, checked exhaustively

The complaint that started all of this was specific: under Codex it "doesn't
stop at a good stopping point", and it "just makes a plan". Both are failures
of one decision - what the budget line tells the agent to DO - and that
decision now has five inputs: how full the binding window is, whether it is
scoped to a model or shared by the account, which host is reading, whether a
relay is armed, and whether a cheaper lever exists.

Five inputs is too many to spot-check, and spot-checking had already missed
one. test/stopping.test.js walks all 160 combinations and asserts the rules
the whole matrix must satisfy: never tell a spent shared window it still has
budget; always offer the switch on a spent model-scoped one; never say stop
and carry on in the same line; never ask for a handoff below the wall; never
name a Claude Code command to Codex; never leave a stop instruction standing
with a relay armed; and never emit an empty line or leak a value into one.

It failed on its first run. The effort sentence built its command from the
process host rather than the host the line was being written for, so a line
composed for Codex could carry /effort - a command that does not exist there.
Right in production by accident, wrong in principle, and now the host is
passed in rather than read from global state.

That is two real bugs from two walks of this decision: the previous one had a
spent shared window claiming it was "not out of budget" because a cheaper
effort existed. Both are the same underlying mistake - not distinguishing
which window binds and what a lever actually does to it - which is exactly why
it is a matrix now instead of a habit of checking carefully.

630 tests.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

1.16.1 - a cheaper turn cannot buy back a spent window

Choose a tag to compare

@ridelink0 ridelink0 released this 08 Sep 22:25

1.16.1 - a cheaper turn cannot buy back a spent window

Found by doing the check properly rather than assuming it: walking what Codex
is actually told at 50, 70, 80, 88, 92, 97 and 100 per cent and reading each
instruction. At 100 per cent of a SHARED window the new escape wording had it
say "you are not out of budget and you must not stop as though you were",
because a cheaper effort existed. That is wrong. Effort makes a turn cheaper;
it does not give you a turn in a window that has none. Only a model switch
retires a window outright, so only a model switch now survives to 'gone' - a
spent shared window stops, as it should.

This is the failure the plugin exists to prevent, produced by the plugin, in
reverse: refusing to stop at the one moment stopping is right. Two versions ago
it stopped when it should have switched; without this it would switch when it
should stop.

Effort keeps its place while headroom remains: at 'tight' on a shared window
the line still says carry on and names the cheaper level.

The same walk confirmed the rest of the range reads correctly: roomy through
88 per cent (the wall is 90, and winding down earlier spends a budget that
expires anyway), tight from 92 with the lever named, and a clean stop at 100.

622 tests.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

1.16.0 - the agents show up

Choose a tag to compare

@ridelink0 ridelink0 released this 08 Sep 22:22

1.16.0 - the agents show up

Agents spend the same window as the session that dispatched them, and no
display has ever named one. A fan-out could empty half a five-hour window in
five minutes while the status line showed a single session working and the
percentage moved for no visible reason. This plugin's own development did that
twice in one afternoon: a hundred and fifty-eight agent transcripts across
fourteen runs, none of them on any display.

usage.liveAgents() counts the agent transcripts touched recently, and the
number of runs they belong to, and the status line carries it: "+6 agents
(2 runs)". Singular for one, no run count when there is only one run, and it
is the first thing dropped when the terminal is too narrow - a percentage
nobody can see is worse than a count nobody can see.

Cheap on purpose: it stats files and never parses one, and memoises for two
seconds because the panel redraws every second and the scan measured about 95
milliseconds on a machine with a few hundred transcripts.

The first version of the walk looked one directory too shallow and counted
nothing at all on a machine with a hundred and fifty live transcripts, which
is a good argument for checking a reader against real data rather than against
the shape you assumed.

621 tests.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

1.15.0 - the lever in the host's own words

Choose a tag to compare

@ridelink0 ridelink0 released this 08 Sep 22:10

1.15.0 - the lever in the host's own words, and as a choice rather than an exit

Two gaps in 1.14.

The commands were Claude Code's under both hosts. /model and /effort do not
exist in Codex, so the line was telling Codex to run something that does not
exist - to do nothing while believing it acted. usage.levers(host) now names
the lever in the vocabulary of whichever host will read it: Codex gets its own
model and effort controls, and the script's weaker promise is stated rather
than implied, because lowpower.js --host codex saves defaults for NEW sessions
and cannot change one already running. The effort sentence carries the command
too, where before it named no way to act at all.

And it read as an emergency exit when it is a lever to pull on purpose. The
line now says outright that the change can be made without being asked,
whenever the current setting is dearer than the work in front of you needs,
rather than only when a window is nearly gone - a mechanical rename does not
need the model 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. SKILL.md section 5 teaches both halves.

Also: an escape with no command names the lever and invents no syntax, instead
of printing "Use undefined." - found by two older tests going red against the
new shape, which is what those tests are for.

619 tests. A third bug pass over this plugin (concurrency between hooks, the
Codex reader against six real rollouts including a truncated one, hostile input

  • a 20 MB JSONL line, 5000-todo events, path traversal in relay ids - and
    packaging drift) produced six claims and zero that survived two skeptics.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

1.14.1 - one point, one sentence

Choose a tag to compare

@ridelink0 ridelink0 released this 08 Sep 22:06

1.14.1 - one point, one sentence

Seen in the live line straight after shipping 1.14.0: the older per-model
warning and the new escape line both fired, saying nearly the same thing twice
on every prompt - and the older one only ever managed "Use /model (or ...",
never naming a model. It now steps aside whenever the escape line names the
switch, and still speaks when there is no escape to name.

615 tests.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com