Install
$ agentstack add skill-davidsimoes-claude-skills-shared-restart-resume ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
/restart-resume — Rebuild every session post-reboot
Reads the most recent restart manifest produced by /restart-process, recreates the tmux layout (sessions, windows, pane geometry), and spawns fresh claude processes per Claude pane with the captured handoff as the first user message.
Why fresh, not --resume: the whole point of /restart-process + /restart-resume is to take advantage of an updated claude binary, new MCP versions, fresh memory, no stale connections. --resume reuses old session state including the binary version. We deliberately discard that.
Where the manifest lives
By default, $HOME/.cache/claude-restart/latest/manifest.json (a symlink to the most recent archive dir). Override the root via the RESTART_HANDOFFS_DIR env var if /restart-process was configured to write elsewhere.
When to invoke
- A fresh terminal opens post-reboot and a SessionStart hook surfaces a pending manifest banner
- The user says
/restart-resumeor any of the trigger phrases in the description above - Auto-invocation via the SessionStart-hook mechanism — wire your hook to emit
additionalContextreferencing this skill; the model will then invoke without asking
Pre-flight
- Verify a manifest exists at
${RESTART_HANDOFFS_DIR:-$HOME/.cache/claude-restart}/latest/manifest.json. If missing, abort with: "no pending manifest — was /restart-process actually run?".
- Print a summary BEFORE any destructive tmux mutation:
``python import json, os root = os.environ.get("RESTART_HANDOFFS_DIR") or os.path.expanduser("~/.cache/claude-restart") m = json.load(open(f"{root}/latest/manifest.json")) n_sessions = len({w["session"] for w in m["windows"]}) n_claude = sum(1 for w in m["windows"] for p in w["panes"] if p.get("is_claude")) n_panes = sum(len(w["panes"]) for w in m["windows"]) print(f'Manifest from {m["captured_at"]}: {n_claude} claude panes across ' f'{n_sessions} sessions ({n_panes} total panes).') print(f'Orchestrator was at: {m["orchestrator_pane"]}') ``
- Confirm intent to the user: "About to recreate tmux sessions. Existing sessions with the same names will be reused (their first windows may be renamed to manifest names). Proceeding."
Invocation
~/.claude/skills/restart-process/scripts/restore.sh \
"${RESTART_HANDOFFS_DIR:-$HOME/.cache/claude-restart}/latest"
restore.sh is the shared engine (lives in the sibling /restart-process skill dir since that's where the rest of the family lives). It performs seven phases:
- R1. Reads
manifest.json; validatesschema_version: 1; validates sha256 checksum against canonical re-serialization; verifies every referencedhandoff_path,launcher_path,pane_state_pathexists. Exits2on any mismatch. Symlink path arguments are resolved viarealpathup-front (see Failure modes #7).
- R2. For each session in the manifest: if it doesn't exist,
tmux new-session -d -s -c. If it does exist (e.g. a scheduled task or shell startup recreated it between/restart-processand/restart-resume), log and proceed. Handoffs are not lost to silent collisions — the own-pane case (the typical collision) is handled by displaced-spawn in R7. Other collisions are documented under "Known limitations".
- R3. For each window:
tmux new-window -t : -n -c(skips windows that already exist after R2). The explicit-t session:idxis load-bearing — it preserves non-contiguous indices (e.g.{1, 3, 6}) the manifest captured.
- R4. EXPLICIT ORDER per window:
- (i)
tmux split-windowuntil pane count matches manifest - (ii)
tmux select-layout ''to restore exact geometry - (iii)
sleep 0.3then per pane:send-keys - Claude pane: send
cd && claude "$(cat )"+ Enter — claude boots with the handoff as the first user message - Non-Claude pane: send the captured
argv— NO Enter (user reviews before executing)
- R5. Own-pane skip: whichever pane is running
/restart-resumeis the de facto orchestrator for this run and is skipped unconditionally (not just whenis_orchestrator == Truein the manifest). If the skipped pane has a Claude handoff in the manifest, the handoff is queued for displaced-spawn in R7 — it does NOT get orphaned on disk.
- R6. Mark manifest consumed: write a
restored_atmarker file inside the archive dir + remove thelatestsymlink. This prevents a SessionStart banner from firing on subsequent sessions.
- R7. Displaced-spawn queue: for each handoff queued in R5, find the next free window index in the same session and create a new window there named
(resumed). Sendcd && claude "$(cat )"+ Enter so Claude boots with the handoff as its first user message. This lets you invoke/restart-resumefrom a pre-existing session (e.g. a fresh post-reboot terminal that automatically opened a session matching one in the manifest) without losing the Claude that was supposed to land at the orchestrator's pane.
Post-restoration
Tell the user:
- N panes restored (includes any displaced)
- M panes skipped (own-pane skips that had no Claude handoff to displace)
- D panes displaced (own-pane Claude handoffs spawned at
:instead of the manifest's original target — JSON listsorig_target_pane,new_target_pane,window_name) - Any errors
- Manifest archived at
/(no longer thelatestsymlink target)
Failure modes
| # | Failure | Behavior | |---|---|---| | 1 | No latest/ symlink | Abort; no destructive action | | 2 | Checksum mismatch | Abort with stated vs computed hashes | | 3 | Schema version mismatch | Abort — restore engine needs to be updated for new schema | | 4 | Per-pane file missing | Abort — manifest references a file that's not on disk | | 5 | select-layout fails | Non-fatal: tmux falls back to default tiling for that window | | 6 | send-keys fails for one pane | Logged, continue with other panes | | 7 | restore.sh invoked with a symlink path (the typical case) | Resolved via realpath() BEFORE composing any send-keys command — otherwise R6's symlink removal would race the slow-to-init pane shells, causing cat /handoff-*.md to fail and Claude to boot with no context | | 8 | Restore runs in a tmux pane the manifest claims existed (own-pane collision) | Skipped at the original target via R5; the Claude handoff is displaced-spawned at : by R7 (zero info loss) | | 9 | Non-own-pane collision in a pre-existing session (rare) | Existing windows are reused; send-keys lands in them. See "Known limitations" |
Known limitations
- Non-own-pane collisions in pre-existing sessions reuse the existing windows. If a scheduled task or your shell startup created a session with the same name as one in the manifest AND that session also has windows at the same indices the manifest specifies (a rarer case than the own-pane variant, which R7 handles), restore will send-keys into those existing windows. Workaround: kill the conflicting session before invoking
/restart-resume, or pass an alternate manifest dir directly. - Window renaming only applies to freshly-created sessions. If the session already existed (per the limitation above), its windows are NOT renamed — to avoid clobbering user windows.
- Layout strings include a tmux checksum prefix. If you hand-edit a manifest, recompute the layout string via
tmux list-windows -F '#{window_layout}'— otherwiseselect-layoutfails (non-fatal, but the geometry won't match exactly).
When NOT to use
- Mid-task —
restoremutates tmux globally. Don't run if you have active work that conflicts with the manifest's expected sessions. - If a different
/restart-processwas triggered after the manifest you're trying to restore — onlylatestis restored. Older manifests can be restored manually by passing their dir path directly.
Files
This skill is intentionally thin — all the logic lives in the sibling /restart-process skill's scripts/restore.sh. Tests for restore.sh (including regression coverage for #7 above) live in /restart-process/tests/restore.bats.
SKILL.md— this file (just the contract + invocation)- Engine:
../restart-process/scripts/restore.sh - Tests:
../restart-process/tests/restore.bats
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: davidsimoes
- Source: davidsimoes/claude-skills-shared
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.