Configuration

The config.json schema, thresholds, and policy knobs

Config is JSON at ~/.config/tokenmaxxing/config.json. Every field is optional; defaults apply per-field.

{
  "thresholds": {
    "session": 90,
    "weekly": 98,
    "accounts": { "shared-seat": { "session": 75, "weekly": 75 } }
  },
  "claudeBin": "/path/to/real/claude",
  "codexBin": "/path/to/real/codex",
  "grokBin": "/path/to/real/grok",
  "piBin": "/path/to/real/pi",
  "policy": {
    "projectionMargin": 0,
    "switchModels": ["fable"],
    "usagePollTtlMs": 90000,
    "maxWaitMs": 3600000,
    "checkIntervalMs": 60000,
    "accountReleaseMs": { "session": 1800000, "weekly": 18000000 }
  },
  "hub": { "port": 8317 }
}

Fields

FieldDefaultMeaning
thresholds.session90The 5-hour session bar, one number. See Bars.
thresholds.weekly98The weekly bar, covering the 7-day aggregate and every per-model weekly cap.
thresholds.accounts{}Per-account thresholds keyed by account label, each with both session and weekly. See Per-account bars.
"credits" in a thresholds.accounts entryfalseMarks an account that carries purchased usage credits.
claudeBin, codexBin, grokBin, piBinwritten by initPins to the REAL binaries the supervisors and the status-only pool spawn. See Binary pins.
policy.projectionMargin0Subtracted from the session threshold only. See Projection margin.
policy.switchModels["fable"]Model families whose per-model weekly cap gates a switch (entries are lowercased on load).
policy.usagePollTtlMs90000The shortest sample interval of a Claude account, the one an account near a bar gets. See Sample interval.
policy.maxWaitMs3600000 (1 hour)The depleted-pool auto-wait bound. See Depleted-pool wait.
policy.checkIntervalMs60000, minimum 10000The periodic check tick. See Check timer.
policy.accountReleaseMssession 1800000 (30 minutes), weekly 18000000 (5 hours)How close to its reset a window is when a thresholds.accounts entry stops holding the account under the global bar.
hub.port8317, the CLIProxyAPI defaultThe loopback port the usage hub listens on (tokenmaxxing serve and its background service). See Usage hub.

Bars

thresholds.session is both the trigger and the candidate screen, for Claude and Codex alike. See How switching decides. The former array form (the session ladder) is rejected: config loading fails with a zod message naming thresholds.session.

Projection margin

  • policy.projectionMargin is subtracted from the session threshold only, so one large turn is less likely to jump the 5-hour window from under the bar to over the hard limit.
  • It must stay below every session threshold, thresholds.accounts included.
  • The weekly bar takes no margin because a single turn is too small a fraction of the week to overshoot it, and margin there would only strand use-it-or-lose-it headroom.

Per-account bars

  • An account named in thresholds.accounts uses its own pair in place of thresholds.session and thresholds.weekly, in any pool, with the same projection margin on the session threshold, until a window nears its reset.
  • policy.accountReleaseMs sets how near, with one value for the session window and one for the weekly windows (defaults 1800000 and 18000000, 30 minutes and 5 hours).
  • An entry with "credits": true (default false) marks an account that carries purchased usage credits: its windows never make it exhausted, so it stays usable past 100 percent of them, and its pair ranks it after every account with plan headroom left and moves a session off it to such an account.
  • A label that names no pooled account has no effect.

See How switching decides.

Buffered usage quota

Every displayed usage percent is measured against the account's switch threshold, not against the provider's full limit. This covers the statusline, status, the usage note of add and auth, and the usage hub.

  • The threshold is the account's own entry in thresholds.accounts, else the global threshold, minus policy.projectionMargin for the session window.
  • The threshold is lifted near a reset the way switching lifts it (policy.accountReleaseMs).
  • 100 means the account reached its switch threshold, where tokenmaxxing stops placing sessions on it unless its thresholds.accounts entry sets credits. Usage past that point stays at 100.
  • The status-only grok pool has no switch threshold and shows the provider's figure.

The figure therefore reads higher than the usage Claude Code or Codex reports: with thresholds.session at 90, a session window at 45 percent reads 50. Switching decisions and the stored records use the provider's figures.

Binary pins

init writes the pin for each pool, and so does init --pi. The recursion-guard diagnostic tells you to fix claudeBin here when it stops pointing at the real Claude binary.

FieldOverride for one process
claudeBinTOKENMAXXING_CLAUDE_BIN
codexBinTOKENMAXXING_CODEX_BIN
grokBinTOKENMAXXING_GROK_BIN
piBinTOKENMAXXING_PI_BIN

Each variable overrides the file value for one process, except that init pins the binary it resolved into config.json, so an override set for init persists.

Sample interval

Each account's interval follows its cached figures: the window closest to its bar sets it, as 15 minutes times the fraction of that bar still unused, never under policy.usagePollTtlMs, so a value above 15 minutes sets every interval. With the default value:

AccountSampled
Emptyevery 15 minutes
At half its session barabout every 7.5 minutes
Within a tenth of a barevery 90 seconds

These accounts get a set interval instead:

AccountInterval
Session or weekly aggregate at or over its bar15 minutes, or policy.usagePollTtlMs when it is longer
No session or borrower on this host15 minutes, or policy.usagePollTtlMs when it is longer
No stored figurepolicy.usagePollTtlMs (see Periodic check)

How the samplers use it:

  • The check tick, status, and a seat's sample inside a hook decision all wait out the interval.
  • The hook decision samples only when the seat's tee is older than policy.usagePollTtlMs or the session's model is a gated family.
  • A seat whose sample keeps failing backs off exponentially from its interval, doubling per consecutive failure up to 30 minutes, and resets on the first success.
  • A Codex seat reads its usage GET when its cached figure is older than policy.usagePollTtlMs.

Depleted-pool wait

policy.maxWaitMs is the depleted-pool auto-wait bound (see When nothing is usable):

  1. Waiters fill resets within this bound first.
  2. When those are full, the overflow waits for the next reset with room, up to twice this bound out.
  3. When that horizon is full, the overflow joins the least-crowded reset.

Check timer

policy.checkIntervalMs is the periodic check tick, and every tick evaluates (see Periodic check).

  • The default is 60000. The minimum is 10000, because launchd does not spawn a job more than once every 10 seconds by default.
  • init writes it, rounded up to whole seconds, as the timer's interval. On Linux the systemd AccuracySec is a twelfth of it, at least one second.
  • The installed timer keeps its old tick until you run tokenmaxxing init again.
  • With a Nix-managed timer, set checkTimer.intervalSeconds to the same value; that option has the same 10-second floor.

Editing and validation

tokenmaxxing config prints the path and the effective values. Edit the file in an editor. A wrong-typed or out-of-range value fails the next load (check, status, the hooks) with the zod message naming the field. Unknown keys are ignored, the removed hardThresholds, policy.greedySessionFloor, and policy.greedySwapMargin included.

On this page