claude-pacer
Health Uyari
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 8 GitHub stars
Code Basarisiz
- process.env — Environment variable access in budget-guard.cjs
- fs module — File system access in budget-guard.cjs
- fs module — File system access in extras/unix/schedule-resume.sh
- child_process — Shell command execution capability in statusline.cjs
- execSync — Synchronous shell command execution in statusline.cjs
- fs.rmSync — Destructive file system operation in statusline.cjs
- process.env — Environment variable access in statusline.cjs
- fs module — File system access in statusline.cjs
- child_process — Shell command execution capability in test_statusline.cjs
- spawnSync — Synchronous process spawning in test_statusline.cjs
- fs.rmSync — Destructive file system operation in test_statusline.cjs
- process.env — Environment variable access in test_statusline.cjs
- fs module — File system access in test_statusline.cjs
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
Statusline + budget guard + pacing verdict for Claude Code usage limits — the statusline is for you, the guard is for Claude, the verdict is for your agents
claude-pacer
A statusline + budget guard + pacing verdict for Claude Code usage limits.
繁體中文說明 → README.zh-TW.md · Story and walkthrough (blog, zh-TW) · English version of the post
Try the rendering without touching your config: node statusline.cjs --demo.
Refactor auth middleware │ 5h ▓▓▓┃░░░ 42%·2h13m │ 7d ▓▓▓▓┃▓░ 71%·3d2h │ Ctx ▓▓░░░░ 34% │ Fable 5·high
Refactor a…│5h▓▓░░42%│7d▓▓▓░71%│Ctx34%│Fable5·hi ← same line on a narrow terminal
There are many great Claude Code statuslines out there —
ccusage,
ccstatusline,
CCometixLine,
cc-statusline,
claude-powerline, … —
use whichever you like. This one exists
because a statusline alone never stopped an autonomous agent from blowing
through a rate limit at 2 AM. claude-pacer is three layers that share one data
file:
statusline.cjs— what you see: 5h / 7d usage, context-window
fullness, optional conversation topic. Numbers or bars.budget-guard.cjs— what Claude sees: a hook that injects wrap-up
instructions into the model's context at 85% / 93% usage, so long
autonomous runs wind down gracefully instead of dying mid-task.usage_verdict.py— what agents should run instead of interpreting
raw numbers: a one-line GO / PACE / STOP verdict that encodes the reset
arithmetic agents keep getting wrong.
Why this exists
It started with overnight runs dying mid-task: hand Claude Code a long
autonomous job, go to bed, and find it cut off at 2 AM by the 5-hour usage
window — context stranded, work half-done. Plenty of tools auto-send
"continue" after the crash; the point here is acting before the wall:
past 85% Claude stops launching new heavy work, at 93% it finishes the step
it's on cleanly and schedules its own resume in the same conversation — no
half-written files, no broken mid-operation state to untangle.
The statusline then fixes the small daily frictions of heavy multi-session
use:
- "Which conversation is this again?" — the topic segment names each
session when you're juggling several at once. - "How much runway do I have?" — usage bars with an elapsed-time marker
show at a glance whether you're burning faster than the clock. - "Wait, which model am I on?" — model + reasoning effort sit at the far
right, so you notice before spending premium-model quota on a trivial
task you forgot to switch back for. - "How close is compaction?" — the context gauge warns you before a
surprise compact eats your conversation state.
Install
Requirements & cost. Windows, macOS or Linux. Node.js (statusline + guard)
and Python 3 (verdict, optional); no npm or pip packages. A Claude Code Pro/Max
subscription for the usage numbers (see below). No accounts, no API keys, no
network calls, free (MIT).
git clone https://github.com/drpwchen/claude-pacer.git
In ~/.claude/settings.json:
{
"statusLine": {
"command": "node /path/to/claude-pacer/statusline.cjs"
},
"hooks": {
"UserPromptSubmit": [{ "hooks": [{ "type": "command",
"command": "node /path/to/claude-pacer/budget-guard.cjs" }] }],
"PostToolUse": [{ "hooks": [{ "type": "command",
"command": "node /path/to/claude-pacer/budget-guard.cjs" }] }]
}
}
On macOS / Linux, use an absolute path to node if Claude Code is
launched from a GUI or a launch agent: that process may not inherit the PATH
from your shell profile, and the statusline then silently renders nothing.which node gives you the path to paste (Homebrew: brew install node →/opt/homebrew/bin/node on Apple Silicon, /usr/local/bin/node on Intel).
The statusline works on its own; add the hooks only if you want the guard.
Usage percentages come from Claude Code's rate_limits statusline data, which
exists on Pro/Max subscriptions (API-key billing has no such windows).
Preview both display modes without touching your config:
node statusline.cjs --demo
You should see the statusline rendered at several widths, in both number and
bar modes.
🧋 Saved you some time? Buy me a drink.
Reading the statusline
| Segment | Meaning |
|---|---|
Ctx 34% |
Context window fullness (how close you are to compaction) |
5h 42% |
5-hour usage window, percent used |
2h13m left |
Time until this window resets |
t58% |
Percent of the window's time already elapsed — if usage% > time%, you're burning faster than the clock |
7d … |
Same three readings for the 7-day window |
Fable 5·high |
Current model and reasoning effort |
In bar mode the ┃ marker is the elapsed-time position, inserted between
bar cells (it never eats a fill cell, so the filled proportion always reads
true): filled bar past the marker = burning faster than the clock. Compact
tiers drop the marker — a 4-cell bar is too coarse for it.
Colors: green < 70% ≤ yellow < 90% ≤ red.
The line is responsive: it renders full-width first, and if that doesn't
fit the terminal it degrades step by step — full with a shorter topic, then
compact (4-cell bars paired with time remaining, since the bar already
shows usage), then percentages only.
Terminal width comes from the $COLUMNS env var, which Claude Code sets for
the statusline process since v2.1.153 (fallbacks: process.stdout.columns,
then probing the attached console — mode con on Windows, stty size </dev/tty elsewhere — cached 15 s). If width can't be determined the line
stays full — it never degrades on a guess. "width" in config.json overrides detection, and"tier" ("full" / "compact" / "minimal") pins a layout outright (always one line).
Two lines instead of truncation. Before compacting anything, the line
wraps ("wrap": "auto", the default): if the full layout doesn't fit even
with a shorter topic, Ctx + model move to a second line — and if the first
line is still too wide, 7d moves down with them. Each line then degrades on
its own, so on a narrow pane you still see the full model name and context
gauge instead of Opus 5.5·me…. Claude Code supports multi-line statuslines
natively. "wrap": "never" (or --no-wrap) keeps the old one-line
behavior.
Claude Code indents the statusline row and keeps a right margin, so a line
exactly $COLUMNS wide gets cut. The layout fits $COLUMNS minus"reserve" (default 4 = 2 indent + 2 margin). If you setstatusLine.padding in Claude Code's settings, add that to reserve; if
notifications on the right of the row still eat your line, raise it.
Configuration
Settings live in ~/.claude/claude-pacer/config.json (created by you; see
config.example.json). CLI flags override the file.
| Key | Default | Flag | Meaning |
|---|---|---|---|
display |
"bar" |
--bar / --number |
Bar gauges vs percent numbers |
topic |
true |
--topic / --no-topic |
Show conversation topic |
context |
true |
--context / --no-context |
Show context-window segment |
labels |
"en" |
— | "zh" renders 剩/時 labels |
model |
true |
— | Show model + reasoning effort (rightmost) |
topic_chars |
20 |
— | Topic truncation length |
bar_width |
6 |
— | Bar width in characters |
width |
null (auto) |
--width N |
Terminal columns for the responsive layout; unknown = stay full |
tier |
"auto" |
--tier T |
Pin a layout: full / compact / minimal |
wrap |
"auto" |
--wrap never / --no-wrap |
auto: move Ctx + model (then 7d) to a second line before compacting; never: always one line |
reserve |
4 |
--reserve N |
Columns Claude Code keeps for itself (indent + right margin); add your statusLine.padding |
State dir override (all three scripts): --dir <path> or $CLAUDE_PACER_DIR.
Topic mode
On by default ("topic": false or --no-topic to hide it). The topic is
resolved in priority order:
- Session title — Claude Code's own AI-generated/renamed session name
(/renameor automatic), the most accurate description of the session; - Transcript summary — the summary Claude Code writes on compaction;
- First user prompt — fallback for brand-new sessions.
CJK titles get their spaces stripped (they read fine without them and the
saved columns matter on narrow screens).
budget-guard
A hook on UserPromptSubmit + PostToolUse (so it also fires mid-turn during
long autonomous runs). Reads limits.json written by the statusline.
- soft (85%): tells Claude to finish in-flight work and start nothing big.
- hard (93%): tells Claude to wrap up NOW, schedule a one-shot resume a few
minutes after the window resets, report to the user, and end the turn. - Near-reset exemption (
near_reset_min, default 20): with ≤20 min left in
the window the stakes shrink — hitting the cap only pauses work until the
reset. The soft warning goes silent; the hard one downgrades to "work
normally, worst case is a brief pause, arm a one-shot resume if capped". builtin_auto_continue(defaultfalse): withfalsethe guard arms
the resume itself — the hard warning above (one-shot CronCreate, orhandoff.md+ the resume script if the terminal will close). Settrueto
rely on Claude Code's own Continue automatically at usage limit
(/config) instead. That feature only resumes a turn the limit
interrupted, so in this mode the guard never tells Claude to stop: the soft
warning goes silent, and the hard one says keep working, save in-progress
state, and launch no new subagent waves — subagents do not auto-continue
(they end as failed and the main session must resume them after the reset).truewas the default in v0.1.6; in the author's multi-session setup the
built-in resume never fired, so v0.1.7 reverted it — try it only if you've
seen it work for you.- Limit: the guard is only as fast as its samples. Usage is read when a
statusline renders (~every 2 min). A fleet of agents burning several %/min
can go from below 93% straight to the cap between two samples; then no
warning lands in time and no resume gets armed. For such runs, pace the
dispatch withusage_verdict.py/ pace mode rather than relying on the
hard warning. - Warnings are per-session and re-arm every 10 min, so every concurrently
running session/agent hears them — not just the first one. - Silent when the window has already reset (stale-high data can't false-fire).
- Pace mode (opt-in): create
<state-dir>/pace.jsonwith{"on": true, "agents": 5}to get a periodic usage line injected even below
the thresholds — useful when a dispatcher is pacing a fleet of subagents.
Delete the file when the run ends.
Thresholds and intervals are in the guard section of config.json.
usage_verdict.py
$ python3 usage_verdict.py # `python` on Windows
GO — 5h at 42%, 133 min left, behind pace (0.75 = 42% used / 56% elapsed), projected ~75% at reset. [7d: 7d 71% (resets 10-09 13:00) — not near cap, ignore] headroom available, can dispatch more. (...)
Exit codes: 0 = GO, 1 = PACE, 2 = STOP, 3 = no data. --json for machine use.
The line always starts with the verdict, then the core reason, then the[7d: …] note, then optional detail — so a caller that truncates the line
(say to 200 characters) still keeps the 7d note.
Why a script instead of just reading the numbers? Four mistakes agents (and
humans) make constantly:
- Reset arithmetic —
limits.jsononly refreshes when a statusline
renders. After a reset it still shows the old 90-something %. Ifnow > resets_at, usage is ~0%; no need to spend tokens "verifying". - 7d false alarms — a high 7d % is meaningless when the 7d window resets
before the current 5h window ends. The verdict ignores it for you. - Pace, not just burn — pace = used % ÷ elapsed % of the 5h window
(below 1 = behind pace, there is headroom). The projection takes the
larger of the whole-window average rate and the last 30 minutes' trend
(extrapolated only as far as it was sampled). A projected overrun on its
own means PACE only when pace ≥ 0.9 — a dispatch burst while you are
behind pace is reported, not acted on. In the first 20 minutes of a window
the projection never triggers PACE by itself (1% after 1 minute would
"project" 300%); only the soft threshold does. The hard STOP threshold
rules either way. - Reading tomorrow's reset as today's — reset times print
HH:MMwhen
they fall on today's date andMM-DD HH:MMotherwise.budget-guard.cjs
uses the same rule in its warnings.
USAGE_VERDICT_NOW=<epoch seconds> pins the clock (for bothusage_verdict.py and budget-guard.cjs); test_usage_verdict.py uses it
(stdlib only: python3 test_usage_verdict.py). The statusline layout has its
own snapshot tests (node test_statusline.cjs, no dependencies), which pin the
clock the same way.
One shared copy (optional). budget-guard.cjs tells agents to run theusage_verdict.py next to it. If you also want the verdict at a shared path
(other scripts, a dispatcher, a dotfiles repo), install the real file as~/.claude/scripts/usage_verdict.py and copy extras/usage_verdict_shim.py
next to budget-guard.cjs (in ~/.claude/hooks/<folder>/) asusage_verdict.py. The shim runs the real file with the same arguments,
output and exit code, so there is only one copy to edit.
--ratio estimates your plan's 7d/5h cap ratio empirically from collected
history — useful for planning multi-day batch jobs (the two windows are
officially independent; no published conversion exists).
Auto-resume after a hard cap (extras)
When the hard guard fires and the terminal must close, Claude writes ahandoff.md and schedules claude -p to continue the work a few minutes
after the window resets. With no resume_hint set, the guard names the
script for your OS automatically (when extras/ sits next tobudget-guard.cjs, i.e. you run it from the clone):
- Windows —
extras/windows/registers a one-shot Scheduled Task
(survives terminal exit and logout). Adapt the working-directory line
before use. - macOS / Linux —
extras/unix/schedule-resume.sharms anohuptimer
(survives the terminal closing; for logout/reboot resilience register the
same command withat, cron, or launchd instead).
Files written
Everything lives in the state dir (default ~/.claude/claude-pacer/):limits.json (latest window snapshot), limits-history.jsonl (burn-rate
samples, ~2 min interval, auto-trimmed at 256 KB), topics.json (topic cache),guard-state.json, and your config.json / pace.json. Nothing leaves your
machine; there are no network calls anywhere.
Limitations
- Usage numbers exist only on Pro/Max subscriptions; with API-key billing there
are no 5h / 7d windows to read. - The guard is only as fast as the statusline's samples (~every 2 min). A fleet
burning several %/min can reach the cap between two samples before any
warning lands (see budget-guard above). - The guard injects instructions; it cannot force Claude to stop. Subagents do
not auto-continue after a cap. - The 5h and 7d windows are independent; no conversion between them is
published, so none is derived.
Related tools
codex-pacer — the same idea for Codex CLI.
🌱 Start here if you're new to AI agents
This tool is one piece of my personal AI workflow. If you want to learn how to
use AI agents like Claude Code from zero (no programming background needed), I
wrote a beginner series (in Traditional Chinese):
The story behind this particular tool →
為什麼我需要一個會踩煞車的 statusline
Full map of my tools and posts → drpwchen.com/map
License
MIT
Support 支持
If this tool helped you, you can buy me a drink 🧋
覺得這個工具有幫助嗎?歡迎請我喝飲料。
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi