Skills upgrade
Safe OpenClaw upgrade with instant rollback. Use when user says "upgrade openclaw", "update openclaw", "check for updates", or any request to upgrade/update the OpenClaw installation. NOT for config changes (use gateway config.patch). NOT for skill updates (use clawhub).
install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/aliahmadaziz/openclaw-safe-upgrade" ~/.claude/skills/clawdbot-skills-upgrade && rm -rf "$T"
OpenClaw · Install into ~/.openclaw/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/aliahmadaziz/openclaw-safe-upgrade" ~/.openclaw/skills/clawdbot-skills-upgrade && rm -rf "$T"
manifest:
skills/aliahmadaziz/openclaw-safe-upgrade/SKILL.mdsource content
OpenClaw Safe Upgrade
Single atomic command. Auto-rollbacks on ANY failure. Survives the gateway restart it triggers.
Script
# From an agent session — ALWAYS set escape flag (ensures script survives gateway restart) _UPGRADE_FORCE_ESCAPE=1 bash skills/upgrade/scripts/safe-upgrade.sh # Force upgrade even if already on latest _UPGRADE_FORCE_ESCAPE=1 bash skills/upgrade/scripts/safe-upgrade.sh --force # Safe read-only checks (no escape needed) bash skills/upgrade/scripts/safe-upgrade.sh --check # Pre-flight only bash skills/upgrade/scripts/safe-upgrade.sh --rollback # Manual rollback
What Happens (one command, 10 steps)
- Cgroup escape: re-execs via
so gateway stop can't kill the scriptsystemd-run --user --scope - Pre-flight: version check, disk space, breaking changes
- Backup: installation tarball, config, cron jobs, acpx customizations
npm i -g openclaw@latest- Restore acpx config (ACP agent customizations survive upgrades)
- Gateway restart (process-isolated: stop + start, survives script's own lifecycle)
- Wait for gateway health (configurable timeout) → auto-rollback if fails
- Wait for WhatsApp reconnect (non-fatal timeout)
- Verify: correct version + cron count preserved → auto-rollback if fails
- Record result → optional golden snapshot → cleanup backup
If ANY critical check fails, the script automatically rolls back — restores install, config, crons, and acpx. Trap handler catches unexpected exits during critical phases.
Agent Workflow
- Run
first. Review output with the user.--check - Inform user: "Launching upgrade — I'll go offline during gateway restart."
- Run the upgrade:
Do NOT pipe the output (no_UPGRADE_FORCE_ESCAPE=1 bash skills/upgrade/scripts/safe-upgrade.sh
, no| tee
). The script writes to2>&1 | cat
./tmp/upgrade-live.log - The current session will end when the gateway restarts. This is expected.
- After restart, the new session checks:
for status~/.openclaw/upgrade-result.json
for live output/tmp/upgrade-live.log
: report to user, update any version referencessuccess
: tell user what went wrong (reason in result file)rolled_back- No result file + backup at
: script was killed — run~/.openclaw/upgrade-backups/current/--rollback
- Full forensic log at
.~/.openclaw/upgrade-last.log
What Gets Backed Up
- OpenClaw installation tarball
- Config (
)openclaw.json - Cron jobs (
)jobs.json - acpx user config (
) if present~/.acpx/config.json - Metadata (from/to version, timestamp, cron count)
Backup location:
~/.openclaw/upgrade-backups/current/
Result File
~/.openclaw/upgrade-result.json:
{ "status": "success|rolled_back|rollback_failed|no_change|blocked", "from_version": "2026.3.2", "to_version": "2026.3.7", "message": "...", "timestamp": "...", "log": "~/.openclaw/upgrade-last.log" }
Why Cgroup Escape?
OpenClaw runs as a systemd service. When an agent runs this script, the script is a child process inside the service's cgroup.
systemctl stop sends SIGKILL to ALL processes in the cgroup — including the upgrade script. SIGKILL cannot be caught (no trap handler fires).
The script detects this and re-execs itself via
systemd-run --user --scope into its own transient systemd scope. The parent process exits immediately — no pipes, no tee, no connections back to the gateway cgroup. This is why piping output is forbidden.
Important Notes
- Never run
directly — always use this scriptgateway update.run - Always set
when running from an agent session_UPGRADE_FORCE_ESCAPE=1 - acpx customizations are auto-preserved across upgrades
- Rollback restores the EXACT previous state: install + config + crons + acpx
is safe to run anytime, changes nothing--check- The script auto-detects gateway port from config (no hardcoded defaults)
- Optional hooks: if
orgolden-snapshot.sh
exist in your workspace, they're used; otherwise silently skippedservice-quick-check.py