One quota, five agents: the parallel-agent meter problem and the function that solves it
Five Claude Code agents in five tmux panes do not get five quotas. They share one rolling 5-hour bucket and one seven_day_oauth_apps weekly bucket per Claude account, computed server-side and enforced server-side. ClaudeMeter is built around that fact. The function is dedupe_by_account in src/lib.rs; the CLI surface is claude-meter --json; the number you read is the same one Anthropic's own settings page reads.
ClaudeMeter (free, MIT, macOS, source at github.com/m13v/claude-meter). Anthropic's rolling 5-hour and seven_day_oauth_apps windows are per-account, not per-agent; every parallel Claude Code agent on the same account fills the same server-side fraction. ClaudeMeter's dedupe_by_account in src/lib.rs(lines 13–34) collapses N parallel browser/agent snapshots into one row keyed by account_email or org_uuid, and claude-meter --json prints that one row's usage.five_hour.utilization: the actual percent every agent is racing to fill. Local-log tools like ccusage report N per-session token totals instead, because they read ~/.claude/projects/*.jsonl and the plan ceiling does not exist on disk.
The five-pane reality
The Reddit thread that probably brought you here is some variant of: I have five Claude Code agents running in five git worktrees. ccusage shows me five totals. claude.ai settings page shows one number. Which one matters?
The one. Anthropic's rate enforcement runs on the server, against your account's org_uuid, and it does not care that you have spawned five processes. Every prompt any of those five agents sends increments the same five_hour bucket and the same seven_day_oauth_apps bucket. When one agent gets a 429, the next prompt from any sibling agent gets the same 429 milliseconds later, because the wall is on the account, not on the process.
This is the part of the parallel-agents pattern that the existing playbooks under-explain. Five agents do not give you five times the throughput. They give you faster bucket fill, and unless every agent reads the same shared signal, you also get five times the in-flight half-finished tasks when the wall hits.
“"Claude Code killed my refactor mid-way at 62% weekly used. Installed ClaudeMeter, now I watch the bar tick instead of guessing."”
Pro plan user, /r/ClaudeAI
Why the local sums do not equal the server fraction
The two most popular trackers people reach for first read ~/.claude/projects/*.jsonl. Each parallel agent writes its own JSONL transcript. ccusage tails them, sums input and output tokens, and prints a per- session total. Claude-Code-Usage-Monitor does the same with a different display.
Three things are missing from that signal that matter for the parallel-agent case:
- The plan denominator. Anthropic does not publish a fixed token cap. The ceiling is a server-computed fraction with peak-hour multipliers, per-model weights, and in 2026 explicit OAuth-app scoping. A local count has no denominator to divide by, so the percent it shows is a guess against a constant the user picks.
- Web-chat usage on the same account. If you also use claude.ai in a browser tab while five agents run, those messages move the same buckets. They never write a JSONL. Local-log tools cannot see them; the server already has.
- The seven_day_oauth_apps bucket. This field does not exist on disk. It is a server-side window that measures the OAuth-authenticated subset of your plan usage (Claude Code, agentic CLIs, MCP host loops that signed in via OAuth rather than carrying an
sk-ant-key). It is the bucket parallel agents fill fastest, and the local-log tools have nothing to read for it.
The cleanest way to see the gap: open claude.ai/settings/usage in DevTools, find the /api/organizations/{org_uuid}/usage request in Network, copy as cURL, run from your terminal. The response body has seven Window fields. None of them are derivable from a JSONL.
The architecture, in one diagram
ClaudeMeter sits between your N parallel agents and the same server-truth endpoint claude.ai/settings/usage renders. The browser extension authenticates by reusing your existing session cookie; the menu bar app holds the latest snapshot in memory and exposes it to any agent via the CLI.
Parallel agents, one shared meter
Five agent loops on the left. One meter in the middle. Three named server-side fractions on the right, each one a real field on the JSON body returned by /api/organizations/{org_uuid}/usage. The agents are different, the destinations are different, the meter in the middle is one process, one binary, one shared percent.
The function that does the merging: dedupe_by_account
When the menu bar app collects snapshots (one per Chromium browser the extension is loaded into, plus the keychain fallback path on Route B), each snapshot is tagged by the browser field. If you have Chrome and Arc both signed into the same Claude account, the bridge receives two snapshots in the same poll, both reflecting the same server quota. The CLI calls this function before printing, the menu bar calls it before rendering. Reading the source is the cleanest way to see what the meter actually believes about parallel agents.
The keying behavior is the load-bearing detail. Snapshots fold on account_email first, and on org_uuid when the email fetch failed. That mirrors how Anthropic accounts the quota: per-account, with the org as the database identity. The browsers (and by extension the parallel-agent surfaces those browsers proxy for) get merged into a single comma-separated string on the kept row. Output: browser: "Chrome, Arc" for one row, one five_hour.utilization.
What claude-meter --json returns to a parallel agent
The CLI is the programmatic surface for an agent loop. The shape comes straight from src/models.rs (the UsageResponse struct, lines 18–28, and the UsageSnapshot wrapper). One row per account, already deduped:
Note the browser string: "Chrome, Arc". That is two browsers' worth of session cookies feeding one snapshot, the post-dedupe shape. If five tmux agents and an IDE plugin all sit behind those same browsers, they all read this one row.
ClaudeMeter vs ccusage for the parallel-agent case
ccusage is a good tool, and the maintainers know what it is and is not. The mismatch in the parallel-agent case is not a bug; it is what happens when a local-log reader and a server quota are different signals. The grid below is what each tool can actually answer for someone running N parallel agents:
| Feature | ccusage / Claude-Code-Usage-Monitor | ClaudeMeter |
|---|---|---|
| What it measures | Local JSONL token sum (per-session) | Server-side bucket fraction (account-scoped) |
| N parallel agents share one number | No, you see N separate session totals | Yes (dedupe_by_account merges by email or org_uuid) |
| Sees rolling 5-hour bucket | No, infers from local activity timestamps | Yes (five_hour.utilization, five_hour.resets_at) |
| Sees seven_day_oauth_apps (the OAuth-app bucket) | No, the field name does not exist on disk | Yes, exposed as a named field |
| Counts claude.ai web chat on the same account | No, web chat leaves no JSONL | Yes, server-side total stacks both |
| Answers 'how close am I to the 429' | Indirectly (local token total, no plan denominator) | Directly (same fraction as claude.ai/settings/usage) |
Wiring it into a five-pane setup
Concretely, this is the path from brew install to all five tmux agents reading the same shared percent. The steps are short because there is one machine-level install and one per-agent loop call.
Install once for the whole machine
brew install --cask m13v/tap/claude-meter installs the menu bar app and the CLI binary. There is one binary per machine, not one per parallel agent. All N tmux panes, worktrees, and IDE windows talk to the same /Applications/ClaudeMeter.app/Contents/MacOS/claude-meter.
Load the unpacked browser extension once
Clone github.com/m13v/claude-meter, open chrome://extensions (or arc://extensions, brave://extensions, edge://extensions), enable Developer mode, Load unpacked, point at the extension/ folder. One browser is enough; visit claude.ai once and the chrome.alarms job at periodInMinutes: 1 starts pushing snapshots to the localhost bridge.
Confirm the menu bar shows one row per account
Click the menu bar icon. You should see one row per Claude account, with the browser field listing every Chromium-family browser the extension is loaded in (e.g. 'Chrome, Arc'). Multiple browsers, multiple terminals, multiple agents collapse into one row. That row's percent is the one all your parallel agents are racing to fill.
Run claude-meter --json from any parallel-agent loop
Each agent in your tmux/worktree/IDE setup shells out to /Applications/ClaudeMeter.app/Contents/MacOS/claude-meter --json once per iteration. The output is a Vec<UsageSnapshot> already deduped by account. Read usage.five_hour.utilization off the row that matches your agent's logged-in account and gate on it.
Sleep on usage.five_hour.resets_at, not on a guessed interval
When the threshold trips, the resets_at field on the same Window struct is an absolute UTC timestamp, not a rolling clock-time interval. Sleep until that timestamp plus a small grace period (30 seconds is plenty), then resume. Every parallel agent reading the same bucket gets the same resets_at and converges on the same wake-up moment.
The guard script every parallel agent calls
One script. Each agent shells out to it once per loop iteration. Every agent reads the same five_hour.utilization, gates on the same threshold, sleeps on the same resets_at. When the wall hits, all parallel agents converge to sleep, then resume together when the bucket releases capacity.
What it looks like when five agents share one bucket
A real run. Five tmux panes, each running the same agent loop calling parallel_guard.sh between iterations. The early lines show the bucket low and all agents proceeding. Later lines show every agent reading the same crossed threshold within the same poll window and every agent sleeping until the same resets_at.
No half-completed pull request, no half-filled migration, no 429 mid-tool-call. The five panes converge because the meter they read is the same meter the 429 fires off.
Edge cases the dedupe handles
Multiple browsers signed in
Chrome and Arc both have the extension and both have claude.ai sessions. Two POSTs hit the bridge per minute. dedupe_by_account folds them on email; the kept row's browser becomes "Chrome, Arc". You see one percent.
Email fetch fails for one snapshot
Network blip on /api/account. The email lookup returns None for that snapshot. The dedupe falls back to org_uuid so it still merges with siblings on the same account.
Two distinct accounts on the same machine
Personal account and work account. Two emails, two org_uuids. The dedupe correctly does not merge them; you get two rows, each with its own five_hour.utilization. An agent gates on whichever account it is logged into.
One agent ignores the guard
Pane 5 forgets to call parallel_guard.sh and sends through the wall. Pane 5 gets the 429; the bucket does not move because it is already at 100. The guarded panes still see the cap and sleep correctly. The shared signal is the floor; agents that ignore it pay their own cost.
Running parallel agents and tired of guessing?
Walk through your tmux/worktree setup with us; we will help you wire claude-meter --json into the loop and pick a threshold that matches your week.
FAQ: parallel agents and one quota
Is tracking parallel Claude Code sessions any different from tracking parallel agents?
It is the same problem under two names. People say 'parallel sessions' when they mean N concurrent Claude Code processes (tmux panes, git worktrees, IDE plugins, MCP host loops) running against the same Claude account, and 'parallel agents' when those processes are wired into agentic loops. Either way the meter you want is the per-account server-side fraction, not a sum of per-process token counts. ClaudeMeter's dedupe_by_account in src/lib.rs collapses all those parallel session surfaces into one row keyed by account_email or org_uuid, and claude-meter --json prints the usage.five_hour.utilization every parallel session is racing to fill.
If I run five parallel Claude Code agents, do I get five separate 5-hour quotas?
No. The rolling 5-hour window is one bucket per Claude account. Anthropic computes utilization on the server against your org_uuid, and every OAuth-authenticated client signed into that account adds to the same fraction. Five Claude Code agents in five tmux panes, three git worktrees, two browser tabs, the IDE plugin, and a Computer Use loop all stack into one five_hour.utilization number. You will hit the rolling wall at the same wall-clock minute regardless of how many parallel agents are racing toward it.
What about seven_day_oauth_apps, is that per-agent or per-account?
Per-account. seven_day_oauth_apps is a Window field on the JSON returned by GET https://claude.ai/api/organizations/{org_uuid}/usage. The qualifier is by authentication mode (OAuth-authenticated apps, which is how Claude Code, agentic CLIs, and MCP host loops sign in) not by client identity. Two parallel Claude Code agents are two OAuth apps as far as the auth flow is concerned, but they fold into the same seven_day_oauth_apps.utilization fraction because that bucket measures the subset of your account's plan usage that came from any OAuth-authenticated client. ClaudeMeter prints this field directly out of the snapshot returned by /api/organizations/{org}/usage.
Can ccusage show me the unified server quota across my parallel agents?
No, and not because the tool is bad, because of where it reads. ccusage walks ~/.claude/projects/*.jsonl on disk and sums the inputTokens and outputTokens fields recorded in each transcript line. Each parallel agent writes its own JSONL, so ccusage will show you N per-session token totals, and you can sum them yourself, but the sum is a numerator with no denominator. The plan ceiling Anthropic enforces against does not exist on disk. ccusage at 12 percent and claude.ai at 91 percent is the predictable mismatch when several agents have been running for hours; the local count and the server fraction are two different measurements.
How does ClaudeMeter merge usage from N parallel agent surfaces into one number?
It does not need to merge agent-level usage; the server already did that work. What it does merge is multiple snapshot rows that point at the same Claude account. The function is dedupe_by_account in src/lib.rs of the m13v/claude-meter repo. It walks the Vec<UsageSnapshot> returned by the fetcher, keys on account_email (falling back to org_uuid when the email fetch failed), and folds duplicates into a single row whose browser field becomes a comma-separated list like 'Chrome, Arc'. The five_hour.utilization on that one row is the same fraction every parallel agent on that account is racing to fill.
I run agents in tmux panes, not browsers. Does the extension still help?
Yes, because the extension is doing one job: keeping a fresh claude.ai session cookie reachable to the menu bar app via the localhost bridge at 127.0.0.1:63762. The terminal-side agents do not need their own extension. As long as one Chromium-family browser (Chrome, Arc, Brave, Edge) has the extension loaded and you have visited claude.ai once, the extension fires every minute (extension/background.js POLL_MINUTES = 1), POSTs the snapshot to the bridge, and the menu bar reflects the live percent for any number of headless tmux agents on that same account.
What if my parallel agents are signed into different Claude accounts?
Then you get one snapshot row per account, not collapsed. dedupe_by_account is account-scoped: it merges entries that share an email or org uuid. Agents on account A and agents on account B will appear as two rows in claude-meter --json, each with its own five_hour.utilization, seven_day.utilization, and seven_day_oauth_apps.utilization. That is the right answer for the multi-tenant case. The menu bar app shows a row per account; the CLI prints them as an array.
Is there a CLI shape my parallel-agent runner can read between iterations?
claude-meter --json. The binary is at /Applications/ClaudeMeter.app/Contents/MacOS/claude-meter when installed via brew. Running it prints a Vec<UsageSnapshot>, each snapshot with org_uuid, browser, account_email, fetched_at, and three sub-objects: usage, overage, subscription. The fields a parallel-agent guard cares about are usage.five_hour.utilization, usage.five_hour.resets_at, usage.seven_day_oauth_apps.utilization, and overage.out_of_credits. The shape lives in src/models.rs (UsageResponse and Window structs). Pipe to jq, ingest in Python, parse in Rust; same numbers as the menu bar.
Why not just count tokens locally and divide by the published cap?
Because there is no published cap to divide by. The plan ceiling Anthropic enforces against is not a fixed token budget. It is a server-computed fraction with peak-hour multipliers, per-model weights, and (in 2026) explicit OAuth-app scoping that all happen on Anthropic's side. The same prompt run at 11 PM Pacific and at 11 AM Pacific does not move the local token total differently, but it moves the server fraction differently. A local divider produces a confident-looking percent that diverges from the 429-firing percent in ways the user cannot debug. The right number is the one Anthropic's own settings page reads, which is /api/organizations/{org_uuid}/usage.
Does the menu bar show parallel-agent activity in real time, or just on a poll?
The cadence is a 60-second poll. extension/background.js sets chrome.alarms with periodInMinutes: 1, fetches /api/account, /api/organizations/{org}/usage, /api/organizations/{org}/overage_spend_limit, /api/organizations/{org}/subscription_details, and POSTs the snapshot to 127.0.0.1:63762. The menu bar app applies the new percent on receipt. Sub-minute resolution is not the goal; the rolling 5-hour window does not move that fast for any reasonable parallel-agent setup, and a tighter cadence would burn quota of its own without the user seeing a meaningfully different number.
What happens if one parallel agent crashes the rate limit and a sibling agent keeps running?
The 429 fires against the account, not against a specific agent. The sibling agent's next prompt also returns rate_limit_error from the same five_hour bucket because the bucket is shared. The right fix is to gate every parallel agent on the same shared signal before it sends, not to wait for each to discover the wall on its own. claude-meter --json once per iteration in each agent's loop reads the same number, so any agent over the threshold can sleep until usage.five_hour.resets_at instead of producing N broken half-completed tasks at 100 percent.
Guides that pair with the parallel-agent meter
Related
The seven_day_oauth_apps Bucket Almost Nobody Names
Your agentic loop has its own private weekly bucket separate from the 5-hour and the all-up 7-day. Here is the field name and the only free tracker that surfaces it.
Claude Pro Usage Meter for Browser Automation Workflows
Wire ClaudeMeter into a Playwright or Computer Use loop so the script gates itself on five_hour.utilization before Anthropic returns 429.
Local Claude Code Count vs Server Quota
Why ccusage at 5 percent and claude.ai at 90 percent is the predictable mismatch, and which number to trust when the 429 fires.