Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions platform/docs/BACKUP_AND_RECOVERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
- harness results you want to keep
- compose state for Postgres / LiteLLM / Qdrant if you need continuity

`clawops recovery backup-create` now writes archives under the StrongClaw state
root (for example `~/.local/state/strongclaw/backups` on Linux) instead of
`~/.openclaw/backups`, which prevents backup self-inclusion during fallback
archive traversal.

## Included commands

- `clawops recovery backup-create`
Expand All @@ -21,16 +26,31 @@ OpenClaw CLI path (`openclaw-cli`) or the local tar fallback path

## Scheduled maintenance

StrongClaw host service activation now installs a daily maintenance schedule at `04:00` local time:
StrongClaw host service activation now installs independent daily jobs:

- backup create at `03:00` local time
- backup verify at `03:30` local time
- prune retention at `04:00` local time

systemd units/timers:

- `openclaw-backup-create.timer` -> `openclaw-backup-create.service`
- `openclaw-backup-verify.timer` -> `openclaw-backup-verify.service`
- `openclaw-maintenance.timer` -> `openclaw-maintenance.service`

launchd agents:

- systemd: `openclaw-maintenance.timer` -> `openclaw-maintenance.service`
- launchd: `ai.openclaw.maintenance`
- `ai.openclaw.backup-create`
- `ai.openclaw.backup-verify`
- `ai.openclaw.maintenance`

The scheduled command is:
Commands:

- `clawops recovery --home-dir <home> backup-create`
- `clawops recovery --home-dir <home> backup-verify latest`
- `clawops recovery --home-dir <home> prune-retention`

This maintenance path is idempotent and retention-only. It prunes expired
The prune path is idempotent and retention-only. It prunes expired
StrongClaw-owned backup and log artifacts and does not mutate upstream
OpenClaw internals or shared `/tmp/openclaw` state by default.

Expand Down
51 changes: 51 additions & 0 deletions platform/launchd/ai.openclaw.backup-create.plist.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ai.openclaw.backup-create</string>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-lc</string>
<string>set -euo pipefail; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" backup-create</string>
</array>
<key>WorkingDirectory</key>
<string>__REPO_ROOT__</string>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key>
<string>__HOME_DIR__</string>
<key>XDG_CONFIG_HOME</key>
<string>__HOME_DIR__/.config</string>
<key>OPENCLAW_HOME</key>
<string>__OPENCLAW_HOME__</string>
<key>OPENCLAW_STATE_DIR</key>
<string>__STATE_DIR__</string>
<key>OPENCLAW_CONFIG_PATH</key>
<string>__OPENCLAW_CONFIG_PATH__</string>
<key>OPENCLAW_CONFIG</key>
<string>__OPENCLAW_CONFIG__</string>
<key>OPENCLAW_PROFILE</key>
<string>__OPENCLAW_PROFILE__</string>
<key>STRONGCLAW_RUNTIME_ROOT</key>
<string>__STRONGCLAW_RUNTIME_ROOT__</string>
<key>PATH</key>
<string>__HOME_DIR__/.config/varlock/bin:__HOME_DIR__/.local/bin:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
__LAUNCHD_EXTRA_ENV__
</dict>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>__STATE_DIR__/logs/launchd-backup-create.out.log</string>
<key>StandardErrorPath</key>
<string>__STATE_DIR__/logs/launchd-backup-create.err.log</string>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
51 changes: 51 additions & 0 deletions platform/launchd/ai.openclaw.backup-verify.plist.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ai.openclaw.backup-verify</string>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-lc</string>
<string>set -euo pipefail; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" backup-verify latest</string>
</array>
<key>WorkingDirectory</key>
<string>__REPO_ROOT__</string>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key>
<string>__HOME_DIR__</string>
<key>XDG_CONFIG_HOME</key>
<string>__HOME_DIR__/.config</string>
<key>OPENCLAW_HOME</key>
<string>__OPENCLAW_HOME__</string>
<key>OPENCLAW_STATE_DIR</key>
<string>__STATE_DIR__</string>
<key>OPENCLAW_CONFIG_PATH</key>
<string>__OPENCLAW_CONFIG_PATH__</string>
<key>OPENCLAW_CONFIG</key>
<string>__OPENCLAW_CONFIG__</string>
<key>OPENCLAW_PROFILE</key>
<string>__OPENCLAW_PROFILE__</string>
<key>STRONGCLAW_RUNTIME_ROOT</key>
<string>__STRONGCLAW_RUNTIME_ROOT__</string>
<key>PATH</key>
<string>__HOME_DIR__/.config/varlock/bin:__HOME_DIR__/.local/bin:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
__LAUNCHD_EXTRA_ENV__
</dict>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
<key>StandardOutPath</key>
<string>__STATE_DIR__/logs/launchd-backup-verify.out.log</string>
<key>StandardErrorPath</key>
<string>__STATE_DIR__/logs/launchd-backup-verify.err.log</string>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
2 changes: 1 addition & 1 deletion platform/launchd/ai.openclaw.maintenance.plist.template
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<array>
<string>/bin/sh</string>
<string>-lc</string>
<string>set -euo pipefail; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" backup-create; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" backup-verify latest; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" prune-retention</string>
<string>set -euo pipefail; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" prune-retention</string>
</array>
<key>WorkingDirectory</key>
<string>__REPO_ROOT__</string>
Expand Down
16 changes: 16 additions & 0 deletions platform/systemd/openclaw-backup-create.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[Unit]
Description=StrongClaw backup creation task
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
WorkingDirectory=__REPO_ROOT__
Environment=OPENCLAW_STATE_DIR=__STATE_DIR__
Environment=OPENCLAW_HOME=__OPENCLAW_HOME__
Environment=OPENCLAW_CONFIG_PATH=__OPENCLAW_CONFIG_PATH__
Environment=OPENCLAW_CONFIG=__OPENCLAW_CONFIG__
Environment=OPENCLAW_PROFILE=__OPENCLAW_PROFILE__
Environment=STRONGCLAW_RUNTIME_ROOT=__STRONGCLAW_RUNTIME_ROOT__
Environment=PATH=%h/.config/varlock/bin:%h/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
ExecStart=__PYTHON_EXECUTABLE__ -m clawops recovery --home-dir __HOME_DIR__ backup-create
10 changes: 10 additions & 0 deletions platform/systemd/openclaw-backup-create.timer
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=Run StrongClaw backup creation daily

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
Unit=openclaw-backup-create.service

[Install]
WantedBy=timers.target
16 changes: 16 additions & 0 deletions platform/systemd/openclaw-backup-verify.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[Unit]
Description=StrongClaw backup verification task
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
WorkingDirectory=__REPO_ROOT__
Environment=OPENCLAW_STATE_DIR=__STATE_DIR__
Environment=OPENCLAW_HOME=__OPENCLAW_HOME__
Environment=OPENCLAW_CONFIG_PATH=__OPENCLAW_CONFIG_PATH__
Environment=OPENCLAW_CONFIG=__OPENCLAW_CONFIG__
Environment=OPENCLAW_PROFILE=__OPENCLAW_PROFILE__
Environment=STRONGCLAW_RUNTIME_ROOT=__STRONGCLAW_RUNTIME_ROOT__
Environment=PATH=%h/.config/varlock/bin:%h/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
ExecStart=__PYTHON_EXECUTABLE__ -m clawops recovery --home-dir __HOME_DIR__ backup-verify latest
10 changes: 10 additions & 0 deletions platform/systemd/openclaw-backup-verify.timer
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=Run StrongClaw backup verification daily

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
Unit=openclaw-backup-verify.service

[Install]
WantedBy=timers.target
2 changes: 0 additions & 2 deletions platform/systemd/openclaw-maintenance.service
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,4 @@ Environment=OPENCLAW_CONFIG=__OPENCLAW_CONFIG__
Environment=OPENCLAW_PROFILE=__OPENCLAW_PROFILE__
Environment=STRONGCLAW_RUNTIME_ROOT=__STRONGCLAW_RUNTIME_ROOT__
Environment=PATH=%h/.config/varlock/bin:%h/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
ExecStart=__PYTHON_EXECUTABLE__ -m clawops recovery --home-dir __HOME_DIR__ backup-create
ExecStart=__PYTHON_EXECUTABLE__ -m clawops recovery --home-dir __HOME_DIR__ backup-verify latest
ExecStart=__PYTHON_EXECUTABLE__ -m clawops recovery --home-dir __HOME_DIR__ prune-retention
30 changes: 25 additions & 5 deletions src/clawops/assets/platform/docs/BACKUP_AND_RECOVERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
- harness results you want to keep
- compose state for Postgres / LiteLLM / Qdrant if you need continuity

`clawops recovery backup-create` now writes archives under the StrongClaw state
root (for example `~/.local/state/strongclaw/backups` on Linux) instead of
`~/.openclaw/backups`, which prevents backup self-inclusion during fallback
archive traversal.

## Included commands

- `clawops recovery backup-create`
Expand All @@ -21,16 +26,31 @@ OpenClaw CLI path (`openclaw-cli`) or the local tar fallback path

## Scheduled maintenance

StrongClaw host service activation now installs a daily maintenance schedule at `04:00` local time:
StrongClaw host service activation now installs independent daily jobs:

- backup create at `03:00` local time
- backup verify at `03:30` local time
- prune retention at `04:00` local time

systemd units/timers:

- `openclaw-backup-create.timer` -> `openclaw-backup-create.service`
- `openclaw-backup-verify.timer` -> `openclaw-backup-verify.service`
- `openclaw-maintenance.timer` -> `openclaw-maintenance.service`

launchd agents:

- systemd: `openclaw-maintenance.timer` -> `openclaw-maintenance.service`
- launchd: `ai.openclaw.maintenance`
- `ai.openclaw.backup-create`
- `ai.openclaw.backup-verify`
- `ai.openclaw.maintenance`

The scheduled command is:
Commands:

- `clawops recovery --home-dir <home> backup-create`
- `clawops recovery --home-dir <home> backup-verify latest`
- `clawops recovery --home-dir <home> prune-retention`

This maintenance path is idempotent and retention-only. It prunes expired
The prune path is idempotent and retention-only. It prunes expired
StrongClaw-owned backup and log artifacts and does not mutate upstream
OpenClaw internals or shared `/tmp/openclaw` state by default.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ai.openclaw.backup-create</string>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-lc</string>
<string>set -euo pipefail; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" backup-create</string>
</array>
<key>WorkingDirectory</key>
<string>__REPO_ROOT__</string>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key>
<string>__HOME_DIR__</string>
<key>XDG_CONFIG_HOME</key>
<string>__HOME_DIR__/.config</string>
<key>OPENCLAW_HOME</key>
<string>__OPENCLAW_HOME__</string>
<key>OPENCLAW_STATE_DIR</key>
<string>__STATE_DIR__</string>
<key>OPENCLAW_CONFIG_PATH</key>
<string>__OPENCLAW_CONFIG_PATH__</string>
<key>OPENCLAW_CONFIG</key>
<string>__OPENCLAW_CONFIG__</string>
<key>OPENCLAW_PROFILE</key>
<string>__OPENCLAW_PROFILE__</string>
<key>STRONGCLAW_RUNTIME_ROOT</key>
<string>__STRONGCLAW_RUNTIME_ROOT__</string>
<key>PATH</key>
<string>__HOME_DIR__/.config/varlock/bin:__HOME_DIR__/.local/bin:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
__LAUNCHD_EXTRA_ENV__
</dict>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>__STATE_DIR__/logs/launchd-backup-create.out.log</string>
<key>StandardErrorPath</key>
<string>__STATE_DIR__/logs/launchd-backup-create.err.log</string>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ai.openclaw.backup-verify</string>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-lc</string>
<string>set -euo pipefail; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" backup-verify latest</string>
</array>
<key>WorkingDirectory</key>
<string>__REPO_ROOT__</string>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key>
<string>__HOME_DIR__</string>
<key>XDG_CONFIG_HOME</key>
<string>__HOME_DIR__/.config</string>
<key>OPENCLAW_HOME</key>
<string>__OPENCLAW_HOME__</string>
<key>OPENCLAW_STATE_DIR</key>
<string>__STATE_DIR__</string>
<key>OPENCLAW_CONFIG_PATH</key>
<string>__OPENCLAW_CONFIG_PATH__</string>
<key>OPENCLAW_CONFIG</key>
<string>__OPENCLAW_CONFIG__</string>
<key>OPENCLAW_PROFILE</key>
<string>__OPENCLAW_PROFILE__</string>
<key>STRONGCLAW_RUNTIME_ROOT</key>
<string>__STRONGCLAW_RUNTIME_ROOT__</string>
<key>PATH</key>
<string>__HOME_DIR__/.config/varlock/bin:__HOME_DIR__/.local/bin:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
__LAUNCHD_EXTRA_ENV__
</dict>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
<key>StandardOutPath</key>
<string>__STATE_DIR__/logs/launchd-backup-verify.out.log</string>
<key>StandardErrorPath</key>
<string>__STATE_DIR__/logs/launchd-backup-verify.err.log</string>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<array>
<string>/bin/sh</string>
<string>-lc</string>
<string>set -euo pipefail; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" backup-create; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" backup-verify latest; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" prune-retention</string>
<string>set -euo pipefail; "__PYTHON_EXECUTABLE__" -m clawops recovery --home-dir "__HOME_DIR__" prune-retention</string>
</array>
<key>WorkingDirectory</key>
<string>__REPO_ROOT__</string>
Expand Down
Loading
Loading