23:58 · somewhere in your terminal
While you sleep,the workcontinues.unsnooze auto-resumes Claude Code and Codex when the usage limit resets
When Claude Code, Codex, or any of your AI coding agents hits the 5-hour or weekly usage limit, the session just… stops. unsnooze tracks every limit-stopped session across all your projects and resumes it when the limit resets, with or without a terminal multiplexer. Even if your laptop slept through it.
the problem
Every other Claude Code auto-resume tool solves a slice.
Overnight and long-running agent work dies at the 5-hour or weekly cap — one pane retried, one CLI covered, or your session abandoned for a different provider mid-thought. unsnooze guards all of it and always brings back the same session, same context, same conversation.
| Capability | unsnooze | claude-auto-retry | autoclaude | hydra |
|---|---|---|---|---|
| Multi-CLI (Claude · Codex · Grok · Qwen · Kimi · OpenCode · Antigravity · Cursor) | ✓ | — | — | partial |
| GUI sessions (VS Code extension, desktop apps) | ✓ | — | — | — |
| Waits for reset & resumes the same session | ✓ | ✓ | ✓ | — |
| All sessions at once (shared ledger + one daemon) | ✓ | — | ✓ | ✓ |
| Revives sessions whose pane or process is gone | ✓ | — | — | — |
| Survives laptop sleep & weekly-scale waits | ✓ | partial | partial | — |
| Settings + first-run wizard | ✓ | — | — | — |
one night · how it works
Anatomy of a night shift, from usage limit to resumed session
unsnooze is a scheduler that presses your keys — nothing more. It records the stop, waits out the reset, and resumes the same session. Here is one night, minute by minute.
The wall
Mid-refactor, the banner lands: “You've hit your usage limit · resets 3am.” The session stops. Without unsnooze, this is where the night ends.
The ledger
Claude's
StopFailurehook — or a pane scrape, or the session files GUI surfaces write — records the stop in~/.unsnooze/state.json: agent, session id, working directory, pane, reset time. The reset is parsed from the banner text, DST-safe. Unparseable banners are never guessed at — unsnooze re-probes until a real time appears.The wait
A singleton daemon checks wall-clock against the target epoch every 30 seconds — no long timers to break. A laptop that slept through the reset fires on the next tick. A weekly limit is just a bigger epoch.
The wake
Pane still alive? The resume message is typed in — only after proving the pane is yours and your CLI is foreground and idle. Pane gone? A fresh multiplexer pane runs
claude --resume <id>— or, with no multiplexer, a detached headless process. Either way it's the same session, same context, same conversation.The verification
After every wake, the pane is re-captured. If the limit banner came back — reset time misparsed, limit not actually lifted — unsnooze reschedules from the fresh banner, capped at five attempts. It never hammers.
The morning
You wake up; the work didn't stop.
unsnooze statusshows every session that hit a wall, when it woke, and what it's doing now.
who it watches
Eight AI coding CLIs, one ledger
Terminal sessions are watched through the shell wrapper and your multiplexer; GUI sessions through the files they already write. One shared ledger, one daemon, every project at once — and across every machine in your ssh fleet.
Claude Code stable
Dual-channel: the StopFailure hook (authoritative, carries the session id) plus pane scraping for banners and the interactive limit menu — always answered with “Stop and wait for limit to reset,” never a blind Enter. Dead sessions revive via claude --resume. A per-model limit (“You've reached your … limit”) has no reset to wait for, so it is tracked, probed and never typed at.
Codex CLI stable
Detects the exact banner strings from the Codex source and parses every reset format — “try again at 3:51 PM,” absolute dates, “in 4 days 20 hours.” Stops behind an OpenAI-compatible proxy are read from the limit error Codex writes, and a workspace wall — credits gone or a spend cap hit — is held with the remedy instead of being woken into. Dead sessions revive via codex resume.
GUI surfaces daemon
Sessions in Claude Code's VS Code extension, the ChatGPT desktop app, and Claude desktop have no pane to scrape — so the daemon tails the session files those surfaces already write. Codex rollouts even carry the exact epoch reset time. At reset, the session revives in a multiplexer pane; it's the same session file, so the conversation stays visible in the GUI's own history.
unsnooze setup. Hit a banner one missed? unsnooze report captures are how these get good.grokClaude-compatible hooks (including StopFailure) work today; banner patterns stay generic until xAI documents the strings.qwenHook plus verbatim quota scrapes. Qwen never prints a reset time — 5-hour fallback, self-corrected on verify.kimiAnchors on the red 429 line kimi stops with. Resume ids verified on disk first — kimi silently starts a new session for unknown ids.opencodeRetries limits itself, forever — so unsnooze never touches a live pane. Its job: reviving sessions whose process died mid-wait.agyAntigravity, the Gemini-CLI successor. Parses “Refreshes in 6 days…” as the weekly cap; treats 503 capacity errors as transient, not a limit.cursor-agentThe one limit not worth waiting out: Cursor resets on your monthly billing cycle. So unsnooze never schedules a weeks-long sleep — it probes, and resumes the moment the wall comes down. Wraps cursor-agent, never the cursor IDE launcher.wherever you work
Supported terminals
Four terminal multiplexers, on macOS, Linux and Windows — and if you have none of them, unsnooze still catches and resumes your limit stops.
tmux≥ 3.2
The reference backend, and the only one that can push OSC notifications straight to the terminal you are actually looking at. Everything else is measured against it.
Zellij
Full parity for the whole session lifecycle — detect, resume in place, revive a dead pane, reap idle sessions.
herdr≥ 0.8.0
Built for running coding agents. A workspace there is the project, so a revival opens a tab in the one already on that directory. And since herdr restores saved agent panes by itself, unsnooze never restarts a stopped session — that could resume the same conversation twice — and revives into a fresh name instead.
cmux
Detect, resume and revive all work. It has no joinable named session, so a revival opens a fresh workspace and there is no attach: hint to print.
StopFailure hook and the session transcript instead of a pane, and revives into a detached process. That is what makes native Windows, bare servers and CI work. You give up the limit-menu answering and the live pane — so headless is only ever chosen when nothing else is there, never ahead of a real multiplexer. A headless revival that dies is retried with backoff, and its own error shows as last error in unsnooze status.autoUses the multiplexer you are already inside; failing that, whichever of tmux, Zellij or herdr is installed (tmux breaks ties — cmux only when you are inside it or pin it); failing that, headless.pin itunsnooze config set multiplexer tmux|zellij|herdr|cmux|headless — and the full capability table is in the docs.trust · before you install
It presses your keys. Here's the contract.
A tool that types into your terminal at 3am has to earn that. unsnooze is a scheduler, not an auto-approver — it never changes how your agent handles permissions. The security model spells out the boundaries.
- Types only after proving the pane is yours
- Every keystroke requires identity (an ownership stamp or a process-id + birth-time lease — pane ids get recycled, so a mismatch vetoes) and liveness (your agent is still running there, foreground, not mid-stream). Ownership unprovable → it opens a fresh session instead of typing.
- Never a blind Enter
- Claude's limit menu is located and read before any key is sent; unsnooze computes the exact moves to “Stop and wait for limit to reset.” Unreadable menu → it presses nothing. It will never select “Upgrade your plan.”
- No permission bypass flags
- No
--dangerously-skip-permissions, no auto-approve, no touching MCP config — unsnooze adds none of its own; flags you put inresumeExtraArgsare yours. Whatever your agent does after resuming is governed by its own permission model, the same as if you'd typed the message yourself. (Headless Codex revivals pass--skip-git-repo-check, becausecodex execrefuses non-git folders the session already ran in.) - See before you trust
unsnooze previewis a true dry-run: it prints exactly what would be typed, where, and why — or what's holding it back — and sends nothing. It shares its decision code with the real dispatcher, so it cannot drift from what dispatch actually does.- Nearly zero network, zero telemetry
- One daily version check to the npm registry (nothing identifying; off with one setting), and push notifications only if you configure an ntfy topic. All state stays local and owner-only (0700/0600) under
~/.unsnooze. - Reversible install
- The settings hook and rc-file wrappers are backed up first;
unsnooze uninstallremoves every change. Releases are published to npm with provenance.
Honest limits: unsnooze does inject keystrokes into your live terminal on your behalf, and it does not sandbox your agent or defend against prompt injection — that's your agent's job. The full threat model and residual risks live in SECURITY.md.
01:30 · if you're up anyway
A usage-limit dashboard for the small hours
unsnooze dashboard is a full-screen terminal UI — status, usage forecast, sessions, install doctor, live logs, queued prompts, and your whole ssh fleet, with mouse support: click tabs and rows, wheel-scroll the logs. Pipes, CI, and --json stay plain. Try the tabs.
❯ unsnooze z z z daemon: running claude f3a1… ~/work/payments snoozed wakes 3:00 am (in 2h 41m) ctx ~152k tok claude 9d07… ~/oss/unsnooze resumed woke 8:01 pm · verified codex 8c42… ~/work/ingest snoozed wakes 3:00 am (in 2h 41m) qwen 1be3… ~/exp/agents paused held by workspaceGuard · resume-now to review 2 snoozed · 1 resumed · 1 paused — attach: tmux attach -t unsnooze-resumed
m toggles mouse mode · ? help overlay · q quits — works down to an 80×24 terminal
20:41 · before the wall
Know the 5-hour limit wall before you hit it
Recovery is only half the job. unsnooze usage forecasts your burn rate and time-to-limit so you can /compact, pause, or switch models before a stop — see it live in the usage tab of the dashboard above, or --json it into your own tooling. The usage forecast documentation covers how each figure is derived.
Every figure carries its provenance
(exact) from local data or the opt-in statusline shim, (calibrated from N stops) learned from your own recorded limit stops, or (estimated) while calibrating. Never a bare percentage.
ETA as a band, not a lie
Time-to-wall is cross-checked against known reset times and shown as a range — never a false-precision minute, never a blind now-plus-five-hours.
Account-wide, not per-pane
Burn sums all active sessions and subagents — the limit is per-account. Idle gaps over 5 minutes are excluded so a quiet hour doesn't hide a fast burn.
03:00 · the reset moment
Don't just resume — queue what's next
Resuming snoozed work is half the night. unsnooze prompt add pre-writes the next task per project: the moment the limit resets, a brand-new agent session opens in that directory and your prompt is typed as its first message. Manage the queue from the dashboard's prompts tab, or entirely from the CLI — every verb is in the queued prompts reference.
$ unsnooze prompt add --project ~/work/payments "run the full test suite and fix any failures" prompts: queued p-3f9a1c2e for claude in ~/work/payments — delivering after the reset 03:00:07 queue new claude window in ~/work/payments · typing queued prompt 03:00:29 verify pane healthy · no banner · delivered ▶ p-3f9a1c2e consumed
One-shot, and verified
Each prompt is delivered exactly once — a fresh window running the agent in that project, prompt typed only after the input box is provably idle. If the limit turns out to still be active, the entry re-queues using the banner's own reset time and the window is closed; after repeated failures it gives up loudly.
Anchored, never guessed
Due-ness comes from real signals — the statusline's exact resets_at or your recorded limit stops. No signal means no limit to wait out: it delivers on the next daemon tick and prompt add says so up front. --at 9pm / --at +2h30m schedule an exact time instead.
Fleet-wide
--host gpu-box queues on any registered machine over your own ssh; that host's daemon delivers under its own gates and reports back in unsnooze fleet. Hosts opt out with remoteQueue off.
04:15 · the details that hold
Guards for everything that can go wrong when a session resumes
Every guard is a config key — set once in unsnooze setup, change any time with unsnooze config set, override per environment with UNSNOOZE_* vars. Every key is listed in the settings and guards documentation.
Pre-wall warnings
usageWarndefault: notifyThe daemon warns at 80% and 95% of the window's quota, and at 30 and 10 minutes to the wall at your current pace — deduped once per window. It may suggest /compact so the eventual wake is cheap; it never auto-types it.
Cold-cache wake guard
contextGuarddefault: informWaking after hours means the provider's prompt cache is long gone — the first message re-reads the entire context at full price. unsnooze estimates the size (ctx ~152k tok) and notifies you, or holds sessions above a threshold for a manual decision.
Stale-workspace guard
workspaceGuarddefault: informThe repo's HEAD and dirty state are fingerprinted at stop time. If anything changed before the wake, the resumed agent is told to re-read before acting — or the session is held and resume-now shows the diff first.
Notifications, your way
notifyChanneldefault: autoOS toasts (macOS, Linux, native Windows — including from WSL), terminal OSC banners in iTerm2 / kitty / WezTerm / Ghostty, a plain BEL, or ntfy push to your phone — for limit hit, resumed, and gave-up.
Menu answering, on your terms
menuAutoAnswerdefault: trueClaude's limit menu is driven only when it can be read exactly; turn it off and unsnooze is watch-only. autoResume off goes further: track everything, type nothing.
Tidy panes, eventually
reapResumeddefault: falseunsnooze reap closes finished panes and empty sessions — dry-run by default, auto-reap strictly opt-in after seven idle days.
the toolbox
You mostly just run claude — unsnooze watches the terminal
Day to day nothing changes — the shell wrapper watches claude,codex and friends automatically. The rest of the CLI is for looking around — see the full command reference for every flag and example.
unsnooze statustracked sessions, reset countdowns, context sizes — or a live dashboard on a TTYunsnooze dashboardfull-screen TUI: status, usage, sessions, doctor, logs, fleet, prompts — with mouse supportunsnooze usageaccount burn & time-to-limit forecast (--json for scripts)unsnooze previewdry-run: what would happen right now, and why — nothing is typedunsnooze resume-nowdon't wait for the reset time (--all for everything)unsnooze cancelstop tracking a sessionunsnooze message <id>per-session wake message (--clear to reset)unsnooze prompt add "…"queue a one-shot prompt: at the limit reset a new session opens in the project and types it (--at, --now, --host)unsnooze sessionslist unsnooze-owned multiplexer sessions and panesunsnooze hosts add <name>register another machine over ssh — key or password auth (hosts test pre-flights it)unsnooze fleetevery registered host's sessions in one view; resume/cancel remotely from the dashboard's fleet tabunsnooze design setupregister the claude-design MCP server so Claude Design runs watched inside Claude Codeunsnooze reapclose finished panes and empty sessions — dry-run by defaultunsnooze doctorinstall health check, with --fixunsnooze logs -fwhat unsnooze has been doing, liveunsnooze reportcapture a pane to report an undetected banner — how experimental adapters get goodunsnooze updateupdate unsnooze itself (a daily registry check tells you when)unsnooze uninstallremove every change it made (--purge for state too)asked at 4am
Questions people actually ask
Does this get around the rate limit?
No. unsnooze waits for the reset exactly like you would, resumes once, and verifies the limit actually lifted. It replaces the 4am alarm, not the limit.
What if my laptop was asleep or the terminal was closed?
Reset times are stored as absolute timestamps and checked every 30 seconds, so a laptop that slept through the reset resumes on the next tick — and dead panes are reopened by session id in a fresh multiplexer pane (or a detached process when running headless).
Why did resuming a big session eat so much quota?
Prompt-cache expiry, not unsnooze. After hours stopped at a limit the provider's cache is long gone, so the first wake message — unsnooze's or a hand-typed “continue,” identical cost — re-reads the entire context at full price. The contextGuard setting estimates the size before waking and can notify you or hold the session for a manual decision. /compact before the wall is what actually helps.
What if the repo changed while a session slept?
unsnooze fingerprints the workspace (HEAD plus uncommitted state) at stop time and re-checks at wake. By default the session resumes with a heads-up in the wake message;workspaceGuard=pause holds it until you review the diff.
Does it work on Windows?
Yes, natively. PowerShell wrappers go into your $PROFILE, the StopFailure hook is written in cmd syntax, and the daemon is started on demand by your agents — nothing is registered to run at sign-in. With no multiplexer installed unsnooze runs headless — it detects stops from the hook and the session transcript instead of a pane, so limits are still caught and resumed. WSL remains the richer option, since that is where tmux lives and where you get menu answering and a live pane to attach to.
Claude Code can auto-continue now — what does unsnooze add?
Claude's own auto-continue covers the 5-hour limit, in-process, for Claude. It cannot fire when the app is closed, the machine slept, or you are on a headless box over ssh — and it does not cover the weekly limit or any other CLI. unsnooze watches from outside the session, so it survives all of that, and it resumes Codex, Grok, Qwen, Kimi, OpenCode, Antigravity and Cursor too. When Claude does resume itself, unsnooze notices and stands aside rather than sending a second wake — unsnooze status says so explicitly.
Does it work with Claude Design?
Yes, for design work run through the claude-design MCP server inside Claude Code — run unsnooze design setup to wire it up. Design draws from the same 5-hour and weekly pool as everything else, so a long design run stops like any other session and is resumed the same way. unsnooze does notautomate the web canvas at claude.ai/design: Anthropic’s Consumer Terms bar automated access to claude.ai, and accounts have been terminated for it.
What does it need?
Node ≥ 20.12, on macOS, Linux or Windows. A multiplexer (tmux ≥ 3.2, Zellij, herdr or cmux) gives you pane-level watching; without one unsnooze runs headless and still resumes. Wrappers install into ~/.zshrc / ~/.bashrc, ~/.config/fish/config.fish for fish, or your PowerShell $PROFILE; everything is reversible with unsnooze uninstall.