claude-usage-limits 1.18.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "usage-limits",
3
3
  "displayName": "Usage Limits",
4
- "version": "1.18.0",
4
+ "version": "1.23.0",
5
5
  "description": "Puts your remaining Claude Code usage limit into Claude's context before every prompt, so it opens with what fits in the budget instead of starting work that gets cut off. Reports headroom as turns rather than percentages, prices a job before you start it, and detects your plan tier.",
6
6
  "author": {
7
7
  "name": "Ridelink",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usage-limits",
3
- "version": "1.18.0",
3
+ "version": "1.23.0",
4
4
  "description": "Reports how much of your Codex usage limit is left as turns of work rather than a percentage, prices a job before you start it, and counts the other agents sharing the same budget.",
5
5
  "author": {
6
6
  "name": "Ridelink",
package/README.md CHANGED
@@ -839,6 +839,109 @@ and are counted together. On this machine the transcripts carry both `cli` and
839
839
  Windows, macOS, and Linux all work. `CLAUDE_CONFIG_DIR` is honoured if you have
840
840
  moved the config directory.
841
841
 
842
+ ## Budget modes
843
+
844
+ This plugin is not free. It puts a line into the model's context before every
845
+ prompt, refreshes readings after tool calls, and keeps a status line alive. A
846
+ mode called "save tokens" that still injects four hundred tokens of advice per
847
+ turn is not saving anything - it is charging you for the advice about saving.
848
+
849
+ So a mode changes two things, not one: what the plugin tells the agent to do,
850
+ and what it costs to say it.
851
+
852
+ ```
853
+ claude-usage-limits mode which one, where it came from
854
+ claude-usage-limits mode max set it
855
+ claude-usage-limits mode off --guard 95 off, except one line near the wall
856
+ claude-usage-limits mode auto pick from pressure, always reported
857
+ claude-usage-limits mode --list all four, and the aliases
858
+ claude-usage-limits mode --ledger measured cost per turn, per mode
859
+ ```
860
+
861
+ | mode | what it does | what it costs |
862
+ | --- | --- | --- |
863
+ | `max` | fewest tokens that can still finish the job | one terse line, readings every 10 minutes, silent while nothing a decision depends on has moved |
864
+ | `high` | full capability, re-costed every two minutes mid-turn | the normal line, **plus a standing directive on every prompt** (about 650 characters, so a `high` briefing runs roughly 40% longer than `standard`), plus a short re-cost the first time a cheaper tier would do the same job - re-measured every two minutes, said only when the answer changes |
865
+ | `standard` | what the plugin has always done | today's line, today's cadences, unchanged |
866
+ | `off` | nothing at all | every hook returns before reading anything: no scan, no state write, no line, no end-of-reply tally |
867
+
868
+ `high` is the mode that spends a little more to waste a lot less: it carries a
869
+ standing directive and re-measures mid-turn, so its own line is longer than
870
+ `standard`'s. `max` is the one that costs less to say. Picking `high` because
871
+ the word sounds efficient and expecting a shorter line is the one
872
+ misunderstanding worth heading off.
873
+
874
+ Aliases, because people ask for these in their own words: `ultra`,
875
+ `ultra-efficient`, `maxtoken`, `maxefficient` for `max`; `smart`,
876
+ `high-efficient` for `high`; `efficient`, `token-efficient`, `default`, `on`
877
+ for `standard`; `none`, `quiet`, `silent`, `ignore` for `off`.
878
+
879
+ **`normal` is deliberately not an alias.** To some people it means "the plugin
880
+ working as usual" (`standard`); to others it means "the plugin stays out of the
881
+ way" (`off`). Those are opposite instructions, so guessing is wrong half the
882
+ time. Ask for `normal` and you get a question back, not a setting.
883
+
884
+ `off` means off, including at 100 per cent used. That is what it says and it is
885
+ honoured literally - which is also the failure this plugin exists to prevent,
886
+ so setting it prints the consequence once and offers `--guard 95`: one short
887
+ line when the window is nearly spent, and nothing else, ever. The default guard
888
+ is none. Discoverable, not imposed.
889
+
890
+ The one thing a mode never does is lower the quality of the work. When things
891
+ are tight you change the ORDER of the work, never the amount or the quality.
892
+ The savings come from ceremony - speculative reads, re-reads, preamble,
893
+ subagents nobody needed, workflows that cost more context than they save - and
894
+ the directives say that outright, because a model reading "use fewer tokens"
895
+ will otherwise quietly decide to skip the hard part. There is a test for it,
896
+ and another one that checks the `max` line is never longer than the `standard`
897
+ line for the same reading.
898
+
899
+ ### Two planes, and which one is whose
900
+
901
+ There are two separate things people mean by "change the model":
902
+
903
+ - **The user plane** is your `settings.json` (`model`, `effortLevel`), the
904
+ `/effort` and `/model` pickers, and `lowpower.js`. It is you saying what you
905
+ want for yourself. The plugin reads it, shows it, and **never writes it on
906
+ its own initiative.** Claude may recommend a change, and make one if you ask;
907
+ it may not make one unasked. There is a test that exercises every mode, every
908
+ alias, `auto`, the bounds and the guard, and then checks `settings.json` is
909
+ byte-identical.
910
+ - **The agent plane** is the tier actually running the turn, and the tier of
911
+ everything the turn spawns. That is what costs money, and that is what the
912
+ modes govern.
913
+
914
+ `claude-usage-limits mode --baseline` shows both side by side. The budget line
915
+ now says the tier as well, and where the reading came from, because the number
916
+ that decides what a turn costs was the one number the line never printed.
917
+
918
+ What Claude can genuinely move, stated without embroidery: the model on an
919
+ `Agent` call, and the model and effort inside a `Workflow` script. Its own
920
+ model and effort it cannot change mid-session - no hook output field exists for
921
+ it, on either host - so the plugin names the exact command and leaves it with
922
+ you. It does not pretend otherwise.
923
+
924
+ You can bound what it may suggest:
925
+
926
+ ```
927
+ claude-usage-limits mode --floor sonnet/medium # never point below this
928
+ claude-usage-limits mode --ceiling opus/xhigh # nor above it
929
+ claude-usage-limits mode --pin # report only, suggest nothing
930
+ claude-usage-limits mode --decline # no, and stop suggesting that
931
+ ```
932
+
933
+ And when you say "put it back", there is something to put it back to:
934
+
935
+ ```
936
+ claude-usage-limits mode --history what changed, when, at whose instruction
937
+ claude-usage-limits mode undo reverse the last change, naming it first
938
+ ```
939
+
940
+ `undo` reverses what the plugin owns. For a change to your own settings it
941
+ names the entry and the command that undoes it and leaves the file alone -
942
+ which is the same rule as everywhere else, and the reason the byte-identical
943
+ test can never go green by accident.
944
+
842
945
  ## Working cheaply on purpose
843
946
 
844
947
  Half the problem is measurement. The other half is that a high effort setting
@@ -972,7 +1075,8 @@ skills/usage-limits/scripts/ usage.js, brief.js, pulse.js, stop.js,
972
1075
  lowpower.js, install-codex-hook.js,
973
1076
  recommend.js, panel.js, feed.js,
974
1077
  statusline.js, live.js, view.js, bars.js,
975
- activity.js
1078
+ activity.js, reading.js, drift.js,
1079
+ mode.js, voice.js, relay.js, wake.js
976
1080
  skills/usage-limits/references/ the longer notes
977
1081
  hooks/hooks.json runs brief.js before each prompt, pulse.js
978
1082
  during long turns, stop.js after each reply
@@ -981,6 +1085,7 @@ commands/check.md the /usage-limits:check command
981
1085
  commands/session.md the /usage-limits:session command
982
1086
  commands/panel.md the /usage-limits:panel command
983
1087
  commands/statusline.md the /usage-limits:statusline command
1088
+ commands/usage-mode.md the /usage-mode command
984
1089
  bin/cli.js the npx entry point
985
1090
  tools/sync-version.js keeps the manifest version in step
986
1091
  vscode/ the VS Code extension; build.js copies the
@@ -994,11 +1099,18 @@ test/ node --test, no dependencies
994
1099
  node --test
995
1100
  ```
996
1101
 
997
- 480 tests over the pricing, the window arithmetic, plan and credit detection,
1102
+ 712 tests over the pricing, the window arithmetic, plan and credit detection,
998
1103
  the status line, the before-prompt line, the mid-turn pulse, the after-reply tally and the session history, job forecasting,
999
1104
  per-project attribution, the Codex reader and its installer, the CLI,
1000
1105
  packaging, and the settings save/restore.
1001
1106
 
1107
+ The budget modes are checked as rules rather than examples: the whole stopping
1108
+ matrix is walked in every mode (640 lines), `off` must inject nothing at any
1109
+ percentage and any pressure, the `max` line must never be longer than the
1110
+ `standard` line for the same reading, no line may tell the agent to do the work
1111
+ worse, and every mode path, alias, bound and guard is exercised before
1112
+ `settings.json` is compared byte for byte.
1113
+
1002
1114
  ## Status
1003
1115
 
1004
1116
  It works and I use it daily.
@@ -1040,3 +1152,109 @@ This exists because of a real session. The Fable weekly hit 89 per cent, the
1040
1152
  line said the budget was nearly gone, and the work stopped - with the 5-hour
1041
1153
  window at 46 and every other model untouched. One command would have carried it
1042
1154
  on.
1155
+
1156
+ ## 1.23.0 - the ceiling, and three hosts that can be told no
1157
+
1158
+ Everything before this release reported. This one intervenes.
1159
+
1160
+ ### The Codex meter was going blind about a third of the time
1161
+
1162
+ Codex writes more than one meter into its rollouts, and they are not successive
1163
+ readings of one thing. A ChatGPT Plus session carries `limit_id: "codex"`, which
1164
+ holds the 5-hour and weekly windows, interleaved with `limit_id: "premium"`,
1165
+ which holds the credit balance and has `primary` and `secondary` set to `null`.
1166
+ The reader took whichever was written last.
1167
+
1168
+ On the machine this was found on, two of every six rollouts ended on a `premium`
1169
+ payload - and when one did, the plugin reported no windows at all. Measured on a
1170
+ real session: the final line was a `premium` payload two lines after a `codex`
1171
+ payload reading **99 per cent of the 5-hour window**, and what reached the agent
1172
+ was a meter with nothing in it.
1173
+
1174
+ That is the whole of "Codex does not slow down when the limit is close": nothing
1175
+ ever told it the limit was close. The reader now keeps the newest reading of each
1176
+ meter and prefers the one that actually describes a window. Nothing is merged or
1177
+ synthesised - the payload returned is one Codex really wrote.
1178
+
1179
+ ### An old snapshot is a floor, not a reading
1180
+
1181
+ There was already a warning for a reading spent past its own remainder. It could
1182
+ never fire for a snapshot taken at the start of a window, because everything
1183
+ spent since is still inside the remainder.
1184
+
1185
+ So a session ran for most of an hour being told **7 per cent** while the account
1186
+ was at **41**: Claude Code's own cache had not moved in fifty minutes, the
1187
+ plugin's live reading was rate-limited into backoff, and the correction was
1188
+ quietly carrying the entire difference on its own. A correction is a good
1189
+ adjustment to a recent snapshot and a bad substitute for an old one, because the
1190
+ pricing error compounds with every point it has to bridge. Past fifteen minutes
1191
+ the brief now says the figure is a floor and points at `/usage`.
1192
+
1193
+ ### The ceiling
1194
+
1195
+ node bin/cli.js mode --cap 60
1196
+ node bin/cli.js mode --cap off
1197
+
1198
+ Past the ceiling, **fan-out calls are refused at the hook** - `Agent`, `Task`,
1199
+ `Workflow` and their equivalents on each host. Everything else keeps working at
1200
+ any percentage: reads, edits, tests, commands. The work still finishes, just
1201
+ sequentially, in one session, which is where the saving is. A measured fan-out
1202
+ costs between 2.6x and 5.9x the same work done in sequence, because every agent
1203
+ warms its own cache from cold and none can report back until they all stop.
1204
+
1205
+ It is off until you set a number, it never fires without a reading behind it, and
1206
+ the refusal says what to do instead - a denial that only says "over budget" gets
1207
+ retried.
1208
+
1209
+ **Why a refusal rather than a sentence.** On Codex the reported figure
1210
+ demonstrably does not change behaviour, and the reason is not stubbornness.
1211
+ `gpt-6-astra`'s own system prompt, shipped in `models_cache.json`, says: *"Do not
1212
+ settle for a partial or 'helpful enough' solution that does not fully satisfy the
1213
+ user's task to save time, effort or tokens"* - and ranks the live user
1214
+ instruction above anything an `AGENTS.md` or a skill says. A line asking it to
1215
+ economise is arguing with its own instructions, and losing.
1216
+
1217
+ ### The Codex subagent clamp
1218
+
1219
+ `lowpower on --host codex` now also bounds `[agents]`. Two facts read out of the
1220
+ model catalog Codex itself caches, not out of documentation:
1221
+
1222
+ gpt-6-astra: default_reasoning_level = "low"
1223
+ multi_agent_reasoning_effort = "xhigh"
1224
+
1225
+ Astra's own default effort is the cheapest one, and its subagents run at the
1226
+ dearest one **no matter what the session is set to**. Lowering effort without
1227
+ bounding them leaves the most expensive path in the product untouched. The clamp
1228
+ is a marked block, removed exactly by `lowpower off`, and it refuses outright
1229
+ rather than writing a second `[agents]` table over one you wrote yourself.
1230
+ `--no-agents` declines just that half.
1231
+
1232
+ ### Antigravity
1233
+
1234
+ node skills/usage-limits/scripts/install-antigravity.js on
1235
+
1236
+ Installs into `~/.gemini/config/plugins/usage-limits/`. `PreInvocation` carries
1237
+ the budget line as an injected ephemeral message; `PreToolUse` carries the
1238
+ ceiling, which Antigravity implements as a real `decision: "deny"`.
1239
+
1240
+ One thing is said plainly rather than papered over: **Antigravity publishes no
1241
+ remaining quota anywhere readable on disk.** It refreshes quota - its own log
1242
+ says so - and keeps it in memory. A previous version filled that gap by reporting
1243
+ *Claude's* meter under a `cross-agent-claude` source, next to a hardcoded plan
1244
+ and a model name invented for a settings file that has no model key in it. All of
1245
+ that is gone. Where there is nothing to read, the report says the quota is
1246
+ unreadable.
1247
+
1248
+ ### Caveman, and why it is not here
1249
+
1250
+ It was on the list for this release and it is not in it. JetBrains ran a
1251
+ controlled A/B of the caveman skill - 86 tasks, paired, ~240 billed trials - and
1252
+ measured output tokens down **8.5 per cent** against an advertised 65, with
1253
+ quality differences indistinguishable from noise (p=0.82). An independent
1254
+ benchmark found the literal instruction `be brief.` matched or beat it, and
1255
+ because agentic cost is input-dominated, the skill's own rules riding along every
1256
+ turn can cost more than they save. Its engine is also BSL-licensed, not open.
1257
+
1258
+ Claude Code already ships a built-in **Concise** output style that does the same
1259
+ job in the cached system-prompt layer at no marginal cost. Use that. This plugin
1260
+ will not ship a measured 8 per cent as a 65 per cent saving.
package/bin/cli.js CHANGED
@@ -26,6 +26,16 @@ const HELP = `claude-usage-limits - how much agent usage is left, and whether th
26
26
  claude-usage-limits statusline on bars under the Claude Code prompt
27
27
  claude-usage-limits statusline off put back what was there
28
28
 
29
+ claude-usage-limits mode which budget mode the hooks are in
30
+ claude-usage-limits mode max fewest tokens that still finish the job
31
+ claude-usage-limits mode high full capability, re-costed every two minutes
32
+ claude-usage-limits mode standard what the plugin does today
33
+ claude-usage-limits mode off inject nothing; hooks return immediately
34
+ claude-usage-limits mode off --guard 95 off, except one line when nearly spent
35
+ claude-usage-limits mode auto pick from pressure, always reported
36
+ claude-usage-limits mode --list the four modes and their aliases
37
+ claude-usage-limits mode --ledger measured cost per mode
38
+
29
39
  claude-usage-limits lowpower status show the current effort setting
30
40
  claude-usage-limits lowpower on lower effortLevel, remembering the old value
31
41
  claude-usage-limits lowpower on --effort medium --model sonnet
@@ -59,6 +69,12 @@ function run(argv) {
59
69
  return Promise.resolve(0);
60
70
  }
61
71
 
72
+ if (args[0] === 'mode') {
73
+ const budget = require('../skills/usage-limits/scripts/mode.js');
74
+ process.stdout.write(budget.main(args.slice(1)) + '\n');
75
+ return Promise.resolve(0);
76
+ }
77
+
62
78
  if (args[0] === 'lowpower') {
63
79
  const lowpower = require('../skills/usage-limits/scripts/lowpower.js');
64
80
  return Promise.resolve(lowpower.main(args.slice(1)));
@@ -0,0 +1,64 @@
1
+ ---
2
+ description: Show or set the budget mode - how hard the plugin leans, and what it costs to say it
3
+ ---
4
+
5
+ Run `node "${CLAUDE_PLUGIN_ROOT}/skills/usage-limits/scripts/mode.js" $ARGUMENTS`
6
+ and report the answer back. Then stop; do not start other work as part of this
7
+ command.
8
+
9
+ The plugin is not free. It puts a line into your context before every prompt,
10
+ refreshes readings after tool calls, and keeps a status line alive. A mode
11
+ changes two things at once: what the plugin tells you to do, and what it costs
12
+ to say it.
13
+
14
+ | mode | what it is |
15
+ | --- | --- |
16
+ | `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 |
17
+ | `high` | full capability, re-costed every two minutes mid-turn: the normal line plus a directive to keep checking whether the tier is bigger than the task. The mid-turn re-cost is re-measured on that cadence and said only when the answer changes |
18
+ | `standard` | what the plugin does today, unchanged |
19
+ | `off` | nothing is injected at all, and every hook returns before reading anything - including the end-of-reply cost line and the closing line |
20
+
21
+ Aliases: `ultra`, `ultra-efficient`, `maxefficient` and friends for `max`;
22
+ `smart`, `high-efficient` for `high`; `efficient`, `token-efficient`,
23
+ `default`, `on` for `standard`; `none`, `quiet`, `silent`, `ignore` for `off`.
24
+
25
+ **`normal` is deliberately not an alias for either `standard` or `off`.** To
26
+ some people it means "the plugin working as usual" and to others "the plugin
27
+ stays out of the way", and those are opposite instructions. The script answers
28
+ it with a question. Ask which was meant; never guess.
29
+
30
+ Commands:
31
+
32
+ - (no arguments) - the current mode, where it came from, and what it changes.
33
+ - `<name>` - set it. `<name> --session --session-id <id>` sets it for one
34
+ session only.
35
+ - `auto` / `auto off` - pick from pressure. Under 50 per cent used it is
36
+ standard, 50 to 79 high, 80 or over (or tight, or gone) max. It is always
37
+ reported as what it resolved to (`auto -> max`) and it never picks `off`.
38
+ - `off --guard 95` - off, except one short line when the window is nearly
39
+ spent. `off` on its own is silent even at 100 per cent; that is what it means
40
+ and it is honoured literally, so the guard exists and is offered once.
41
+ - `--list`, `--explain <name>` - the modes, and one mode's full record.
42
+ - `--floor sonnet/medium`, `--ceiling opus/xhigh`, `--pin` - the user's own
43
+ bounds on what the plugin may suggest. `--pin` means report only: the gap
44
+ between the baseline and what is running is stated and nothing is suggested.
45
+ - `--baseline` - the user's own setting and the tier actually running, side by
46
+ side.
47
+ - `--advice` / `--no-advice` / `--advice-on` - the recommendation channel.
48
+ - `--decline [id]` - the user said no. That recommendation is remembered as
49
+ declined and is never raised again, in this session or any later one. With no
50
+ id it declines whatever is pending.
51
+ - `--history`, `undo` - what changed, when, at whose instruction; and reverse
52
+ the last one, naming it first.
53
+ - `--ledger` - measured turns and cost per turn, per mode, from what replies
54
+ actually cost.
55
+
56
+ Two rules that hold in every mode:
57
+
58
+ 1. **The modes govern the agent plane only.** `settings.json`, `/effort`,
59
+ `/model` and `lowpower.js` are the user's own baseline. The plugin reads
60
+ them, shows them, and never writes them on its own initiative. Recommend a
61
+ change freely; make one when asked; never make one unasked.
62
+ 2. **A mode never lowers the quality of the work.** The savings come from
63
+ ceremony - speculative reads, re-reads, preamble, subagents nobody needed -
64
+ and never from doing the job less well.
package/hooks/hooks.json CHANGED
@@ -58,7 +58,7 @@
58
58
  ],
59
59
  "PreToolUse": [
60
60
  {
61
- "matcher": "Workflow|Agent|Task",
61
+ "matcher": "Workflow|Agent|Task|Bash",
62
62
  "hooks": [
63
63
  {
64
64
  "type": "command",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-usage-limits",
3
- "version": "1.18.0",
3
+ "version": "1.23.0",
4
4
  "description": "Puts your remaining Claude Code usage limit into Claude's context before every prompt, so it opens with what fits in the budget instead of starting work that gets cut off. Reports headroom as turns rather than percentages, prices a job before you start it, and detects your plan tier.",
5
5
  "keywords": [
6
6
  "claude",
@@ -275,6 +275,137 @@ The user can also ask any time with `/usage-limits:session`, or run
275
275
  `--sessions` for the history of recent sessions on this machine.
276
276
 
277
277
 
278
+ ## Budget modes
279
+
280
+ How hard this plugin leans, and what it costs to say it. Four modes, set by the
281
+ user and read by every hook:
282
+
283
+ ```
284
+ node scripts/mode.js # which one, where it came from, what it changes
285
+ node scripts/mode.js max # set it
286
+ node scripts/mode.js --list # all four, and the aliases
287
+ node scripts/mode.js --explain high # one mode's full record
288
+ ```
289
+
290
+ | mode | one line |
291
+ | --- | --- |
292
+ | `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 |
293
+ | `high` | full capability, re-measured every two minutes mid-turn, and said only when the answer changes |
294
+ | `standard` | what the plugin does today, unchanged. The default |
295
+ | `off` | nothing injected at all; every hook returns before reading anything, including the end-of-reply tally |
296
+
297
+ Aliases: `ultra`, `ultra-efficient`, `maxtoken`, `maxefficient` map to `max`;
298
+ `smart`, `high-efficient` to `high`; `efficient`, `token-efficient`, `default`,
299
+ `on` to `standard`; `none`, `quiet`, `silent`, `ignore` to `off`.
300
+
301
+ **`normal` is not an alias for either.** To some people it means "the plugin
302
+ working as usual" (`standard`) and to others "the plugin stays out of the way"
303
+ (`off`) - opposite instructions, so a silent guess is wrong half the time. If
304
+ the user says "normal", ask which they meant and say what each one does. The
305
+ script answers the same way.
306
+
307
+ `auto` picks from how full the binding window is - standard under 50 per cent
308
+ used, high from 50 to 79, max at 80 or above - and always reports itself as
309
+ what it resolved to (`auto -> max`). It reads the snapshot already on disk
310
+ rather than scanning, because the mode has to be settled before anything
311
+ expensive runs, and with no readable window it stays on `standard` rather than
312
+ guessing. It never picks `off`: turning the plugin off is a decision a person
313
+ makes.
314
+
315
+ `off` means off, including at 100 per cent. That is deliberate. If the user
316
+ wants one line at the wall and nothing else, `node scripts/mode.js off --guard 95`
317
+ is it.
318
+
319
+ Two rules hold in every mode, and they are not negotiable:
320
+
321
+ - **A mode never lowers the quality of the work.** When things are tight you
322
+ change the ORDER of the work, never the amount or the quality. The savings
323
+ come from ceremony - speculative reads, re-reads, preamble, subagents nobody
324
+ needed, workflows that cost more context than they save.
325
+ - **The modes govern the agent plane only**, and never write `settings.json`.
326
+
327
+ ### Two planes, and the conversation between them
328
+
329
+ The **user plane** is `settings.json` (`model`, `effortLevel`), the `/effort`
330
+ and `/model` pickers, and `lowpower.js`. It is the user saying what they want
331
+ for themselves. It is theirs.
332
+
333
+ The **agent plane** is the tier actually running this turn, and the tier of
334
+ everything this turn spawns. That is what costs money.
335
+
336
+ What is actually yours to move, stated exactly, because a claim beyond this
337
+ would be a lie the user cannot check:
338
+
339
+ - **The model on an `Agent` call is yours.** `model: "sonnet" | "opus" |
340
+ "haiku" | "fable"` on any Agent call, and it overrides both the agent
341
+ definition and the configured default. It is ignored for `subagent_type:
342
+ "fork"`, which always inherits the parent model.
343
+ - **Model and effort inside a `Workflow` script are yours**, per `agent()`
344
+ call: `opts.model` and `opts.effort` (`low` | `medium` | `high` | `xhigh` |
345
+ `max`). The host's own advice is to omit `opts.model` unless you are
346
+ confident, and to use `opts.effort: 'low'` for mechanical stages - so lean on
347
+ effort rather than model when sizing what you spawn.
348
+ - **Your own model and effort are NOT yours to change mid-session.** Nothing a
349
+ hook can emit changes them: there is no such field anywhere in the hook
350
+ output contract, and `PreModelSwitch` can only veto a switch someone else
351
+ started. `/model` and `/effort` are typed by a person and
352
+ `CLAUDE_CODE_EFFORT_LEVEL` is read at launch. So say the exact command in one
353
+ line and let the user run it. Never imply you changed it yourself.
354
+ - `xhigh` and `max` are refused outright when thinking is disabled, so never
355
+ point at either without that being true.
356
+
357
+ The two planes talk to each other, in both directions, through the
358
+ conversation. The whole rule in one line:
359
+
360
+ **You may RECOMMEND a user-plane change. You may MAKE one when asked. You may
361
+ never make one unasked.**
362
+
363
+ Recommending, when you do it:
364
+
365
+ - **Evidence or silence.** Cite a measurement - what this account has actually
366
+ measured, from `usage.js --recommend`, the fit line in the budget briefing,
367
+ or `scripts/drift.js`. "Recommended" with no number is nagging.
368
+ - **At most one per session**, and none at all in `off`. The plugin enforces
369
+ this; do not route around it.
370
+ - **A declined recommendation is not raised again.** When the user says no,
371
+ record it - `node scripts/mode.js --decline` - and it is never volunteered
372
+ again, in this session or any later one. `--advice` shows what is pending.
373
+ - **Name the exact command, the plane it changes, and when it takes effect.**
374
+
375
+ When the user asks you to change something, or says **"change it back"**: read
376
+ `node scripts/mode.js --history` first, say out loud what you are reverting and
377
+ to what, then do it. Never infer a target that is not in the log. `node
378
+ scripts/mode.js undo` reverses the last change the plugin owns and names it
379
+ first; for a change to the user's own settings it names the command and leaves
380
+ the file alone, because that plane is not the plugin's to write.
381
+
382
+ The surprise to head off, every time: **a user-plane change does not move the
383
+ session already running.** If the user says "turn low power on" and you do it,
384
+ nothing about this session changes - `lowpower.js` says so itself ("Applies to
385
+ new sessions. For the session you are in, run /effort X"). Relay that in your
386
+ own words whenever you make one, and the same in reverse: putting the baseline
387
+ back does not restore this session's tier either.
388
+
389
+ ### Bounds the user can set
390
+
391
+ ```
392
+ node scripts/mode.js --floor sonnet/medium # never point below this, even in max
393
+ node scripts/mode.js --ceiling opus/xhigh # nor above it, even on the hard part
394
+ node scripts/mode.js --pin # do not self-switch at all: report only
395
+ ```
396
+
397
+ Under `--pin` the plugin reports the gap between the baseline and what is
398
+ running and suggests nothing. Respect it in your own words too: report, do not
399
+ switch.
400
+
401
+ ### Stepping back up
402
+
403
+ The efficient modes are two-directional, and that matters more than it sounds.
404
+ Having dropped to a cheap tier for a mechanical stretch, say so when the work
405
+ turns hard again and point back at the baseline. A one-way ratchet down is how
406
+ a long session quietly degrades, which is the thing the quality rule forbids.
407
+
408
+
278
409
  ## 4. Low power
279
410
 
280
411
  Two halves, and the second one is the half that actually binds.
@@ -404,41 +535,48 @@ waste at 10 per cent used exactly as much as at 80; the only difference is that
404
535
  at 80 somebody notices.
405
536
 
406
537
  It cannot judge how hard your work is. You can. So when you see it, look at what
407
- is actually in front of you and take one of three levers yourself, saying which
408
- in one line:
538
+ is actually in front of you and reach for one of three levers, saying which in
539
+ one line. Two of them are yours to pull; the first is not.
409
540
 
410
541
  1. **Drop the effort** for that stretch - a rename, a docs pass, running tests,
411
- applying a fix you have already worked out.
412
- 2. **Hand the stretch to a cheaper model**, and keep the dear one for the
413
- decisions that need it.
542
+ applying a fix you have already worked out. `/effort` and `settings.json` are
543
+ the user's own baseline, so this one you **offer**: name the command, say why
544
+ the stretch does not need the tier, and leave the pulling of it to them.
545
+ 2. **Hand the stretch to a cheaper model.** Your own model is the user's setting
546
+ too, so say that in one line rather than switching - but the model on
547
+ anything you SPAWN is entirely yours: an Agent call takes a model, and a
548
+ Workflow's `agent()` takes a model and an effort. Size those to the stage.
414
549
  3. **Do less of it at this setting** - a fan-out multiplies the setting across
415
- every agent, so six agents at ultra is six ultra turns, not one.
550
+ every agent, so six agents at ultra is six ultra turns, not one. Yours.
416
551
 
417
552
  Put it back when the work gets hard again. The question is asked once per
418
553
  setting per session, not every prompt, and never at all unless there is a real
419
554
  measured comparison behind it - a ratio from a price list would have you drop
420
555
  effort on a hunch and call it evidence.
421
556
 
422
- **This is a lever you may pull yourself, not only an emergency exit.** Use it
423
- whenever the current setting is dearer than the work in front of you needs,
424
- without being asked and long before any window is tight: a mechanical rename,
425
- a docs pass or a mass find-and-replace does not need the model and effort a
426
- hard design decision does. Drop it for that stretch, say in one line that you
427
- did and why, and put it back when the work gets hard again. An agent that only
428
- ever reads this as a wall notice runs every trivial turn at the top setting and
429
- then wonders where the window went.
557
+ **This is worth raising early, not only at the wall.** Say it whenever the
558
+ current setting is dearer than the work in front of you needs, long before any
559
+ window is tight: a mechanical rename, a docs pass or a mass find-and-replace
560
+ does not need the model and effort a hard design decision does. An agent that
561
+ only ever reads this as a wall notice runs every trivial turn at the top setting
562
+ and then wonders where the window went.
563
+
564
+ **And "offer it" is one line, not a stop.** Naming the lever and carrying on is
565
+ the whole action. Waiting for an answer before doing the work would cost more
566
+ than the tier ever did.
430
567
 
431
568
  The budget line does this arithmetic for you. Once the binding window is half
432
569
  gone it says which lever applies, and at the wall it says outright that you are
433
570
  not out of budget and must not stop as though you were. When it does, the
434
- sequence is: switch, say in one line that you switched and why, carry on with
435
- the whole request at full quality.
571
+ sequence is: say in one line which command frees it and why, and carry on with
572
+ the whole request at full quality. A per-model weekly is not the account's
573
+ budget, and treating it as one is the error.
436
574
 
437
575
  This is written down because it was got wrong. A session ended with the Fable
438
576
  weekly at 89 per cent and the line saying the budget was nearly gone - while the
439
577
  5-hour sat at 46 and every other model on the account was untouched. One command
440
- would have carried it on. Stopping there was not caution; it was quitting with a
441
- reason that sounded like one.
578
+ would have carried it on, and naming that command costs a line. Stopping there
579
+ was not caution; it was quitting with a reason that sounded like one.
442
580
 
443
581
  Only when the switch is genuinely unavailable - no other window has room, or the
444
582
  user has ruled it out - does the checkpoint below apply.
@@ -540,6 +678,14 @@ of it.
540
678
 
541
679
  ## Running under Codex
542
680
 
681
+ One difference that matters for the budget modes. Every entry in Codex's
682
+ `hooks.json` carries an `additionalContextLimit` - a per-hook cap on how much
683
+ context a hook may inject, which Claude Code has no equivalent of. A long
684
+ briefing can therefore be truncated there without a word. If a line looks cut
685
+ off under Codex, that is why: `node scripts/mode.js max` keeps it to one line,
686
+ and `high` is the verbose one.
687
+
688
+
543
689
  Everything above works the same. The numbers come from a different place and
544
690
  one thing about how they arrive is different, and both are worth knowing.
545
691
 
@@ -654,6 +800,7 @@ stop.
654
800
  | `scripts/host.js` | Works out which agent this is running inside, so one host's percentages are never reported against the other's turns. |
655
801
  | `scripts/codex.js` | The Codex reader: the meter and the pace out of `~/.codex/sessions`, plus the live `--refresh` call. |
656
802
  | `scripts/install-codex-hook.js` | `status`, `on`, `off`. Installs the Codex-side instruction, which Claude Code does not need. |
803
+ | `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`, `--baseline`, `--advice`/`--no-advice`, `--history`, `undo`, `--ledger`. Reads settings.json and never writes it. |
657
804
  | `scripts/lowpower.js` | `status`, `on`, `off`. Restores what it replaced. Claude Code only. |
658
805
  | `scripts/recommend.js` | The chooser behind `usage.js --recommend`: posture, then the effort and model commands for each lever. Not meant to be called by hand. |
659
806
  | `references/tactics.md` | Every lever that lowers cost, and why it works. |
@@ -661,6 +808,7 @@ stop.
661
808
  | `scripts/statusline.js` | `status`, `on`, `off`. Puts the bars under the prompt and restores what was there. |
662
809
  | `scripts/feed.js` | The status line command Claude Code runs. Not meant to be called by hand. |
663
810
  | `scripts/live.js` | The usage reading itself, taken the way Claude Code takes it for `/usage`, kept in `usage-limits-live.json` where `collect()` prefers it when newer than the cache. |
811
+ | `scripts/drift.js` | How wrong the reading was: each correction written down against the one it replaced. Run it with no arguments for the median and worst gap measured so far, `--json` for the fields. Answer "how far behind does this plugin actually run" from here rather than from memory. |
664
812
  | `scripts/view.js`, `scripts/bars.js`, `scripts/activity.js` | The display model, the drawing in Claude's colours, and the working/idle marks the hooks leave for the panel. Not meant to be called by hand. |
665
813
  | `scripts/relay.js` | The relay: `status`, `on`/`off`, `at N`, `grace N`, `mode notify\|resume`, `permission MODE`, `thinking off\|resume\|always`, `note "<text>"`, `cancel`, `log`. |
666
814
  | `scripts/wake.js` | What the scheduler runs after the reset: re-checks the meter, then notifies or resumes. Never called by hand. |