
seatledger
io.github.agentwaresv0.2.0Updated Oct 8, 2026
Local ledger of Claude Code and Codex tokens, API-equivalent cost, limits and token-rate changes.
Overview
Reads local Claude Code and Codex transcripts to report token usage, API-equivalent cost, limits and rate changes.
- What it does
- seatledger reads the transcripts Claude Code and Codex already keep on the machine and turns them into a local ledger: tokens and API-equivalent dollars by day, project folder, model and client, plus burn rate toward limits you set. Its rate-change detector flags days when tokens per request, cache-read share or tokens per turn step up, reporting the date and client version where the change starts. The MCP server is read-only and exposes seatledger_usage_summary, seatledger_rate_changes and, if the machine joined a team ledger, seatledger_team_summary.
- When to use it
- Use it when you want to see what your coding-agent seats actually consumed, compare plans or months by API-equivalent cost, or get an early signal that the same work started costing more tokens after a client update. It is a local, account-free tool, so it suits individual developers and small teams rather than vendor-side billing.
- Requirements
- Runs locally over stdio via npx (Node.js). Reads ~/.claude/projects and ~/.codex/sessions by default; CLAUDE_CONFIG_DIR, CODEX_HOME and SEATLEDGER_HOME override those locations. No account or API key is needed for local use. The optional team ledger needs an invite link and a push key, stored by seatledger team join or supplied as SEATLEDGER_KEY.
Installation
In SourceWeft
- Open seatledger in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
seatledger
What your coding-agent seats and tokens bought, from your own machine — and when the rate changed.
[seatledger and seatledger rates on synthetic history]
The picture is the real output of npx seatledger demo, which runs on synthetic history. It
is regenerated by pnpm screenshot and a test fails if it drifts from what the CLI prints.
seatledger reads the transcripts Claude Code and Codex already keep on your machine and tells you:
- tokens and API-equivalent dollars by day, project folder, model and client;
- how fast you are burning toward limits you set, and when you would reach them at this rate;
- when the rate changed: the same work suddenly costing more tokens per request, cache reads dropping because writes moved to a shorter cache lifetime, more tokens per turn after a client update, or Codex's own 5-hour window filling faster for the same tokens — with the date and the client version where it starts.
No vendor will build that last one: it is an alarm about their own rate. seatledger is MIT, has no
telemetry and no runtime dependencies, and needs no account. It makes no network calls unless you
join a team ledger and run seatledger push — and then it sends daily
aggregates only, which seatledger push --dry-run prints in full.
Commands
Every command takes --json, --client claude-code|codex, --claude-dir, --codex-dir and
--no-cache. Without npm: npx github:agentwares/seatledger runs the same CLI from this
repository (it ships its built dist/).
What it reads
Checked on 7 October 2026 against Claude Code transcripts written by versions up to 2.1.286 (the
changelog was at 2.1.292) and
Codex rollouts written by 0.144–0.159, plus the Codex source at
rust-v0.160.1
(TokenUsage, TokenUsageRecord, RateLimitSnapshot). Things the formats do that a naive
reader gets wrong, and seatledger handles:
- Claude Code writes one response as several lines, and only the last carries the final
output_tokens. seatledger merges them permessage.id:requestIdand keeps the largest count. - The same response appears in more than one file (subagent transcripts, resumed and set-aside sessions); requests are deduplicated across files.
- Codex's
input_tokensalready includes cached and cache-written input. - Unknown fields are ignored and a line cut off mid-write is skipped, never fatal.
Not read (yet): Gemini CLI was not installed where this was built, so its local record could not be checked against real files; Cursor's local store is an undocumented SQLite database and the copy checked held no per-request token counts. Neither is guessed at.
API-equivalent, not your bill
Dollars are API-equivalent: what the same tokens would cost at the vendor's API list prices. On a Pro, Max, Plus or Team seat you pay a flat fee; this is what that seat's usage would have cost on the API, which is the number to compare seats, plans and months by. It is labelled everywhere it appears. Prices come from a dated table in the package, with its sources:
- Anthropic, platform.claude.com/docs/en/about-claude/pricing, read 7 Oct 2026 — base input, 5-minute and 1-hour cache writes, cache reads, output; fast mode; 1.1x for US-only inference.
- OpenAI, developers.openai.com/api/docs/pricing, read 7 Oct 2026 — input, cached input, cache writes, output, and long-context prices above 272K input tokens.
A model without a list price (Codex's internal codex-auto-review, for one) is counted in tokens
and its dollars are reported as unpriced, never estimated.
The rate-change detector
seatledger rates looks, per client and model, at complete days with at least 20 requests:
A day D is flagged when the median of D and up to 6 active days after it differs from the median of up to 7 active days before it by at least 30% (10 percentage points for shares), at least three quarters of the days on each side sit on their own side of the midpoint, and the difference is more than three times the day-to-day spread. It reports the date, the client version in use and whether D was the first day on it, the before and after values, and what the change is consistent with — for example:
From 30 Sep (Claude Code 2.1.230, the first day on it), cache reads per request fell 37%, cache writes per request rose 6.8x … — the transcript itself shows writes moving from the 1-hour to the 5-minute cache lifetime.
It sees requests on your machine, not the vendor's servers, so it never names a cause. A change in your own work (a new repository, a bigger task, more subagents) moves these numbers too, and when no client version change coincides it says so.
Limits
seatledger does not ship any vendor's plan limits. They are not published as token counts, they
change without notice, and a hard-coded number would be wrong in a way you could not see. Set your
own — the "busiest window in 30 days" figure is a good start if you hit the limit then. A 5-hour
window opens at your first request and lasts five hours, the way Claude Code and Codex describe
theirs; weekly is the rolling last 7 days. Codex also writes its own 5-hour and weekly
percentages to disk; seatledger shows the latest as Codex reported them.
Your history outlives the transcripts
Claude Code deletes transcripts older than cleanupPeriodDays, 30 days by default
(docs). seatledger keeps the counts it has
taken — never text — in ~/.seatledger/cache-v1/, one small file per transcript, so the ledger and
the rate baselines keep their history after the transcript is gone. It also makes later runs fast:
only new or changed transcripts are read. Delete the directory to forget it, or pass --no-cache.
The team ledger
The local ledger answers "what did my seat buy". A team lead paying for ten seats wants the same for everyone, kept longer than a laptop keeps it, and an email when the rate changes on anyone's machine. That is the hosted team ledger, run by agentwares:
The lead signs in with GitHub at
agentwares-agentcheck.vercel.app/seatledger,
which creates the team, and shares its invite link. Each developer runs
npx seatledger team join <link> --as <name> once, then npx seatledger push (by hand, or from a
cron or a session-end hook). An agent can create a free team with no human:
POST /api/seatledger/v1/teams {"accept_terms": true} returns an owner key and an invite link.
Exactly what push sends
One JSON document (seatledger.push/v1); seatledger push --dry-run prints it in full and sends
nothing.
days— every local day the push covers, from the first day this machine has history for. The ledger's rows for those days become exactly the pushed rows, so pushing a day again replaces it, never adds to it.rows— one per day × client × client version × model:requests,input_tokens,output_tokens,cache_read_tokens,cache_write_tokensandapi_equivalent_usd(null for a model without a list price).findings— whatseatledger ratesfound in at least the last 90 days, as numbers and ids: client, model, the day it starts, the client version and the one before it, whether that was the first day on it, and per metric the before and after medians. The sentence you read locally is rebuilt by the service from these numbers; no text is sent. A finding sent again is the same finding.
Never sent: prompt, response, tool or file content; file paths; session or request ids; your
project folder names — unless you pass --project-names, which splits rows by working-directory
folder name (letters, digits, ., _, -; anything else becomes -). Every text field the
service accepts is an id with no spaces and a short length limit; a field that could carry a
sentence is refused.
The first push sends up to 400 days (the plan keeps what it keeps and says which days it did not
store); later pushes start two days before the last one. --since 30d or --since 2026-09-01
overrides that. The key is your own (the owner can revoke it); it lives in
~/.seatledger/team.json, readable by you only, or in SEATLEDGER_KEY. The invite link's host is
where your pushes go; SEATLEDGER_URL overrides it.
From your agent
MCP (npx -y seatledger mcp, stdio, read-only): seatledger_usage_summary and
seatledger_rate_changes read this machine and make no request; seatledger_team_summary reads the
team ledger this machine joined, with its saved key (one HTTPS request, changes nothing). Strict
input schemas, errors with code, cause, fix, retryable.
Whatever a tool returns goes to your agent's model provider like any other tool result, project folder names included.
Claude Code plugin (and Copilot CLI, which reads the same marketplace file):
/plugin marketplace add agentwares/seatledger, then /plugin install seatledger@seatledger.
/seatledger:usage explains the ledger and your limits; /seatledger:rates explains any step
change.
Gemini CLI: gemini extensions install https://github.com/agentwares/seatledger, then
/seatledger:usage and /seatledger:rates.
Privacy
- Reads
~/.claude/projectsand~/.codex/sessions(or the directories you point it at). - Keeps counts, timestamps, request and session ids, model ids, client versions, working-directory folder names and the paths of the transcripts it read. It never stores or prints prompt, response, tool or file content: most transcript lines are skipped before they are parsed, and the records it keeps have no field that could hold text.
- Writes only to
~/.seatledger(limits.json,cache-v1/, andteam.jsononce you join a team), or$SEATLEDGER_HOME. - Has no runtime dependencies. Makes no network calls, except
seatledger push,seatledger teamand theseatledger_team_summarytool, which talk to the team ledger you joined and send what is listed under Exactly whatpushsends.
As a library
Develop
MIT © agentwares contributors.
Source: README.md at commit 7b7fa50
Tools
0Version history
1- v0.2.0LatestOct 8, 2026


