https://github.com/jayfarei/lazyusage
Capacity monitoring for Claude and Codex subscriptions: a tmux-popup dashboard for humans, a JSON capacity API for agents
https://github.com/jayfarei/lazyusage
agents bun claude cli codex rate-limits tmux tui
Last synced: 7 days ago
JSON representation
Capacity monitoring for Claude and Codex subscriptions: a tmux-popup dashboard for humans, a JSON capacity API for agents
- Host: GitHub
- URL: https://github.com/jayfarei/lazyusage
- Owner: JayFarei
- License: mit
- Created: 2026-02-05T17:27:15.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-06-12T10:21:38.000Z (9 days ago)
- Last Synced: 2026-06-12T11:20:49.855Z (9 days ago)
- Topics: agents, bun, claude, cli, codex, rate-limits, tmux, tui
- Language: TypeScript
- Homepage:
- Size: 2.17 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Roadmap: ROADMAP.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# lazyusage
```text
█░░ ▄▀█ ▀█ █▄█ █░█ █▀ ▄▀█ █▀▀ █▀▀
█▄▄ █▀█ █▄ ░█░ █▄█ ▄█ █▀█ █▄█ ██▄
```
[](https://github.com/jayfarei/lazyusage/actions/workflows/ci.yml)
[](LICENSE)
[](https://bun.sh)
**Know how much AI subscription capacity you have left, and put all of it to work.**

`lazyusage` answers the questions you actually ask about your Claude and Codex subscriptions:
- **"Am I overspending against my weekly capacity?"** Pace bars compare allowance burned vs time elapsed, and flag `OVER BUDGET` the moment you burn faster than the window refills.
- **"Which of my projects is eating the tokens?"** A per-project ledger (Daily / Weekly / Monthly) built from your local session history.
- **"Can I give agents 50% of what's left, and have them go to sleep when it's spent?"** A JSON capacity API plus copy-paste prompt templates let goal/loop agents budget themselves to a slice of remaining capacity and stop cleanly when it runs out.
- **"How much will I have spare by the reset?"** Recorded usage history feeds an end-of-window prediction you can plan unsupervised work against.
It serves two audiences with the same data:
1. **Humans, via a tmux-popup dashboard.** Bind the TUI to a key and get a one-keystroke overlay over whatever you are doing, without leaving your editor or agent session.
2. **Agents, via a capacity API.** Agents on a goal, workflow, or loop check how much capacity is left before expensive work, and layer capacity-management strategies on top of the JSON output.
## Quick start
```bash
# Install
bun add -g lazyusage
# Interactive dashboard
lazyusage
# One-shot JSON for agents/scripts
lazyusage --json
# Most compact burn-rate check
lazyusage --capacity
# Lightweight point-in-time check
lazyusage usage-check --json
```
Requirements: Bun `>= 1.3`, plus the Claude CLI (`claude`) and/or Codex CLI (`codex`) in `PATH`. `tmux` is optional (PTY fallback and some end-to-end tests).
## How it works
Each service is fetched through a fallback chain: the first source that answers wins, and every snapshot is stored locally so history and predictions survive restarts.
```text
┌────────────────┐ ┌────────────────┐
│ Claude API │ │ Codex API │ data sources
│ (OAuth creds) │ │ (auth.json) │
└───────┬────────┘ └───────┬────────┘
│ │
▼ ▼
┌─────────────────────────────────────────┐
│ fallback chain │ per service, in order:
│ │
│ API ─► token refresh ─► PTY (tmux) │ fresh API data, refreshed
│ ─► cache ─► fallback zeros │ creds, driving the real CLI,
│ │ last good data, safe zeros
└────────────────────┬────────────────────┘
│ snapshots
▼
┌─────────────────┐
│ SQLite store │◄────── collector daemon (optional,
└────────┬────────┘ always-on, samples on interval)
│
┌────────────────┼────────────────┬─────────────────┐
▼ ▼ ▼ ▼
┌────────┐ ┌─────────────┐ ┌───────────┐ ┌──────────────┐
│ TUI │ │ --text/json │ │ HTTP/SSE │ │ --predict │
│ (popup)│ │ (agents) │ │ server │ │ + planning │
└────────┘ └─────────────┘ └───────────┘ └──────────────┘
```
Every snapshot carries its provenance (`source`, `stale`, `error`), so consumers can tell fresh data from a cached or fallback answer.
### The capacity model
The key derived metric is `capacity_remaining`: how far ahead of (or behind) pace you are within the current window.
```text
time elapsed ▓▓▓▓▓▓▓▓▓░░░░░░░░░░░ 45%
allowance used ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░ 50%
└────────── capacity_remaining = 45 - 50 = -5%
(negative: burning faster than time passes)
```
A positive value means you can speed up; a negative value means at the current pace you will hit the limit before the window resets. The TUI surfaces this as `⚡ OVER BUDGET` warnings; agents read it from JSON.
## The TUI
- 2x2 grid: one row per service, usage bars on the left, per-project token ledger on the right
- `Tab` cycles stats tabs (Daily, Weekly, Monthly, and Graph when the daemon is running)
- `j/k` navigate metrics, `g` fullscreen, `p` pause refresh, `?` help, `q` quit
- `lazyusage claude` or `lazyusage codex` shows a single service
### tmux popup
The TUI is designed to live in a tmux popup, a one-keystroke overlay on top of whatever you are doing. To set it up:
1. Make sure `lazyusage` is on your `PATH` (`bun add -g lazyusage`), or use the full path to the binary in the binding below.
2. Add a binding to `~/.tmux.conf`:
```bash
# Open lazyusage in a popup with prefix + u
bind-key u display-popup -E -w 90% -h 80% "lazyusage"
```
3. Reload your tmux configuration:
```bash
tmux source-file ~/.tmux.conf
```
4. Press `prefix + u` (default prefix is `Ctrl-b`) to open the dashboard, and `q` to dismiss it. `-E` closes the popup automatically when the TUI exits.
Useful variants:
```bash
# Claude only, smaller popup
bind-key U display-popup -E -w 70% -h 50% "lazyusage claude"
# Bind without the prefix (root table), e.g. Alt+u
bind-key -n M-u display-popup -E -w 90% -h 80% "lazyusage"
# Running from a source checkout instead of a global install
bind-key u display-popup -E -w 90% -h 80% "cd /path/to/lazyusage && bun run lazyusage"
```
This pairs well with long-running agent sessions: keep agents working in your panes, pop the dashboard over them when you want to see how much subscription headroom they have left.
## For agents
### Output modes
```bash
lazyusage --capacity # most compact: capacity_remaining only
lazyusage --text # one line per service, all fields
lazyusage --json # structured snapshot
lazyusage --json --live # continuous NDJSON stream
lazyusage --json-only # machine-safe: errors as JSON on stdout
lazyusage claude --json # single service
lazyusage usage-check --json # fast point-in-time check
```
What the text modes look like:
```text
$ lazyusage --capacity
Claude: Session: -5% | Weekly: -4% | Sonnet: +6% [Subscription: max]
Codex: Session: +19% | Weekly: +4% [Subscription: pro]
$ lazyusage --text
Claude: Session: 50% allowance used, 45% time elapsed, -5% capacity remaining (resets 1:20pm) | ...
Codex: Session: 5% allowance used, 24% time elapsed, 19% capacity remaining (resets 2:22pm) | ...
```
### JSON contract
Snapshot responses include resource-awareness metadata so agents can distinguish fresh data from fallback or cached data.
```json
{
"timestamp": "2026-03-22T12:00:00.000Z",
"available_services": ["claude", "codex"],
"services": [
{
"name": "claude",
"available": true,
"source": "api",
"stale": false,
"error": null,
"subscription_type": "Max",
"metrics": [
{
"name": "session",
"used_pct": 26,
"remaining_pct": 74,
"time_elapsed_pct": 61,
"capacity_remaining": 35,
"resets": "9:00pm"
}
]
}
]
}
```
Important fields:
- `source`: where the snapshot came from (`api`, `pty`, `cache`, `fallback`)
- `stale`: whether the last good result is being reused
- `error`: fetch failure detail when the service could not return a fresh clean result
- `remaining_pct`: hard limit headroom
- `capacity_remaining`: burn-rate headroom relative to elapsed time
Treat `remaining_pct` as the hard gate. Treat `source`, `stale`, and `error` as confidence signals.
### Skill and prompt templates
The canonical agent skill lives at [`skills/lazyusage/SKILL.md`](skills/lazyusage/SKILL.md). It covers pre-flight capacity checks, adaptive throttling, stale/fallback-aware decision making, sleep-until-reset logic, service failover, and shared local server usage for multiple agents.
Copy-paste prompt templates for goal/loop agents:
- [`skills/lazyusage/templates/claude-goal-capacity.prompt.md`](skills/lazyusage/templates/claude-goal-capacity.prompt.md): Claude agent on a goal that may only spend a fixed share of remaining capacity
- [`skills/lazyusage/templates/codex-goal-capacity.prompt.md`](skills/lazyusage/templates/codex-goal-capacity.prompt.md): the same capacity-budget protocol for Codex agents (`5h` / `weekly` metric keys)
- [`skills/lazyusage/templates/claude-session-guard.prompt.md`](skills/lazyusage/templates/claude-session-guard.prompt.md): Claude agent that pauses itself near the 5-hour session limit
Runnable examples:
- [`examples/agent_integration.ts`](examples/agent_integration.ts)
- [`examples/agent_integration.sh`](examples/agent_integration.sh)
- [`examples/dashboard/README.md`](examples/dashboard/README.md)
### Capacity budgets for unsupervised work
A simple, robust pattern for agents on a goal/loop: give background work only a fixed share of the remaining capacity and stop when it is spent.
```bash
# Gate a work loop on a capacity budget:
# unsupervised work may use at most 40% of what currently remains.
START=$(lazyusage usage-check claude --json-only | jq '[.services[] | select(.name=="claude").metrics[] | select(.name=="week_all").remaining_pct] | first')
BUDGET=$(echo "$START * 0.4" | bc)
while true; do
NOW=$(lazyusage usage-check claude --json-only | jq '[.services[] | select(.name=="claude").metrics[] | select(.name=="week_all").remaining_pct] | first')
SPENT=$(echo "$START - $NOW" | bc)
if [ "$(echo "$SPENT >= $BUDGET" | bc)" -eq 1 ]; then
echo "capacity budget exhausted, stopping unsupervised work"
break
fi
run_one_unit_of_work
done
```
The same logic works against the HTTP server (`GET /claude`) when several agents share one collector, and `--predict` can replace the static 40% with a dynamic budget derived from predicted end-of-window spare capacity.
## Collector daemon
For continuous history (and the TUI's Graph tab), run the always-on collector daemon. It samples usage on an interval and stores snapshots in the local SQLite database, so history accumulates even when the TUI is closed.
```text
lazyusage daemon start TUI startup
│ │
▼ ▼ daemon healthy?
┌──────────────┐ snapshots ┌────────────────┐
│ collector │────────────────►│ SQLite store │──► Graph tab, history,
│ (60s cycle) │ └────────────────┘ predictions
└──────────────┘ TUI reads stored snapshots instead of
starting its own collection chain
```
```bash
lazyusage daemon start # start in the background
lazyusage daemon status # health, last collection, data freshness
lazyusage daemon logs # recent log output
lazyusage daemon stop # stop the daemon
# Run at login as a background service
lazyusage daemon install # launchd agent on macOS, systemd user unit on Linux
lazyusage daemon uninstall
```
Configuration is optional and lives at `~/.config/lazyusage/daemon.toml`. When the daemon is healthy, the TUI hydrates from its stored snapshots instead of starting its own collection chain, and the stats panel gains a Graph tab (cycle with `Tab`: Daily, Weekly, Monthly, Graph).
## Capacity prediction and planning
`lazyusage` can project how much spare capacity you will have at the end of the current weekly window, based on your recorded usage history:
```bash
# Show predicted spare capacity at window end
lazyusage --predict
# Mark upcoming days with an expected work intensity (regime) to refine the prediction
lazyusage plan 2026-06-15 H # High, ~15%/day
lazyusage plan 2026-06-16 L # Low, ~3%/day
lazyusage plan list
lazyusage plan clear 2026-06-15
lazyusage plan clear --all
```
Regimes: `L` (Low, 3%/day), `M` (Medium, 9%/day), `H` (High, 15%/day), `B` (Burst, 25%/day).
This is the foundation for capacity-management strategies: if the prediction says you will end the week with 30% spare, you can decide to dedicate that slice to unsupervised agent work and keep the rest for interactive sessions. The design document lives at [`docs/design/01-capacity_prediction.md`](docs/design/01-capacity_prediction.md).
## Local server
The server is designed for local tooling. It binds to `127.0.0.1` by default and is intended for localhost browser or agent consumers.
```bash
lazyusage --serve
lazyusage --serve --port 3000
lazyusage --serve --host 0.0.0.0 --port 3000
```
Endpoints:
- `GET /` all configured services
- `GET /claude` Claude only
- `GET /codex` Codex only
- `GET /health` server metadata
- `GET /stream` SSE stream for all configured services
- `GET /stream/claude` SSE stream for Claude only
- `GET /stream/codex` SSE stream for Codex only
## Install
### Fastest path
```bash
bunx lazyusage --help
```
### Global install
```bash
bun add -g lazyusage
lazyusage --help
```
### From source
```bash
git clone https://github.com/jayfarei/lazyusage.git
cd lazyusage
bun install
bun run build
bun run lazyusage --help
```
## Styling
The TUI ships with an intentional default theme instead of pretending to be fully themeable. An alternate monochrome palette is available for minimal terminals:
```bash
LAZYUSAGE_THEME=monochrome lazyusage
```
## Repository layout
```text
packages/
core/ data collection, parsing, storage, formatting (publishable library)
cli/ TUI application + CLI commands (publishable CLI)
e2e/ end-to-end tests via tmux (private)
tests/ unit tests (core, cli, tui)
skills/ canonical agent skill + prompt templates
examples/ agent integration examples + browser dashboard
docs/ design documents (docs/design/) and research notes (docs/research/)
scripts/ build tooling
```
## Development
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide, and [ROADMAP.md](ROADMAP.md) for planned work.
```bash
bun install
bun run build
bun run test:core
bun run test:cli
bun run test:tui
bun run test:smoke
```
## License
[MIT](LICENSE)