Skip to content

Add Usage & Limits: tokens, cost and rate limits per agent CLI - #383

Open
0x92 wants to merge 2 commits into
dcouple:mainfrom
0x92:feature/usage-and-limits
Open

Add Usage & Limits: tokens, cost and rate limits per agent CLI#383
0x92 wants to merge 2 commits into
dcouple:mainfrom
0x92:feature/usage-and-limits

Conversation

@0x92

@0x92 0x92 commented Aug 11, 2026

Copy link
Copy Markdown

Description

Pane runs Claude and Codex as PTYs, so no token accounting flows through the app
itself. The authoritative record is each CLI's own transcript, which this indexes
read-only and incrementally.

  • Reads ~/.claude/projects/**/*.jsonl and ~/.codex/sessions/**/*.jsonl,
    resuming from a byte offset per file so a re-scan is cheap
  • Totals, a hoverable time series, per-model, per-provider and per-project
    breakdowns, and the cache hit rate with the money it saved
  • Provider-reported quota where it exists (Codex writes it into every
    token_count event); a rolling 5h window with a settable limit otherwise
  • Costs are labelled "at API prices", not as a bill: these tokens are usually
    paid for by a flat-rate plan

Prices are a bundled table with a visible as-of date; a model without an entry is
reported as unpriced rather than silently costing zero. A parser_version column
lets a parser fix invalidate already-indexed files instead of only applying to
future transcripts.

Type of Change

  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING.md guidelines
  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • New and existing unit tests pass locally with my changes
  • I have run pnpm typecheck and pnpm lint locally
  • I have tested the Electron app locally with pnpm electron-dev
  • I have added tests that prove my fix is effective or that my feature works

Critical Areas Modified

  • State management/IPC events (three new usage: channels through the shared
    registry; new usage_files, usage_events and usage_rate_limits tables)

Screenshots (if applicable)

image

Additional Notes

Tests: parser (20), scanner (15), pricing (13), aggregator (23), plus a schema
guard for the rule that schema.sql is split on ; at startup — a semicolon
inside a comment silently breaks database initialisation.

Known limitation, noted in the UI: the scanner reads this machine's home
directory only, so agents running inside a WSL distro are not counted.

These four feature PRs are independent but all add an entry to the same
navigation plumbing (navigationStore's ActiveView, the two sidebar
components, preload.ts, api.ts, electron.d.ts). Whichever lands first,
the others need a small rebase there — no logic overlaps.

Not done: the packaged-build check from CONTRIBUTING. I develop on Windows,
so pnpm build:mac was not run.

0x92 added 2 commits August 11, 2026 11:45
Pane runs Claude and Codex as PTYs, so no token accounting flows through
the app. The authoritative record is each CLI's own transcript, which this
indexes read-only and incrementally.

- Reads ~/.claude/projects/**/*.jsonl and ~/.codex/sessions/**/*.jsonl,
  resuming from a byte offset per file so a re-scan is cheap
- Totals, a hoverable time series, per-model, per-provider and per-project
  breakdowns, and the cache hit rate with the money it saved
- Provider-reported quota where it exists (Codex writes it into every
  token_count event); a rolling 5h window with a settable limit otherwise
- Costs are labelled "at API prices", not as a bill: these tokens are
  usually paid for by a flat-rate plan

Prices are a bundled table with a visible as-of date, and any model without
an entry is reported as unpriced rather than silently costing zero.

Tests: parser (20), scanner (15), pricing (13), aggregator (23), plus a
schema guard for the semicolon-in-comment rule that splitting schema.sql on
";" imposes.
Codex states the model, session id and cwd once, on the session_meta line
at the top of a transcript; its token_count events carry none of them.
scanJsonlFile built a fresh CodexParseContext on every pass, so a scan
resuming at a stored byte offset was past those lines with nothing to
stand in for them. Every event it produced fell back to model "codex",
which matches no entry in the price table, with a null session and a null
cwd — so the cost went unpriced and the per-project breakdown lost the
work. The watcher rescans roughly every three seconds while an agent is
running, which made this the normal case: only the first token_count of a
session was ever attributed correctly.

The context now travels with the cursor it belongs to. scanJsonlFile
takes the previous pass's snapshot and returns the one at its own end;
usageManager stores it in usage_files.parse_context and hands it back,
except when the file is being read from byte 0 again, where a stored
context would describe bytes that are gone — the rotation and truncation
case.

Quota samples are deliberately left out of the snapshot: they have their
own table and their own capture time, and replaying one would keep
re-announcing a reading nobody took.

USAGE_PARSER_VERSION goes to 3 so the rows the old parser mis-filed are
read again rather than silently trusted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant