Push alerts when your Claude Code subscription usage crosses a limit.
Project description
ccwatch
ccwatch keeps an eye on your Claude Code usage so you don't have to.
Mid-session you start wondering how much of your weekly limit you've burned, and
the only way to know is to stop and check /usage (or through the claude app / website in settings, manually). ccwatch watches it for you and
pings your phone (or desktop, or a channel) as you cross each mark (10%, 25%, 50%,
75%, 90%, 100%), so you always have a feel for what's left, plus a heads-up like
"at this pace you'll hit your weekly limit around 4pm" before you actually do.
- No Python dependencies. Pure standard library, so
pipx install ccwatchpulls nothing else (it does need two system tools at runtime:tmuxand theclaudeCLI). - Many channels. Telegram, Discord, Slack, ntfy, generic webhook, desktop notifications. Enable any combination.
- Pacing. Linear burn-rate projection: know before you run out.
- Usage history. Every reading is timestamped and logged to a local SQLite database — a record of your Claude Code usage over time, with optional daily/weekly summaries and sparklines.
ccusage vs ccwatch.
ccusagereads token cost from your local logs.ccwatchwatches your actual subscription limit % (the session/weekly windows shown in/usage, which aren't in the logs) and pushes you alerts. They're complementary.
How it works
Claude Code doesn't expose usage over an API, but it renders it in the /usage
TUI panel. ccwatch runs a dedicated, throwaway Claude Code session in a tmux
pane, sends it /usage on a schedule, and scrapes the rendered percentages.
/usage only displays your usage rather than prompting the model, so the
probe's token footprint is negligible — Anthropic notes commands like /usage
make only tiny background status checks.
ccwatch ──tmux send-keys "/usage"──▶ [dedicated claude session]
◀──tmux capture-pane──────── (rendered /usage panel)
──parse %──▶ checkpoints / pacing / history ──▶ Telegram / Discord / …
Because the session and weekly limits are account-global, reading them from
one probe gives your true usage, so there's no need to watch your real working sessions.
See docs/how-it-works.md for the parser, tuning, and the
design trade-offs.
Install
pipx install ccwatch # or: pip install ccwatch
Requirements: Python 3.11+, the claude CLI on your PATH (logged in), and
tmux (ccwatch drives Claude Code through a tmux session). tmux is a one-line
install:
brew install tmux # macOS
sudo apt install tmux # Debian / Ubuntu
sudo dnf install tmux # Fedora
sudo pacman -S tmux # Arch
# Windows: run ccwatch under WSL, then sudo apt install tmux
(ccwatch doctor checks for tmux and prints the right command for your system if
it's missing.)
From source:
git clone https://github.com/richykim7/ccwatch && cd ccwatch
pip install -e .
Quick start
ccwatch setup # interactive: pick channels, link them, send a live test, write config
ccwatch start # starts watching in the background (offered at the end of setup too)
ccwatch start keeps watching after you close the terminal; ccwatch stop ends it.
That's the whole flow on a laptop — no systemd, no extra setup.
ccwatch setup walks you through each notifier (creating a Telegram bot, pasting a
Discord/Slack webhook, choosing an ntfy topic…), sends a test message so you know
it works, and writes ~/.ccwatch/config.toml for you.
Prefer to wire it up by hand? See docs/notifiers.md for
step-by-step instructions per channel. The smallest setup is just two env vars:
ccwatch runs with only TG_BOT_TOKEN + TG_CHAT_ID set, no config file needed.
Keeping it running
ccwatch start is all most people need: it watches in the background — a detached
tmux session — so you can close the terminal or disconnect SSH and it keeps going.
You never have to reattach (attaching only views the logs), and there's only ever
one session: a singleton guard makes a repeat ccwatch start a no-op, and if it
exits the session cleans itself up, so you won't pile up empty sessions. Stop it
with ccwatch stop, and tmux attach -t ccwatch to watch live. It survives
terminal close and SSH drops, but not a reboot (tmux sessions live in memory).
For more than that — restart-on-crash, survive reboots, run headless — pick one:
- systemd (Linux):
packaging/systemd/ccwatch.service. Survives reboot and restarts on crash. - launchd (macOS):
packaging/launchd/com.ccwatch.plist. Same, plus it starts at login. - cron / timer: schedule
ccwatch onceinstead of a long-running daemon. - Docker:
packaging/docker/Dockerfile(note the auth caveats inside).
Start it automatically
- macOS: the launchd agent (
com.ccwatch.plist) starts ccwatch at login viaRunAtLoad. - Linux: install the systemd user service (
ccwatch.service) and runloginctl enable-linger, so it starts at boot and keeps running after you log out. - With Claude Code (one command): run
ccwatch hook install. It adds aSessionStarthook to~/.claude/settings.jsonso ccwatch auto-starts whenever you open Claude Code (idempotent; it no-ops if already running). It's silent so it won't clutter your Claude session, andccwatch hook uninstallremoves it cleanly.
Running it 24/7
A laptop only watches while it's awake; closing the lid suspends everything, tmux
included. That's usually fine, since you only spend Claude usage while you're
working (i.e. while the machine is awake). For true around-the-clock monitoring,
run ccwatch on an always-on machine: a server, VPS, Raspberry Pi, or a cloud
VM. On an always-on VM, ccwatch start is ideal: it keeps running after you
disconnect SSH and watches continuously for as long as the VM is up. (Add the
systemd unit too if you want it to survive VM reboots.)
Commands
ccwatch setup: interactive wizard to link & test notifiers and write the config.ccwatch start: start watching in the background (survives closing the terminal).ccwatch stop: stop the background watcher.ccwatch settings [get KEY | set KEY VALUE]: list, read, or change config values (e.g.ccwatch settings set poll.interval 900).ccwatch hook install|uninstall|status: auto-start ccwatch when you open Claude Code.ccwatch once: one poll → notify cycle and exit (for cron / systemd timers).ccwatch peek: dump the raw/usagepane and parsed readings (use this to tune the parser).ccwatch selftest [--notifier X]: send a test message through your notifiers.ccwatch get-chat-id: list Telegram chat ids that have messaged your bot.ccwatch status [--live]: current usage as colored bars + pacing, at a glance.ccwatch history [--days N]: recent readings as sparklines.ccwatch digest [--daily|--weekly] [--send]: compose a summary now.ccwatch doctor: check tmux / claude / config / notifiers.
Global: --config PATH, --dry-run (route every notification to the log instead
of sending, great for trying it out).
Configuration
Settings live in ~/.ccwatch/config.toml (or any path you pass with
--config PATH). Change values with ccwatch settings set KEY VALUE or by
editing the file directly (comments are preserved either way), then restart
the daemon for it to take effect (ccwatch stop && ccwatch start, or restart
your service). Config is read once at startup, not live.
Everything is optional and has a default; config.example.toml
is the full annotated reference. A minimal config is just one notifier:
[[notifiers]]
type = "telegram"
token = "123456:ABC..." # your bot token (this file is local, chmod 600)
chats = ["987654321"] # your chat id
# add as many as you like:
# [[notifiers]]
# type = "discord"
# webhook = "https://discord.com/api/webhooks/..."
Any value can also be written as "env:NAME" to read it from an environment
variable instead, which is useful only if you keep your config inside a repo (see
Caveats).
Per-section checkpoint thresholds and message wording are configurable; pacing,
quiet hours, history, digests, and presentation ([display]) each have their own
[section] in the file. [display] controls the message tone (style = "terse" or "cheery" for upbeat, motivational messages), whether to
add a usage bar to alert bodies (bars), channel-native severity, and
terminal color.
For how to obtain each channel's token/webhook/topic, see
docs/notifiers.md, or just run ccwatch setup.
Caveats
- The
/usagepanel is scraped, so the parser is layout-dependent. If a Claude Code update changes the panel, runccwatch peekand adjust the regexes inparse.py. The percentage is approximate (rounded); the reset time is scraped from the same panel. - The probe runs with
--dangerously-skip-permissions(yolo) so it can boot unattended. It only ever receives/usage, but understand what that flag means before enabling it; setyolo = falseto require manual trust. - Don't commit secrets to git.
ccwatch setupkeeps your token in~/.ccwatch/config.toml(outside any repo, chmod 600), so by default there's nothing to do. Only if you keep your config inside a repo (e.g. dotfiles) should you switch toenv:indirection, so the committed file holds a pointer rather than the secret itself.
Development & testing
PYTHONPATH=src python3 -m unittest discover -s tests
The suite has no third-party Python dependencies and makes no external network calls:
notifier payloads are verified both against a fake transport and with real
urllib sends to a localhost server, a fake claude script exercises the full
tmux probe path (send-keys → capture-pane → parse), and the setup wizard's
config output is round-tripped back through the loader. See
docs/testing.md for how to verify live delivery to each real
channel.
Acknowledgements
ccwatch shells out to tmux (ISC license) and the Claude Code CLI. Neither is bundled or modified; ccwatch just invokes the copies you install. Thanks to both projects.
License
MIT. See LICENSE.
ccwatch is an independent project and is not affiliated with, endorsed by, or sponsored by Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic, PBC; they are used here only to describe what ccwatch works with.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ccwatch-1.0.0.tar.gz.
File metadata
- Download URL: ccwatch-1.0.0.tar.gz
- Upload date:
- Size: 57.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6133e52335ef7ae3a90037822425986b54d255178c6fe2ca8f81cdab3a3476c6
|
|
| MD5 |
78d202cd278ef9e56ded0476605a53d7
|
|
| BLAKE2b-256 |
2728b36dc4b3e95cc98bab14ef8436411d00a09dff0b4a90661674166a96a309
|
Provenance
The following attestation bundles were made for ccwatch-1.0.0.tar.gz:
Publisher:
release.yml on richykim7/ccwatch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ccwatch-1.0.0.tar.gz -
Subject digest:
6133e52335ef7ae3a90037822425986b54d255178c6fe2ca8f81cdab3a3476c6 - Sigstore transparency entry: 1769129060
- Sigstore integration time:
-
Permalink:
richykim7/ccwatch@c7371d90e5e44bbf34974683e4b7312c52336dc2 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/richykim7
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c7371d90e5e44bbf34974683e4b7312c52336dc2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ccwatch-1.0.0-py3-none-any.whl.
File metadata
- Download URL: ccwatch-1.0.0-py3-none-any.whl
- Upload date:
- Size: 48.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3810ec2b182ca51e566f30005ec8f5a4454c8daff57be488900a515b3f6f4018
|
|
| MD5 |
e1593d890c903e8186d62213c72211df
|
|
| BLAKE2b-256 |
06a85559bedcd89ac7f84a1e6210a2e7ae68e716c68b4faf69bafb5b6ebbc3d5
|
Provenance
The following attestation bundles were made for ccwatch-1.0.0-py3-none-any.whl:
Publisher:
release.yml on richykim7/ccwatch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ccwatch-1.0.0-py3-none-any.whl -
Subject digest:
3810ec2b182ca51e566f30005ec8f5a4454c8daff57be488900a515b3f6f4018 - Sigstore transparency entry: 1769129199
- Sigstore integration time:
-
Permalink:
richykim7/ccwatch@c7371d90e5e44bbf34974683e4b7312c52336dc2 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/richykim7
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c7371d90e5e44bbf34974683e4b7312c52336dc2 -
Trigger Event:
release
-
Statement type: