Query your Claude Code rate limit status from the terminal. Returns NDJSON with utilization percentages and reset countdowns for each rate window.
- Claude Code installed and authenticated (
claude auth) - macOS (reads OAuth token from Keychain via
securityCLI) python3andcurlon PATH
chmod +x claude-usage.sh
./claude-usage.shOutput (one JSON object per line):
{"window": "5h", "utilization": 42.3, "remaining": 57.7, "resets_at": "2026-03-06T18:00:00Z", "resets_in": "2h 14m"}
{"window": "7d", "utilization": 15.1, "remaining": 84.9, "resets_at": "2026-03-10T00:00:00Z", "resets_in": "3d 6h"}| Window | Description |
|---|---|
5h |
5-hour rolling window |
7d |
7-day aggregate |
7d_opus |
7-day Opus-specific budget |
7d_sonnet |
7-day Sonnet-specific budget |
extra |
Overflow usage (only if enabled on your plan) |
import { execFile } from 'child_process';
import { promisify } from 'util';
import { NextResponse } from 'next/server';
const exec = promisify(execFile);
export async function GET() {
const { stdout } = await exec('./claude-usage.sh', [], { timeout: 30000 });
const windows = stdout.trim().split('\n').filter(Boolean).map(JSON.parse);
return NextResponse.json({ windows });
}const [usage, setUsage] = useState([]);
useEffect(() => {
const poll = async () => {
const res = await fetch('/api/claude-usage');
const { windows } = await res.json();
setUsage(windows);
};
poll();
const id = setInterval(poll, 15 * 60 * 1000); // every 15 min
return () => clearInterval(id);
}, []);./claude-usage.sh | python3 -c "
import sys, json
for line in sys.stdin:
w = json.loads(line)
if w['utilization'] >= 80:
print(f\"WARNING: {w['window']} at {w['utilization']}% — resets in {w['resets_in']}\")
"- Reads your Claude Code OAuth token from the macOS Keychain (
Claude Code-credentials) - Calls
https://api.anthropic.com/api/oauth/usagewith that token - Parses the response into per-window NDJSON records with utilization and reset info
- Retries on 429 (rate limited) up to 3 times with exponential backoff