(Skill directory / install name kept as openclaw-emergency-rollback to
avoid breaking existing installations.)
The Recovery Manager provides three independent snapshot/restore subsystems for an OpenClaw install:
openclaw.json + agent & global workspace identity
files. Has an automatic dead-man's-switch watchdog (detached Node
timer plus a native gateway:startup hook) that auto-restores the most
recent config snapshot if the user doesn't accept their changes in time.
This is the original recovery system and its behavior is unchanged.~/.openclaw/skills/ plus each configured
agent's skills directory. Each target keeps its own independent 3-slot
history. Manual snapshots and restores only.~/.openclaw/openclaw.json,
captured as its local project-level manifest and state (not working
content). Each project keeps its own independent 3-slot history. Manual
snapshots and restores only.All three subsystems write to the same change log at
~/.openclaw/rollback/logs/change.log.
Only the config subsystem is ever auto-restored. The watchdog timer and
gateway:startup hook never touch skills or projects.
All scripts are Node.js ( .mjs), which is already installed as an OpenClaw
dependency. No additional packages needed.
If ~/.openclaw/rollback/ does not exist, run setup before anything else.
Read references/SETUP.md now and follow it completely before proceeding.
Critical setup rule: the restart command must be detected, not asked
for. Users often don't know how their own OpenClaw install was deployed,
and guessing kill -USR1 1 when the machine is actually running a systemd
service silently disables auto-recovery. Probe the environment
( systemctl --user is-active openclaw-gateway, docker compose ps, PID 1
identity) before asking. Only ask the user if probes produce no confident
match, and always state what was detected and why before storing.
references/SETUP.md Step 1 has the full detection algorithm.
pkill and Docker/K8s#If you are running OpenClaw as the primary process in a container (PID 1),
do not use pkill -f openclaw to restart the gateway. If you use a
background Dead Man's Switch, pkill will match the path name of the
background script and kill your rescue job instantly.
Instead, use kill -USR1 1 to surgically send the reload signal directly
to the root OpenClaw process.
OpenClaw protects itself from invalid JSON by instantly hot-reloading its last
known good config before the gateway even restarts. To test destructive
recovery properly, you must use Logical Sabotage: feeding OpenClaw
perfectly valid JSON that logically breaks routing (e.g., a dummy token like
64 f s and poisoned workspace paths). This proves the rollback recovers from
logical failure states.
When the config gets sabotaged and OpenClaw restarts, the detached
watchdog-timer may die with the old process tree. That is expected.
To make recovery survive pod/container/local restarts, this skill installs a
native OpenClaw managed hook at ~/.openclaw/hooks/watchdog-recovery/
listening to gateway:startup.
On every gateway startup, the hook reads persistent
~/.openclaw/rollback/watchdog.json:
restore-if-armed.mjs immediately.watchdog-timer.mjs for the remaining seconds.Because the system stores a hard absolute epoch ( expiryEpoch) on persistent
disk, it doesn't matter how long the restart took: if OpenClaw restarts after
expiry, the hook restores immediately; if it restarts before expiry, the hook
recreates the timer.
This is the native cross-environment trigger for pod, Docker, and local machine restarts. No AI, internet, cron, or external supervisor is required.
The watchdog and gateway:startup hook only ever act on CONFIG snapshots.
Skills and projects are never auto-restored.
At the start of every session, run:
bash
UPTIME=$(systemctl --user show openclaw-gateway \
--property=ActiveEnterTimestampMonotonic 2>/dev/null \
| awk -F= '{if($2>0) print int((systime()*1000000-$2)/1000000); else print 999}')
if [ "$UPTIME" = "999" ]; then
UPTIME=$(ps -o etimes= -p $(pgrep -f "openclaw" 2>/dev/null) 2>/dev/null | tr -d ' ')
fi
If uptime is under 90 seconds AND ~/.openclaw/rollback/watchdog.json exists
and shows "armed": true, the gateway just bounced. Open the session with the
Watchdog Reminder (see below).
If armed but uptime is over 90 seconds, still check and remind — the user may have connected to a running session mid-timer.
If armed: false or watchdog file doesn't exist, start the session normally.
Run ~/.openclaw/rollback/scripts/watchdog-status.mjs and display:
text
⚠️ Emergency recovery is armed.
Snapshot [1] "<label>" will auto-restore in ~XX minutes
unless you accept or extend.
Commands:
• "accept changes" — disarm watchdog, lock in current config
• "extend recovery XX minutes" — add more time to the timer
• "list snapshots" — show all saved config snapshots
• "restore snapshot 2" — manually restore snapshot 2 or 3
• "create snapshot" — save current state as new snapshot [1]
Save current OpenClaw config as the new known-good restore point.
~/.openclaw/rollback/scripts/snapshot.mjs "<description>" "<ai_summary>"~/.openclaw/openclaw.json — note the default model, number of agents,
any notable tools or channels — and pass it as the second argument.text
✅ Snapshot saved.
[1] Apr 20 2:30 PM — <description> ← restore target
[2] Apr 19 9:00 AM — <previous label>
[3] Apr 18 4:00 PM — <oldest label>
Slot [1] is always the most recent. Slot [3] is always the oldest. When a 4th snapshot would be created, slot [3] is overwritten as the others shift. Snapshots are never deleted without the user explicitly creating a new one that pushes the oldest out. If the user wants to preserve all three, they can copy slot [3] before creating a new snapshot.
Arm the watchdog dead man's switch.
~/.openclaw/rollback/scripts/watchdog-set.mjs <minutes>text
⏱️ Watchdog armed — XX minutes.
Snapshot [1] "<label>" auto-restores at <HH:MM> if not accepted.
Make your changes whenever you're ready.
If no snapshot exists yet, tell the user to create one first before arming.
Add time to the active watchdog timer.
~/.openclaw/rollback/scripts/watchdog-extend.mjs <minutes>Disarm the watchdog — user is happy with the current config.
~/.openclaw/rollback/scripts/watchdog-clear.mjstext
✅ Watchdog disarmed. Your changes are locked in.
Say "create snapshot" to save this config as your new restore point [1].
Show all saved config snapshots.
Read ~/.openclaw/rollback/manifest.json and display:
text
Saved snapshots (most recent first):
[1] Apr 20 2:30 PM — "opus model working, github tool added"
Config: claude-opus-4 default, 2 agents (main, coding), github MCP active
[2] Apr 19 9:00 AM — "initial clean setup"
Config: claude-sonnet-4 default, 1 agent (main), no extra tools
[3] Apr 18 4:00 PM — "baseline before any changes"
Config: claude-haiku-4 default, 1 agent (main)
Restore target: [1] (auto-restored if watchdog fires)
Watchdog: ARMED — 14m 32s remaining [or: NOT ARMED]
Manually restore a specific config snapshot immediately.
~/.openclaw/rollback/scripts/restore.mjs <slot>Run a destructive test of the full config recovery pipeline.
Read references/TESTING.md for the complete procedure. This test:
~/.openclaw/rollback/openclaw.recoveryopenclaw.json to simulate a bad config changegateway:startup hook to restore automaticallyThis is destructive. The user will lose access to their AI session for up to 2 minutes while the test runs. Before running, confirm the user understands the risks and has terminal/SSH access to manually recover if something goes wrong.
Skills targets are discovered dynamically from ~/.openclaw/openclaw.json at
each snapshot. Each target (global + each configured agent) maintains its own
independent 3-slot history under ~/.openclaw/rollback/skills/<target>/.
Snapshot global skills and every configured agent's skills simultaneously. All targets receive the same user-provided description.
~/.openclaw/rollback/scripts/skills-snapshot.mjs all "<description>"Snapshot only ~/.openclaw/skills/.
~/.openclaw/rollback/scripts/skills-snapshot.mjs global "<description>"Snapshot a single agent's skills directory.
~/.openclaw/rollback/scripts/skills-snapshot.mjs <agent-id> "<description>"Show every skills target with its 3-slot history.
~/.openclaw/rollback/scripts/skills-list.mjsShow the 3-slot history for a single target.
~/.openclaw/rollback/scripts/skills-list.mjs global
or ~/.openclaw/rollback/scripts/skills-list.mjs <agent-id>Restore each target's slot 1 independently.
~/.openclaw/rollback/scripts/skills-restore.mjs allRestore slot 1 (default) or a specific slot for a single target.
~/.openclaw/rollback/scripts/skills-restore.mjs global [N]
or ~/.openclaw/rollback/scripts/skills-restore.mjs <agent-id> [N]Skills snapshots are never auto-restored by the recovery timer or the
gateway:startup hook. They do not arm the watchdog and the watchdog never
touches them.
Project paths are discovered dynamically from ~/.openclaw/openclaw.json at
each snapshot. Each project keeps its own 3-slot history under
~/.openclaw/rollback/projects/<project>/.
Snapshot every configured project. All receive the same description.
~/.openclaw/rollback/scripts/projects-snapshot.mjs all "<description>"Snapshot a single project.
~/.openclaw/rollback/scripts/projects-snapshot.mjs <project> "<description>"Show every project with its 3-slot history.
~/.openclaw/rollback/scripts/projects-list.mjsShow the 3-slot history for a single project.
~/.openclaw/rollback/scripts/projects-list.mjs <project>Restore each project's slot 1 independently.
~/.openclaw/rollback/scripts/projects-restore.mjs allRestore slot 1 (default) or a specific slot.
~/.openclaw/rollback/scripts/projects-restore.mjs <project> [N]Projects snapshots are never auto-restored by the recovery timer or the
gateway:startup hook.
FilePathMaster config~/.openclaw/openclaw.jsonGlobal workspace identity files~/.openclaw/workspace/*.md _(whole-glob: SOUL.md, AGENTS.md, any new .md)_Per-agent workspace files<agent_workspace>/SOUL.md``<agent_workspace>/AGENTS.md``<agent_workspace>/USER.md``<agent_workspace>/IDENTITY.md``<agent_workspace>/TOOLS.md``<agent_workspace>/HEARTBEAT.md``<agent_workspace>/BOOT.md (if present)
Workspace paths and agentIds are read dynamically from openclaw.json at
snapshot time — covers all configured agents automatically.
Never captured by config snapshots: credentials/, auth-profiles.json, session history, memory logs, workspace content files, .env, Docker/K8s environment config.
~/.openclaw/skills/ (global)skills field,
or <agent_workspace>/skills/ if no explicit field)ItemNotesopenclaw.jsonproject-local manifest & MCP spawn instructionsmcp_config.jsontool bridge to external servicespackage.jsonlocal MCP server dependenciesTASKS.json, PROCESSES.json, SPRINT_CURRENT.jsonstate files, if present./tools/local MCP server source scripts./skills/project-local skills.openclaw/workspace.state.jsonproject structural state./comms/directory tree structure ONLY, no file content
Explicitly excluded from project snapshots:
node_modules/memory/auth-profiles.json~/.openclaw/ root (already covered by config snapshots)Respond with this explanation:
text
OpenClaw Recovery Manager — How It Works
Three independent snapshot/restore subsystems sharing one change log.
1. CONFIG (with auto-restore watchdog — the original dead-man's-switch)
"create snapshot [description]" — save current config as restore point
"set emergency recovery XX minutes" — arm the auto-restore timer
"extend recovery XX minutes" — add time to active timer
"accept changes" — disarm timer, keep current config
"list snapshots" — show all 3 saved config snapshots
"restore snapshot [1|2|3]" — manually restore a specific snapshot
"test emergency recovery" — destructive test of the full pipeline
If the user doesn't accept config changes before the timer fires, the
system auto-restores snapshot [1] and restarts OpenClaw — no AI, no
network, no user intervention required.
2. SKILLS (manual only — no auto-restore, no watchdog involvement)
"snapshot all skills [description]"
"snapshot global skills [description]"
"snapshot <agent> skills [description]"
"list skills snapshots"
"list global skills snapshots" / "list <agent> skills snapshots"
"restore all skills"
"restore global skills [snapshot N]"
"restore <agent> skills [snapshot N]"
3. PROJECTS (manual only — no auto-restore, no watchdog involvement)
"snapshot all projects [description]"
"snapshot <project> project [description]"
"list project snapshots"
"list <project> snapshots"
"restore all projects"
"restore <project> project [snapshot N]"
Each target (config / each skill target / each project) keeps its own
independent 3-slot history. Slot [1] is always most recent, slot [3] oldest;
a 4th snapshot pushes slot [3] out.
The auto-restore watchdog is CONFIG ONLY. It never touches skills or
projects.
Dependencies: Node.js (already installed with OpenClaw), tar, gzip.
Append to ~/.openclaw/rollback/logs/change.log whenever any of the
following happens in any subsystem:
Format:
text
[YYYY-MM-DD HH:MM:SS] <EVENT TYPE>
<key: value details>
---
references/SETUP.md — Read this first if ~/.openclaw/rollback/ does not existreferences/TESTING.md — Destructive recovery test procedure (config subsystem)references/RESTORE.md — Manual recovery instructions requiring no AI or scriptsscripts/ — Node.js scripts ( .mjs) — no shell wrappers neededhooks/watchdog-recovery/ — Native OpenClaw startup hook for config restart recovery