State directory layout

Every file and directory under ~/.config/tokenmaxxing

Everything lives under ~/.config/tokenmaxxing/. Override with TOKENMAXXING_HOME.

Hermetic runs

Every external path has an env override so tests stay hermetic. The timer and hub units are not paths, so:

  • A hermetic run of init builds a full isolated HOME and sets TOKENMAXXING_SKIP_TIMER=1 and TOKENMAXXING_SKIP_HUB=1.
  • uninstall addresses the login user's service instances only when HOME is the login home (see Troubleshooting).

Layout

The tree lists the entries in the order of the sections below. Open a folder to see the entries this page names inside it.

config.json
accounts.json
lock
api-keys.json
wait-queue.json
tokenmaxxing.log
tokenmaxxing.log.old
spawnrate.json
update.json
update.lock
check.stderr.log (macOS only)
hub.stderr.log (macOS only)
hub-key
codex-accounts.json
codex-lock
grok-accounts.json
grok-lock

Configuration and accounts

PathWhat it holds
config.jsonYour configuration (sparse; defaults apply per field)
accounts.jsonNon-secret index of pooled Claude accounts, never tokens. The index names no active account: there is no pool-wide active account, each session has its own seat. Fields: Account index fields
lockThe flock file that serializes decisions, placement, and sampling
stores/<uuid8>/One Claude Code credential store per pooled account. On Linux it holds the account's .credentials.json (0600 in a 0700 directory) and Claude Code's refresh lock. On macOS the credential is the keychain item keyed by this path, and the directory holds only the lock
onboard/Throwaway config home for init, add, and auth logins (deleted after harvest, credential included)
api-keys.jsonNon-secret index of stored Anthropic API keys: {version: 1, keys}, each key with id (8 random hex characters), label, workspaceId (optional), creditUsd (the balance you entered, optional), spentUsd, creditSetAt (epoch ms), refusedAt (epoch ms, set on billing_error, optional), and addedAt (epoch ms), plus baselines, the last cumulative cost the supervisor recorded per live session id ({usd, at}), which it bills to a key only as growth; entries older than 30 days are dropped on the next write. Every read-modify-write runs under lock, and a file that exists but fails to parse stops the command instead of reading as no keys
api-keys/<id>One API key per file, 0600 in a 0700 directory. See Credential storage

Account index fields

Each account in accounts.json has these fields.

  • Required: id, label, email, tier, addedAt, and windows.
  • Optional: lastUsageAt, lastProbeAt, probeFails, storeFails, usageRetryAt, enforcedUntil, needsReauth, and oauthAccount.
FieldWhat it holds
windowsThe cached windows: the session and weekly windows unnamed, per-model caps named, each with its duration and sample time
probeFailsConsecutive failed seat samples, for the backoff
storeFailsConsecutive failed store reads on the check tick; five stamp needsReauth
usageRetryAtThe time the retry-after of the usage endpoint's HTTP 429 names; no usage read is sent for the account before it
oauthAccountThe object used to verify identity on auth

A window is {name, usedPercentage, resetsAt, windowSeconds, sampledAt}. name is null for the session and weekly windows and the limit or model name otherwise.

Running sessions

PathWhat it holds
usage/<uuid8>.jsonThe tee per account: the aggregate window snapshot pushed by the sessions running on that account. Its mtime is the feed's liveness heartbeat
live/<session-id>One PID-validated presence file per running supervised Claude session: the account id, the pid, and the start time. A session on an API key carries apiKeyId and an empty account id, and counts toward the key, not toward any account
live/seat-<pid>One record per Claude account lent by seat <pid>, validated against that pid
sessions/<session-id>.jsonPer-managed-session launch flags the supervisor persists for respawns, plus current, the live session id after a /clear or an in-session /resume. Pruned after 30 days idle (matching claude's own transcript retention), never while the session's record under live/ exists
cost/<session-id>.jsonWritten only while api-keys.json exists: the session's latest cumulative cost estimate ({sessionId, usd}), from the statusline in a terminal session and from the result lines in a stream-json session. The supervisor reads it and deletes it when the session ends
respawn/<session-id>Respawn markers the supervisor watches (fields below)
wait-queue.jsonOne {sessionId, accountId, at, waitUntil} claim per supervised session that is moving or waiting, naming the account it relaunches on (lifecycle below)

Placement counts each record under live/ as one session on its account, and rm refuses an account with a living record.

A respawn marker holds:

  • the target account, or, for a move onto an API key, apiKeyId with an empty account id (a hook writes a key marker only for a supervisor that sets TOKENMAXXING_API_KEY_ID on its child, so a supervisor from an older release never receives one)
  • the session to resume
  • a waitUntil: now for a plain move, the reset for a depleted-pool wait
  • whether to compact first
  • the origin: the hook or the seat watch that wrote it, which picks the resume prompt
  • the launch time of the process the marker was written for
  • after a usage-credits refusal, the accounts that have refused the session

A wait-queue.json claim ends one of two ways:

  • Placement counts a claimed session on the account its claim names.
  • At most eight sessions wait on one account while the rest take the next reset with room, or the least-crowded reset when the horizon is full.

Shims, logs, and service files

PathWhat it holds
bin/The PATH shims: claude, codex, pi (after init --pi), and the tokenmaxxing / xx entry points
tokenmaxxing.logAppend-only event log, rotated to tokenmaxxing.log.old once it passes 5 MB
spawnrate.jsonThe time and process id of each wrapper entry in the last 30 seconds, which the recursion guard reads to find a chain of nested entries
update.json, update.lockThe last self-update attempt's timestamp and the flock file that serializes it (Bun global installs only; see Automatic updates)
check.stderr.log, hub.stderr.logmacOS only: the launchd check job's and hub service's stderr (systemd sends it to the journal)
hub-keyThe management key tokenmaxxing serve requires, mode 0600, minted on the first run; a key written by hand is used as it is. See Usage hub

Codex pool

The codex-* entries are the Codex pool's own state.

PathWhat it holds
codex-accounts.jsonThe same index shape as accounts.json, without oauthAccount. No active account either: each session has its own seat
codex-stores/<uuid8>/One store per pooled Codex account: its auth.json, everything else symlinked to the shared ~/.codex
codex-live/One PID-validated presence file per running supervised codex session, and one seat-<pid> reservation per borrow, validated against the pid the record names (table below), so a live account is never a session placement or move target
BorrowIts seat-<pid> record names
seat --codexThe caller's pid
A shim-run exec, e, review, or bare app-serverThe codex child's pid

A borrow picks the account the fewest records name.

pi stores

PathWhat it holds
pi-stores/claude/<uuid8>/, pi-stores/codex/<uuid8>/One pi store per pooled Claude or Codex account that has a pi login, laid out as the diagram shows
pi-onboard/Throwaway pi agent directory for auth --pi logins (deleted after harvest, credential included)

A pi session's presence record goes to live/ or codex-live/. See pi support.

Status-only pools

The grok-* entries are the state of the status-only grok pool. See Status-only pools.

PathWhat it holds
grok-accounts.jsonThe same index shape
grok-stores/<uuid8>/auth.jsonOne 0600 store per account
grok-onboard/Throwaway login home

Outside the state directory

TargetWhat tokenmaxxing does with it
Claude Code's settings.jsonTouches the hook and statusline entries
The keychain items of its own stores (macOS)Touches them
codex's hooks.jsonTouches it
The periodic-check and usage-hub units in launchd or systemdTouches them
Your shell rcTouches the # tokenmaxxing PATH line
codex's config.tomlReads the credential-store setting and hook trust, and never writes it
pi's settings.json and trust.json, and a project's .pi/settings.jsonReads them to pick a pi session's pool and session directory
~/.pi/agentCreates only what is missing among settings.json, models-store.json, and trust.json (as {}) and the sessions and bin directories, so that every pi store can link them

Every onboarding login runs in a throwaway home under the state directory, never in the vendor CLI's own. tokenmaxxing no longer writes ~/.claude.json, Claude Code's default credential store, or codex's live auth.json.

After upgrading

Rebuild the pool

Version 1.37.0 moves every Claude credential into a per-account store, and the Codex pool moves to per-account stores the same way. Neither pool has a migration: rebuild it. init and add write the store from a fresh grant, and the index keeps its records, so labels and cached figures survive.

Claude poolCodex pool
A session the pool's supervisor starts runs onstores/<uuid8>/ and nothing elsecodex-stores/<uuid8>/ and nothing else
Log in the first accounttokenmaxxing init, through an isolated browser sign-intokenmaxxing init --codex, through an isolated device-auth login
Log in each other accounttokenmaxxing addtokenmaxxing add --codex
Index that keeps its recordsaccounts.jsoncodex-accounts.json
Retired stateNot read: the parked backups earlier versions kept (the creds/ files on Linux, the tokenmaxxing-cred-<uuid8> keychain items on macOS), the copy in Claude Code's default store, and the old backups usage.json, lastswap.json, depleted.json, and the sample/ probe homes the retired /usage sampler left behind. Not written: Claude Code's default storeNot read or written: the shared live auth.json rewrite, the codex-creds/ parked copies, the activeId label, the codex-lastswap.json cooldown clock, and the codex-reconcile/ signals
Delete yourselfcreds/ (it holds credentials), usage.json, lastswap.json, depleted.json, sample/, and the tokenmaxxing-cred-<uuid8> keychain itemscodex-creds/ (it holds credentials), codex-lastswap.json, and codex-reconcile/
Keeps your own login for sessions started outside the supervisorClaude Code's default storeCodex's default ~/.codex/auth.json

Index schema

accounts.json and codex-accounts.json are schema version 2:

  • version is 2, and accounts is the array.
  • There is no active field. A file that still carries activeId loads and drops the key on the next save.
  • A version 1 index fails the schema check, and every command throws does not match its schema until the file is repaired or removed.

The account fields and the window shape are in Account index fields.

On this page