GitHub - SteveVitali/claude-hibernate: Hibernate & wake Claude Code sessions across reboots. Exact session resume, 9 terminal backends (tmux, iTerm2, kitty…), macOS + Linux.

GitHub

7 min read Original article ↗

CI

Hibernate your running Claude Code sessions before shutdown; wake them after reboot.

Claude Code does not record which sessions are currently running — a machine shutdown kills every session process, and after reboot you're left reconstructing what was open where. claude-hibernate is OS hibernation for those sessions: write the running set to disk before power-off, restore it at boot.

$ claude-hibernate hibernate --all
Hibernated 8 session(s) (scope=all) to ~/.local/state/claude-hibernate/snapshot.json

  ... reboot ...

$ claude-hibernate wake
Waking sessions as a 2-column pane grid in a new iTerm2 window...

Each session comes back in its original directory, on its original session id, with its original launch flags (--model, --dangerously-skip-permissions, ...), in your terminal of choice.

claude-hibernate demo: hibernate, list, wake --dry-run

Why not just claude --continue? It resumes only the most recent session per directory — so it can't bring back the dozen sessions you had spread across a dozen repos, and it can't disambiguate several concurrent sessions in one worktree. wake restores all of them, unattended, each on its own id (more in the FAQ).

Install

Homebrew (via tap):

brew install SteveVitali/tap/claude-hibernate

curl:

curl -fsSL https://raw.githubusercontent.com/SteveVitali/claude-hibernate/main/install.sh | bash

Manual — it's one self-contained bash script:

git clone https://github.com/SteveVitali/claude-hibernate.git
cp claude-hibernate/scripts/claude-hibernate.sh ~/.local/bin/claude-hibernate

Requires bash 3.2+ (macOS system bash works), python3, and standard Unix tools. Then:

claude-hibernate doctor   # verify your environment end-to-end

Quick start

# --- Before shutdown ---
claude-hibernate hibernate --all       # capture every session on the machine
claude-hibernate hibernate             # ... or just this repo's worktrees
claude-hibernate hibernate --dry-run   # preview the table; writes nothing

# --- After reboot ---
claude-hibernate list                  # see what's in the snapshot
claude-hibernate wake --dry-run        # print the resume commands first
claude-hibernate wake                  # reopen + resume everything

# --- Optional: set and forget ---
claude-hibernate hooks install         # exact session tracking (see below)
claude-hibernate auto enable           # snapshot every 10 min, forever

Commands

Command What it does
hibernate Capture running sessions to the snapshot file
wake Reopen + resume every snapshotted session
list Show the snapshot (--live: currently-running sessions)
doctor Verify environment assumptions; ok/warn/FAIL per check
hooks install|uninstall|status Exact session tracking via Claude Code hooks
auto enable|disable|status Periodic auto-snapshot (launchd/systemd/cron)

Scope flags (hibernate, list --live, wake --live): --repo (current repo's worktrees, default), --here ($PWD only), --all (whole machine).

Wake flags: --dry-run (print commands), --fork (resume with --fork-session, fresh ids), --live (source running sessions instead of the snapshot), --launcher <name> (force a terminal backend), --quiet.

How detection works

Finding "running Claude Code sessions" is genuinely tricky — pgrep -x claude misses most real installs. The process is named after the version (e.g. 2.1.202) for native installs, and on Linux Claude rewrites both the process name and command line. claude-hibernate layers four classification rules:

  1. Name — the process basenames to claude (Homebrew/npm on macOS).
  2. Binary path — a version-shaped name whose executable path contains claude (native installer).
  3. Project correlation — a version-shaped name whose working directory maps to a real ~/.claude/projects/<mangled-cwd> directory.
  4. Args — the command line starts with claude (belt and braces).

Each surviving process is mapped to its cwd (lsof / /proc), git branch, and session id. Session ids are resolved with three precedence levels:

  1. Hook records (exact) — if you ran claude-hibernate hooks install, Claude Code itself reports each session's id at startup via a SessionStart hook. Zero guessing.
  2. --resume <uuid> in the process args (exact) — visible on macOS.
  3. Newest transcript heuristic — the N newest .jsonl transcripts in the project directory map to the N processes running there. Right in practice; ambiguous only when several sessions share one directory.

hibernate records all of it to the snapshot; wake reads only the snapshot (the processes are gone by then). The SRC column in list/--dry-run output tells you which method resolved each session (hook vs heuristic).

Terminal launchers

wake auto-detects your terminal, or force one with --launcher / CLAUDE_HIBERNATE_LAUNCHER:

Launcher Platform Behavior
tmux anywhere Windows in your current session, or a detached claude-wake session
iterm2 macOS 2-column pane grid in one new window
terminal macOS One Terminal.app window per session
kitty / wezterm / alacritty any OS windows / native tabs per session
gnome-terminal / konsole Linux Tabs per session
print anywhere Just prints the cd … && claude --resume … commands

Inside tmux, tmux always wins. Everything falls back to print — wake never strands you.

Auto-snapshot

claude-hibernate auto enable              # every 10 minutes
claude-hibernate auto enable --interval 5
claude-hibernate auto status
claude-hibernate auto disable

Installs a launchd agent (macOS), systemd user timer, or crontab entry (Linux) running hibernate --all --quiet. Snapshots are cheap, atomic, and keep 10 timestamped generations in history/ — so even an unplanned power loss costs you at most the last interval.

State layout

${XDG_STATE_HOME:-~/.local/state}/claude-hibernate/
├── snapshot.json    # current snapshot (schema 2, atomic writes)
├── history/         # last 10 timestamped snapshots
└── live/            # hook-maintained per-pid session records

Overrides: CLAUDE_HIBERNATE_STATE_DIR, CLAUDE_HIBERNATE_FILE, CLAUDE_CONFIG_DIR, CLAUDE_HIBERNATE_HISTORY_KEEP. A legacy v0 snapshot (~/.local/state/claude-hibernate.json) is still read if no new-style snapshot exists.

Using as an Agent Skill

The repo doubles as a skill directory (SKILL.md), so Claude Code can drive it conversationally:

ln -s /path/to/claude-hibernate ~/.claude/skills/claude-hibernate

Then: "hibernate my sessions" / "wake my sessions" in any conversation.

Related projects

needs tmux? needs pre-setup? rescues already-running sessions? exact session ids? platforms
claude-hibernate no no (hooks optional) yes yes with hooks; heuristic otherwise macOS + Linux, 9 terminal backends
tmux-resurrect / continuum yes yes (plugin) no n/a (restores panes, not Claude sessions) anywhere tmux runs
tmux-assistant-resurrect yes yes (plugin) no yes (parses pane content) tmux only
agent-resume-style wrappers no yes (must launch claude through the wrapper) no yes varies

If you already live entirely inside tmux with resurrect/continuum configured, a tmux-centric tool restores your whole layout and is the better fit — pair it with claude --continue per pane. claude-hibernate is for everyone else: no wrapper, no plugin, works on sessions that are already running when you first install it.

FAQ

Why not just claude --continue? It resumes only the most recent session per directory, you must remember which directories were live, and it can't disambiguate N concurrent sessions in one worktree. wake restores all of them, unattended.

Will this break when Claude Code updates? Possibly — transcript internals are an unsupported surface. That's why doctor exists, why hook-tracked sessions bypass the heuristics entirely, and why every heuristic degrades soft (empty summary, heuristic source tag) rather than failing.

macOS asked me to allow Automation on first wake. That's the one-time osascript → iTerm2/Terminal permission prompt; approve it and wake proceeds.

Why bash? Zero-install portability: one file, runs on the macOS system bash (3.2) and any Linux, with python3 only for JSON.

Does hibernate stop the sessions? No — it's a snapshot, not a freeze. Your shutdown kills the processes; the snapshot is what lets wake bring them back.

What about Codex / other agents? Out of scope for 1.0 — see Roadmap.

Roadmap

Deliberately out of scope for 1.0, candidates for later: waking into the previous model/permission state beyond captured flags, Ghostty automation (not scriptable yet — use tmux inside Ghostty), Codex/other-agent support, Windows/WSL, and restoring full terminal layouts (use tmux-resurrect for that).

Caveats

  • Unsupported surface: Anthropic documents transcript internals as subject to change on any release. This tool touches them minimally (filenames for session ids, best-effort summaries), and hooks install avoids the heuristics entirely — but a Claude Code update can still break detection. claude-hibernate doctor after upgrades tells you exactly what still works.
  • Waking while the original sessions still run would attach two processes to one session id — wake detects this and skips those sessions (--fork overrides by branching to fresh ids).
  • Flag capture reads process args, which Linux Claude rewrites — on Linux, flags come back only for sessions tracked via hooks.

Uninstall

claude-hibernate auto disable     # remove launchd/systemd/cron job, if enabled
claude-hibernate hooks uninstall  # remove Claude Code hooks, if installed
rm -f ~/.local/bin/claude-hibernate            # or: brew uninstall claude-hibernate
rm -rf ~/.local/state/claude-hibernate         # snapshots + history

Development

shellcheck -x scripts/claude-hibernate.sh   # lint
bats tests/                                 # 44 tests, fully isolated

See CONTRIBUTING.md and docs/SPEC.md for architecture and design decisions, and RELEASING.md for the release process.

Related

Extracted from agent-skills, a collection of research-grounded, harness-agnostic process skills for AI coding agents — this tool is Claude Code-specific by nature, so it lives on its own.

License

MIT