An execution-policy layer for Claude Code. It reads how much of your usage allowance is left, combines that with task size, and tells Claude how to work: how much to explore, how many subagents to use, how much to implement, how hard to validate, and when to checkpoint or stop.
Usage monitors provide observability. Claude Pace turns local signals into an execution policy.
It works in every environment with no setup — terminal, VSCode extension, JetBrains, headless -p runs — because it does not depend on a status line being wired.
As a plugin (recommended):
claude plugin marketplace add ablhub/claude-pace
claude plugin install claude-pace@claude-paceAs a user-level skill:
git clone https://github.com/ablhub/claude-pace.git && cd claude-pace && ./install.shThen invoke it: /claude-pace (skill install) or /claude-pace:claude-pace (plugin install). Requires Python 3.10+ (standard library only) on macOS or Linux.
| File | Purpose |
|---|---|
scripts/pace.py |
the whole implementation — status, bridge, enable, calibrate |
skills/claude-pace/SKILL.md |
instructions Claude follows |
README.md |
this document |
Plus a plugin manifest, one test file, CI, and a two-file installer.
Claude Code exposes exact rate-limit percentages only to status-line commands, over stdin. That channel does not exist everywhere: verified on Claude Code 2.1.170, status-line commands do not execute in VSCode-extension sessions or headless -p runs, no hook payload (SessionStart, UserPromptSubmit, Stop) carries rate-limit fields, and no local cache or transcript persists them. A design that needs a wired status line therefore leaves most users on a task-size-only fallback — which is exactly the bug this version fixes.
So Claude Pace reads two tiers and reports which one it used:
| Tier | signal_quality |
Source | Availability |
|---|---|---|---|
| 1 | measured |
authoritative status-line JSON, saved by pace.py bridge (or any monitor writing the same schema) |
terminal sessions with the status line wired |
| 2 | estimated-calibrated / estimated-plan-default |
your local transcripts, which record per-message token usage | everywhere, always |
| 3 | none |
task size only (no plan and no calibration) | last resort |
Every Claude Code session writes ~/.claude/projects/**/*.jsonl with per-message token counts and timestamps, in every environment. Claude Pace folds those into hourly buckets (reading only token counts, timestamps, model names, and message ids — never prompts, replies, or file contents), using a cost-weighted token metric that mirrors relative token pricing:
weighted = input×1 + cache_creation×1.25 + cache_read×0.1 + output×5
It then divides the rolling 5-hour and 7-day totals by a window budget:
- Calibrated budget (recommended) — pair a real percentage with the token total for the same fixed window. Two ways to get one: run
pace.py calibrateand type what your usage screen says (works everywhere, takes ten seconds), or enable the status line sobridgecalibrates automatically in terminal sessions. Either way, every environment on that machine inherits measurement-grade numbers. A window with no reset anchor is skipped rather than guessed, and the numerator deliberately under-counts so a learned budget errs small. - Plan-anchored default — until then, budgets are scaled from two measured Max-5x-tier readings by the published plan multipliers. Treat them as within a factor of ~2: real limits move with promotions (a "+50% weekly through Aug 19" promo shifted one test account's weekly budget from 39.5M to 77.2M weighted tokens), with plan type, and with how much allowance you spend outside Claude Code. Override directly with
CLAUDE_PACE_BUDGETS='{"short_window":30000000}'.
Open Settings → Usage (or /usage) and copy the numbers in:
python3 ~/.claude/skills/claude-pace/scripts/pace.py calibrate \
--session-used 58 --session-resets-in 4m \
--weekly-used 22 --weekly-resets "Mon 9:59 AM"Verified against a real screen: with that input, status reported 42% session / 78% weekly remaining — exactly what the UI showed. Add --model-used 23 --model-name fable to calibrate a per-model bar (the model must be named, because per-model caps differ). Calibration older than 14 days is downgraded and flagged, since promotions and plan changes silently move the goalposts.
Cost: the first call parses up to a week of transcripts (~1s here); later calls resume from a byte offset (~0.15s). Bounded by --scan-budget seconds.
A fixed token budget is only as good as the limit it was measured against, and limits move — promotions start and end, plans change, allowance gets spent outside Claude Code. Three mechanisms keep the estimate from drifting into confident nonsense:
- Promotion awareness. Claude Code caches notices like
+50% weekly limits promo through Aug 19locally (undocumented, parsed defensively). If a boost ended after a budget was calibrated, that budget is now too generous, so it is discounted by the boost, the window is marked uncertain, and you are told to recalibrate. Verified end-to-end on a live account with an active promotion. - Step-change detection. Limits jump rather than drift, so a new reading that disagrees with the stored budget by more than 35% replaces it outright instead of being averaged in over many samples — one reading is enough to re-learn a changed limit.
- Self-disproof. If consumption passes the assumed limit while Claude is plainly still working, the assumption is simply wrong: no percentage is reported for that window (a false "exhausted" is worse than no number), the proven consumption is remembered as a floor so later windows start from something at least that large, and you are pointed at
calibrate.
An explicitly configured budget (CLAUDE_PACE_BUDGETS) always outranks these inferences.
Estimates are approximations, so they are deliberately constrained:
- Because "no signal" already yields the most permissive mode, an estimate can only tighten the policy, never loosen it.
- Uncertainty is tracked per window: a window sized by a plan default, a stale or promo-invalidated calibration, or a time-truncated scan may tighten as far as
lowbut can never assertcritical. Only ameasuredreading — or a calibrated window that is itself the governing signal — stops work outright. - Per-model weekly caps (the "Fable only" bar) vary too much to guess, so they are estimated only after calibration, and only for the model family that was calibrated;
measuredmode always reports them when Claude Code provides them. - Estimation uses rolling windows and counts the boundary hour in full — biased toward stricter, never rosier. Timestamps more than an hour in the future (clock skew) are dropped rather than counted.
- Multiple concurrent sessions cooperate through a lock file; a session that finds the cache busy reads it instead of racing a write.
python3 ~/.claude/skills/claude-pace/scripts/pace.py enable # or: ./install.sh --enable-statuslineThis installs the runner at a stable path and points your statusLine at pace.py bridge, with refreshInterval: 30. settings.json is backed up first, symlinks are written through, the file mode is preserved, and an existing status line is wrapped, not replaced — your display stays byte-identical (stdin is passed through exactly; the original runs under /bin/sh, as Claude Code does) while the payload also feeds the bridge. The original command is saved to ~/.claude/claude-pace/original-statusline.cmd; undo by restoring the printed backup.
Universal safe thresholds — Claude Pace defaults, not Anthropic-defined — applied to the most restrictive available signal, identically on every plan (percentages are already relative to your own allowance):
| Mode | Remaining | Exploration | Subagents | Validation | Broad refactor | Checkpoint |
|---|---|---|---|---|---|---|
| healthy | > 60% | normal | ≤ 4 | comprehensive | yes | — |
| moderate | 30–60% | focused | ≤ 2 | targeted + critical integration | strong justification | — |
| low | 10–30% | targeted | ≤ 1 | targeted | no | after next unit |
| critical | < 10% | current task only | 0 | essential only | no | + continuation plan, then stop |
- small — validation capped at targeted even in healthy/moderate mode.
- medium — no adjustment.
- large — mode demoted one step, so migrations become constrained earlier.
- open-ended — demoted one step and a checkpoint is always recommended.
The plan is reporting-only — it sizes the estimate, never the thresholds. Resolution order: --plan → $CLAUDE_PACE_PLAN → "plan" in the state file → best-effort local detection → unknown. Detection reads one undocumented field (the rate-limit tier) from ~/.claude.json and emits only the mapped name (pro / max-5x / max-20x); it may break after a Claude Code update, and every failure degrades to unknown. Disable with --no-detect-plan or CLAUDE_PACE_DETECT_PLAN=0.
python3 scripts/pace.py --task-size large # human-readable
python3 scripts/pace.py status --json --task-size small
python3 scripts/pace.py status --no-estimate # tier 1 only
python3 scripts/pace.py calibrate --session-used 58 --session-resets-in 4m
python3 scripts/pace.py enable # wire the status lineFeeding it from another monitor: write this schema to ~/.claude/claude-pace/usage-state.json (or point $CLAUDE_PACE_STATE anywhere). five_hour/seven_day are accepted as aliases, and raw Claude Code status-line JSON is accepted as-is.
{
"available": true,
"updated_at": "2026-08-13T10:00:00Z",
"short_window": { "used_percentage": 25, "remaining_percentage": 75, "resets_at": 1786625145 },
"weekly": { "used_percentage": 40, "remaining_percentage": 60 },
"model_weekly": { "used_percentage": 45, "remaining_percentage": 55 },
"context": { "used_percentage": 35, "remaining_percentage": 65 }
}Project rule for CLAUDE.md (advisory — it cannot guarantee invocation):
- Before broad repository analysis, a large implementation, a refactor, multiple subagents, or extensive
test runs, invoke /claude-pace and follow its policy. Skip it for trivial edits. Re-check after each
major phase; if it reports `critical`, finish the current unit and write a continuation plan.Everything is local:
- no network requests, no telemetry, nothing uploaded;
- no prompts, replies, or repository contents are read or stored — estimation reads only token counts, timestamps, model names, and message ids, and its cache keys transcripts by hash so no project or file paths are written to disk;
- the status-line bridge persists only normalized usage windows; session ids, paths, workspace info, and cost are parsed and discarded;
- plan detection reads exactly one config field and never stores or emits it;
- state files are written atomically with mode
0600; - settings are modified only by an explicit
enable, which backs up first and never replaces an existing status line.
- It does not increase, bypass, or modify Anthropic limits, and cannot know exact usage where Claude Code does not expose it.
- Transcripts cover Claude Code only, while your usage screen counts the whole account (desktop/web conversations, Cowork, and so on). If you spend a large share of your allowance outside Claude Code, an uncalibrated estimate under-counts it; calibrating captures your current mix, so re-run
calibrateif that mix changes a lot. - Exact percentages require a Claude.ai subscription (
rate_limitsis absent on API-key auth) and a status-line-capable session; otherwise the estimate is an approximation, labeled as such. - It does not guarantee automatic skill invocation, does not change the main model, and does not enforce policy continuously during a response — it sets the plan Claude then follows.
python3 -m unittest discover -s tests -v
bash -n install.sh
claude plugin validate .MIT — see LICENSE. Copyright (c) 2026 Abylay Sagyndyk.
Unofficial community project. Not affiliated with, endorsed by, or supported by Anthropic. Thresholds, weights, and budget defaults are project choices.