documentation

Install and setup

Everything below is drawn from the shipped CLI — command output, defaults, and behavior as implemented. For the threat model, read SECURITY.md.

Getting started

You 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 catches and resumes stops.

install
$ npm install -g unsnooze
$ unsnooze setup

The setup wizard asks which agents to guard and which toggles you want, then wires everything up:

  • Shell wrappers into ~/.zshrc / ~/.bashrc, ~/.config/fish/config.fish for fish, or PowerShell's $PROFILE — after this, typing claude or codex runs the CLI inside a watched multiplexer pane. You never call unsnooze directly to be protected.
  • The Claude StopFailure hook — the authoritative limit-stop signal, carrying the session id.
  • Optionally the daemon (a launchd agent on macOS, a systemd user unit on Linux; on Windows it is started on demand by your agents, with nothing registered to run at sign-in) for GUI-surface watching and pre-wall usage warnings.
  • ~/.unsnooze/config.json with your choices — see Settings.

Fish wrappers are added when fish is your login shell or its config file already exists. An absolute XDG_CONFIG_HOME changes the location to $XDG_CONFIG_HOME/fish/config.fish. After upgrading, run unsnooze setup and open a new shell to load the wrappers.

Every file it touches is backed up first (*.unsnooze-orig pristine, *.unsnooze-bak rolling), and unsnooze uninstall removes every change. Verify the install any time with unsnooze doctor — it reports problems, not a checklist, so a healthy install is a one-liner:

unsnooze doctor
$ unsnooze doctor
unsnooze doctor: all clear — install is healthy.
  · resumer/daemon: running (pid 4821)

Anything wrong comes back as a ✗ finding with a suggested fix, and doctor --fix repairs what it safely can. One nuance on requirements: tmux version isn't checked — any tmux runs, but reviving dead sessions uses env flags that need tmux ≥ 3.2.

Supported terminals

unsnooze drives four terminal multiplexers — and works without one. Pick one explicitly with unsnooze config set multiplexer tmux|zellij|herdr|cmux|headless. On auto it uses the multiplexer you are currently 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.

 tmux ≥ 3.2Zellijherdr ≥ 0.8cmuxheadless
Detect a limit stoppane + hook + transcriptpane + hook + transcriptpane + hook + transcriptpane + hook + transcripthook + transcript
Resume a live session in place✅✅✅✅—
Answer Claude's limit menu✅✅✅✅—
Revive a session whose pane died✅✅✅ 1✅ 2✅ 3
Wrap a bare claude into a managed session✅✅✅—n/a 4
unsnooze reap idle sessions✅✅✅——
attach: hint in unsnooze status✅✅✅——
OSC notifications to your terminal✅————
  1. As a new tab in whichever workspace herdr already has open on that directory — a workspace is the project, not the window — and into a fresh session name (unsnooze-2), never by restarting the stopped one, since herdr restores saved agent panes itself and a revival on top would resume the same conversation twice.
  2. Into a fresh workspace; cmux has no joinable named-session model.
  3. As a detached process. Its output goes to ~/.unsnooze/headless/<session>.log, since there is no scrollback to read it out of later; the prompt rides in argv (claude --resume <id> "…", codex exec resume <id> "…"), and a revival that exits non-zero is retried, with its last output as the last error in unsnooze status.
  4. Nothing to wrap into — your own terminal is the session.

Install: brew install tmux or brew install zellij on macOS, sudo apt install tmux on Linux/WSL. herdr comes from herdr.dev — Homebrew still ships 0.7.3, which unsnooze refuses, so take the release binary.

herdr specifics

  • A stopped herdr session is never restarted. herdr restores saved agent panes when a session restarts (resume_agents_on_restore is on by default), so a revival on top would resume the same conversation twice. Reviving into a stopped session creates unsnooze-2 and so on instead. If you restart one yourself and herdr brings the agent back, unsnooze may still open a fresh pane for it; that case is not yet detected.
  • A revival opens a tab, not a workspace or a split. A herdr workspace is the project, so the tab lands in whichever workspace already has that directory open. Neither steals focus.
  • Multi-line resume messages are carried, not typed. herdr starts a pane command by typing it into a shell, where a newline would submit half of it, so such arguments ride in the new tab's environment and reach the agent byte for byte. (A NUL byte is still refused.)
  • A mismatched HERDR_SOCKET_PATH disables watching for that pane. Pane ids are per-server, so acting from the wrong server could type into an unrelated terminal. The agent still runs; unsnooze says why it is not watching.

Day to day

Run your agents like always. When one hits its limit, unsnooze records the stop in ~/.unsnooze/state.json — agent, session id, working directory, pane, and the reset time parsed from the banner — and wakes it when the limit lifts.

unsnooze status (plain / piped)
$ unsnooze status
  [STOPPED  ] f3a1c2d4  claude 5h      /Users/you/work/payments
              mux tmux · pane %12 · session unsnooze · via hook · resets 19/7/2026, 3:00:00 am (2h 41m) (absolute, from hook) · attempts 0/5 · ctx ~152k tok
  [RESUMED  ] 92d6f63d  claude 5h      /Users/you/oss/unsnooze
              mux tmux · pane %7 · session unsnooze · via cli · resets 18/7/2026, 4:11:00 pm (due now) (absolute, from scrape) · attempts 1/5 · attach: tmux attach -t unsnooze

Each session is two lines: a header (status, 8-char id, agent, limit window, working directory) and a detail line (pane, how the stop was detected, the reset time with countdown and its provenance, attempts out of 5, plus ctx ~152k tok on stopped sessions and an attach hint on live ones). Statuses are stopped, resuming, resumed, cancelled, and failed.

On an interactive terminal, status, usage, and sessions open the live dashboard instead; pipes, CI, NO_COLOR, and --json stay plain. Set autoDashboard off to use the terminal view on a TTY too;unsnooze dashboard remains available. The common interventions:

interventions
$ unsnooze message f3a1 "Run the tests first, then continue."
$ unsnooze resume-now f3a1     # don't wait for the reset time
$ unsnooze cancel --all        # stop tracking everything

Not sure what it's about to do? unsnooze preview is 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. It exits 2 when a wake is actionable right now, 0 otherwise — scriptable.

The rest of the docs

Setup is the whole of the required reading. Everything else is here when you need it:

  • Supported agents — how each agent's limit is detected and resumed, OpenRouter and proxy launchers, and Claude Design.
  • Command reference — every command with real output, the unsnooze usage forecast that tells you when the wall arrives, and the prompt queue that starts the next piece of work as a fresh session.
  • Settings and guards — every key in ~/.unsnooze/config.json, the guards that decide when not to wake a session, and how notifications reach you.
  • SSH multi-host fleet — watch limit-stopped sessions on every machine you code on, plus GUI surfaces and platform support.
  • Troubleshooting and security — when a wake did not happen, what unsnooze doctor reports, and the threat model.

Shipped releases and the reasoning behind each change live in the changelog; anything missing or wrong is worth reporting.