Skip to content

About

Execution-policy layer for Claude Code: adapts exploration, subagents, scope, and validation to available usage signals, context pressure, and task size. Complements usage monitors.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

14 Commits

Folders and files

Repository files navigation

Claude Pace

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.

Install

As a plugin (recommended):

claude plugin marketplace add ablhub/claude-pace
claude plugin install claude-pace@claude-pace

As a user-level skill:

git clone https://github.com/ablhub/claude-pace.git && cd claude-pace && ./install.sh

Then invoke it: /claude-pace (skill install) or /claude-pace:claude-pace (plugin install). Requires Python 3.10+ (standard library only) on macOS or Linux.

The repository is three files

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.

How it gets usage data

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

How estimation works

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 calibrate and type what your usage screen says (works everywhere, takes ten seconds), or enable the status line so bridge calibrates 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}'.

Calibrating from your usage screen (ten seconds, any environment)

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.

Staying right when the limit itself changes

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 19 locally (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.

Guardrails on estimates

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 low but can never assert critical. Only a measured reading — 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; measured mode 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.

Exact numbers (optional, one command)

python3 ~/.claude/skills/claude-pace/scripts/pace.py enable   # or: ./install.sh --enable-statusline

This 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.

Modes

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

Task-size adjustment

  • 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.

Plan

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.

Usage

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 line

Feeding 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.

Privacy

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.

Limitations

  • 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 calibrate if that mix changes a lot.
  • Exact percentages require a Claude.ai subscription (rate_limits is 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.

Testing

python3 -m unittest discover -s tests -v
bash -n install.sh
claude plugin validate .

License

MIT — see LICENSE. Copyright (c) 2026 Abylay Sagyndyk.

Disclaimer

Unofficial community project. Not affiliated with, endorsed by, or supported by Anthropic. Thresholds, weights, and budget defaults are project choices.

About

Execution-policy layer for Claude Code: adapts exploration, subagents, scope, and validation to available usage signals, context pressure, and task size. Complements usage monitors.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages