Files
dotfiles/home_root/.claude/bin/ratecheck
T
vh 7b16be02bf feat: fold in the portable Claude Code, zsh and git config; add a drift check
Added (all now linked from their live locations):
- home_root/.claude/settings.json. The statusLine command now uses $HOME
  instead of a Linux-only absolute path.
- home_root/.claude/bin/ratecheck and home_root/.claude/skills/australis-design.
- home_config/zsh/claude-config-dir.zsh and home_root/.local/bin/claude-config-dir-init,
  the per-repo Claude Code login helper and its seeding script.
- home_root/.gitconfig and home_config/git/ignore.
- home_root/.zshenv, with the cargo env line guarded so boxes without rust start clean.

link-dotfiles --check reports drift without changing anything: tracked files whose
live copy is no longer a link (stow dry-run conflicts) and links into this repo
that dangle. Exits 1 on drift. Verified against a clean baseline and two planted
drifts, a detached .nanorc and a dangling link.

.mailmap maps every earlier identity to Vuong Hoang: the repo-local 'Your Name'
placeholder config (now removed), host-generated emails, and aider suffixes.

CLAUDE.md: the symlink warning now lists every linked file and points at --check.
README: documents what is and isn't tracked under .claude, the edit rule, and --check.
2026-09-24 09:07:16 -07:00

65 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""Read the rate-limit window and say whether a consult may be dispatched.
The percentages exist only in the JSON the harness pipes to the statusline; no CLI
subcommand exposes them and nothing else on disk carries them. `~/.claude/statusline-command.sh`
tees them to ~/.claude/rate-limits.json on every render (added 2026-09-05, operator directive);
this reads that file.
Exit codes: 0 GO 1 PAUSE 2 UNKNOWN
⚠ UNKNOWN is NOT a pause. A stale or missing file means the instrument is broken, and a
broken instrument that halts every consult is a self-inflicted outage worse than the
overspend it guards. UNKNOWN proceeds and says so loudly, so the gap is visible rather
than silently protective.
"""
import json, os, sys, time
THRESHOLD = 93.0 # advisory default; a project may set its own and say so
STALE_SECONDS = 900 # the statusline renders constantly in an interactive session
PATH = os.path.join(os.environ.get("CLAUDE_CONFIG_DIR") or os.path.expanduser("~/.claude"), "rate-limits.json")
def main() -> int:
try:
with open(PATH, encoding="utf-8") as fh:
d = json.load(fh)
except FileNotFoundError:
print(f"UNKNOWN no {PATH} — statusline tee missing or never rendered")
return 2
except (OSError, ValueError) as exc:
print(f"UNKNOWN {PATH} unreadable: {exc}")
return 2
five, seven = d.get("five_hour_pct"), d.get("seven_day_pct")
age = time.time() - (d.get("written_at") or 0)
stamp = d.get("written_at_iso", "?")
if five is None and seven is None:
print(f"UNKNOWN both windows null (written {stamp}) — session reported no rate_limits")
return 2
if age > STALE_SECONDS:
print(f"UNKNOWN stale by {age/60:.0f} min (written {stamp}) — "
f"last seen 5h={five} 7d={seven}; the statusline is not rendering")
return 2
worst = max(v for v in (five, seven) if v is not None)
which = "5h" if five == worst else "7d"
line = (f"5h={five if five is not None else '?'}% "
f"7d={seven if seven is not None else '?'}% "
f"(age {age/60:.1f} min, threshold {THRESHOLD}%)")
if worst >= THRESHOLD:
reset = d.get(f"{'five_hour' if which == '5h' else 'seven_day'}_resets_at")
when = (time.strftime("%H:%MZ", time.gmtime(reset)) if reset else "unknown")
print(f"PAUSE {line} — {which} at {worst}% >= {THRESHOLD}%; resets {when}")
return 1
print(f"GO {line}")
return 0
if __name__ == "__main__":
sys.exit(main())