claudekeeper is a tiny background daemon that watches your Claude Code sessions running in tmux and does two things your usage limit won't let you do on your own:
- ⏰ Schedule — pre‑type a prompt in a pane and have claudekeeper press Enter at a wall‑clock time (
2am,now + 30min, …). Kick off long runs while you sleep. - ♻️ Auto‑resume — when a session hits the 5‑hour usage cap, claudekeeper waits out the reset and continues it automatically, so work doesn't stall while you're away.
And because it does both, it does the thing neither half can alone:
🧠 Cap‑aware deferral — a prompt scheduled for
2amis never fired into a capped pane and lost. claudekeeper holds it until the cap resets, then submits it.
It's dependency‑free Python driven entirely through the tmux CLI, so it runs anywhere tmux does — Linux boxes, HPC login nodes, macOS.
One‑liner (recommended):
curl -fsSL https://raw.githubusercontent.com/PursuitOfDataScience/claudekeeper/main/install.sh | shDrops claudekeeper in ~/.local/share/claudekeeper and a launcher at ~/.local/bin/claudekeeper. The only runtime requirements are python3 ≥ 3.8 and tmux — both already on almost any machine you'd run Claude Code on. No pip, no virtualenv, nothing to compile.
Or via a Python package manager:
uv tool install claudekeeper # or: pipx install claudekeeperWhy not npm i -g?
npm installs Node programs; claudekeeper is Python. The Python equivalent of npm's global one‑liner is uv tool install / pipx install above, or the curl | sh script (which needs nothing but python3). If ~/.local/bin isn't on your PATH, the installer tells you how to add it.
claudekeeper setup # 1. one-time: start the background daemon
# 2. Open Claude Code in a tmux session, type your prompt, DON'T hit enter — then:
claudekeeper schedule mysession 2am # claudekeeper presses Enter at 2am
claudekeeper schedule mysession "now + 30min" --prompt "run the full test suite"
claudekeeper schedule a,b,c 2am # several sessions at once, fired together
# 3. (optional) auto-resume after the usage cap:
claudekeeper watch on
claudekeeper status # the daemon, your jobs, your sessions
claudekeeper logs -f # watch what it does, liveRun claudekeeper with no arguments any time for a refresher — it even lists the Claude sessions you have running right now.
claudekeeper has two moving parts:
- A background daemon (
claudekeeper setupinstalls it). It's the thing that actually presses keys. Scheduled jobs only fire while the daemon is running — the one gotcha, andclaudekeeper schedulewarns you if it isn't. - A job list + settings you manage from the CLI (
schedule,ls,rm,watch on/off). The daemon reads these live.
You pre‑type your prompt into the Claude Code input box and leave it there; claudekeeper submits it for you (a single Enter) at the right moment. With --prompt "...", claudekeeper types the text for you instead.
| Command | What it does |
|---|---|
claudekeeper setup |
Install + start the daemon, then print personalized next steps |
claudekeeper schedule <target,...> <time> [--prompt T] [--daily] [--force] |
Arm a keypress. <target> is a tmux session or session:win.pane — or a comma‑separated list (a,b,c) to arm several at once. |
claudekeeper ls |
List scheduled jobs (with ETA and any deferral) |
claudekeeper rm <id,...|all> |
Cancel jobs — one id, a comma‑separated list, or all |
claudekeeper watch on|off|status |
Toggle cap auto‑resume (off by default) |
claudekeeper status |
Daemon state, jobs, detected Claude panes |
claudekeeper logs [-f] [-n N] |
View / follow activity |
claudekeeper service install|uninstall|start|stop|status |
Manage the daemon directly |
claudekeeper daemon |
Run the loop in the foreground (what the service runs) |
claudekeeper doctor |
Check python, tmux, service manager, paths |
Time formats: 2am, 3pm, 9:30am, 14:30, 22:00, now + 5min, +10m, in 90s, noon, midnight, teatime.
Pass a comma‑separated list instead of a single target — handy when you've staged a prompt in a, b and c and want them all to go at 2am:
claudekeeper schedule a,b,c 2am
✓ will press Enter at Sun 2026-07-26 02:00:00 in 3 tmux sessions:
a [pj-38ef2713]
b [pj-0089457b]
c [pj-13904796]- Every session gets its own job id sharing one fire time, so they submit in the same second — but you can
rmone without touching the others, and each is deferred independently if its pane is capped. - All‑or‑nothing: if any session in the list doesn't exist, nothing is scheduled and the error names the bad one — a typo never leaves you half‑armed. (
--forceskips the check.) - Entries may be pane‑qualified and mixed freely:
claudekeeper schedule a:0.0,b 2am. Repeats are dropped. rmtakes a list too:claudekeeper rm pj-38ef2713,pj-0089457b.
Quoting:
a,b,cworks bare;"a, b, c"works quoted. Unquoteda, b, cdoes not — your shell splits it into separate arguments before claudekeeper sees it.
claudekeeper automates keystrokes into your terminals. It's built fail‑safe, but be aware:
- Auto‑resume is opt‑in.
watchis off until you runclaudekeeper watch on. Out of the box claudekeeper only fires prompts you explicitly schedule. - A cap is only a cap if the pane shows a real reset time. Auto‑resume ignores API errors, scrollback, and mere chatter about limits — it acts only on a parseable "resets H:MM am/pm". Each cap is resumed once, and only re‑arms after the pane is seen working again, so it can never loop and drain your budget.
- A blind Enter lands on whatever has focus. If a pane is sitting on a tool‑permission prompt whose default is destructive, an Enter would accept it. Schedule against panes you've left at the prompt with your text staged.
- It's node‑local. The daemon watches the tmux server on the machine it runs on; run it on the same host as your sessions.
Settings live in ~/.local/state/claudekeeper/config.json (override the dir with CLAUDEKEEPER_HOME). Toggle the common one with claudekeeper watch on/off; edit the file for the rest (msg, poll, buffer, stagger, match_command, only, exclude, …). The daemon re‑reads it every loop, so changes take effect without a restart, and out‑of‑range or wrong‑type values are clamped to safe defaults rather than crashing the daemon. Set CLAUDEKEEPER_TMUX to point at a specific tmux binary.
Keep
CLAUDEKEEPER_HOMEon a local filesystem. claudekeeper serializes its state withflock, which is only reliable on local disks — on some network filesystems (NFS) cross‑host locking is a no‑op. claudekeeper is node‑local anyway.
A single loop, every poll seconds:
- list tmux panes whose command is
claude, capture each one's text; - if
watchis on, detect real caps and schedule a one‑time resume at reset +buffer(staggered across sessions); - fire any due scheduled jobs — deferring any whose target pane is currently capped.
Scheduled jobs are persisted before the keypress (at‑most‑once — a crash never double‑fires a prompt into Claude) and are never lost to a momentary tmux/session outage. Handled caps persist across restarts, so a restart never re‑fires an already‑handled cap. Only one daemon runs per CLAUDEKEEPER_HOME (single‑instance lock).
git clone https://github.com/PursuitOfDataScience/claudekeeper && cd claudekeeper
PYTHONPATH=src python3 -m claudekeeper doctor
for f in tests/test_*.py; do PYTHONPATH=src python3 "$f"; done # unit tests (no deps)claudekeeper is an independent, community‑built tool. It is not affiliated with, endorsed by, or sponsored by Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic, PBC — used here only to describe what the tool works with. claudekeeper just automates the tmux CLI around Claude Code sessions you run yourself.
MIT © 2026 PursuitOfDataScience
