Skill: zhao95/soul-undead (version 1.1.0)

--- name: soul-undead description: Backup, restore, initialize, and sync core OpenClaw workspace markdown files with the fixed private GitHub repository `soul-undead`. Use when the user wants reinstall-safe recovery of AGENTS.md, HEARTBEAT.md, IDENTITY.md, SOUL.md, TOOLS.md, USER.md, and MEMORY.md, or wants those files kept synced to GitHub after real saved changes. Always check GitHub CLI authentication first; if not authenticated, stop and guide the user to complete `gh auth login`. --- # Soul Undead Manage these fixed core files from the OpenClaw workspace: - `AGENTS.md` - `HEARTBEAT.md` - `IDENTITY.md` - `SOUL.md` - `TOOLS.md` - `USER.md` - `MEMORY.md` Fixed repository name: - `soul-undead` Repository visibility is always **private**. ## What this skill does This skill is for preserving and restoring the core markdown files that define an OpenClaw workspace identity and behavior. It is designed for these situations: - First-time setup of a private backup repo for the core files - Restoring the core files onto a new machine after reinstalling OpenClaw - Manually syncing saved local changes back to the GitHub backup repo This skill intentionally does **not** scan the whole workspace and does **not** back up every markdown file. It only manages this fixed core file set. ## Rules - Always check `gh auth status` first. - If GitHub authentication is missing, stop and tell the user to run `gh auth login`. - Do not scan the whole workspace. - Do not ask the user to choose files unless they explicitly ask for a different scope. - Treat the fixed GitHub repo as the authority during first-time initialization on a new machine. - Before any remote restore overwrites local files, create a timestamped local backup snapshot under [REDACTED_SECRET]. - Do not keep a persistent local export mirror; sync should act directly on the GitHub private repo. ## Important behavior: first restore can overwrite local default files On a new machine, OpenClaw may already have generated local default markdown files. This skill does **not** treat those default files as authoritative. If all of the following are true: - GitHub authentication succeeds - The fixed repo `soul-undead` exists - The local state file does not yet say `initialized: true` then this skill will treat that run as a **first-time restore scenario** and pull the remote file set down to the local workspace. That means the remote files can overwrite local default files created by a fresh OpenClaw installation. To reduce risk, the restore order is always: 1. save the current local file set into a timestamped snapshot 2. pull the remote file set from GitHub 3. overwrite the current local files with the remote version The snapshot is stored under: - `~/.openclaw/workspace/skills/soul-undead/local-backups/<timestamp>/` That snapshot is the local fallback if the restore direction was wrong or the remote version is not the one the user wants. ## State file Use a local state file to mark successful initialization: - `~/.openclaw/workspace/skills/soul-undead/.workspace-backup-state.json` Write: ```json {"initialized": true, "repo": "soul-undead"} ``` Only after one of these succeeds: 1. Restore succeeds from the default GitHub repo 2. First-time repo creation and initial upload succeeds Do not write `initialized: true` on failure. ## Required dependencies This skill assumes these tools are available: - `git` - `gh` (GitHub CLI) - `python3` Minimum expectations: - `gh auth status` must succeed before any restore or sync - The active GitHub account must have permission to read/create/push the private repo If `gh` is installed but not authenticated, stop and tell the user to run: ```bash gh auth login ``` If a dependency is missing, tell the user exactly which command/tool must be installed before continuing. ## Required user-facing reminders before execution Before executing restore, first-time init, or sync, explicitly remind the user of the relevant points below. ### Always remind - This skill only manages these files: `AGENTS.md`, `HEARTBEAT.md`, `IDENTITY.md`, `SOUL.md`, `TOOLS.md`, `USER.md`, `MEMORY.md` - The GitHub repository is private and fixed to `soul-undead` - `gh auth login` is required if GitHub CLI authentication is missing ### If first-time restore may happen Explicitly warn that: - if the remote repo already exists, the skill may restore remote files onto the local workspace during first initialization - this can overwrite local default markdown files created by a fresh OpenClaw install - before overwrite, the skill will create a timestamped local backup snapshot under [REDACTED_SECRET] ### If sync/upload is the user's intent Explicitly confirm the task as sync/upload intent and avoid accidentally running restore-first behavior. ## Workflow ### 1. Check GitHub authentication Run: ```bash gh auth status ``` If authentication fails, stop and guide the user to run: ```bash gh auth login ``` ### 2. Initialization / restore decision Use the bundled script: ```bash bash <skill-dir>/scripts/init_or_sync.sh ``` Behavior: - Uses the fixed repo name `soul-undead` - Uses the fixed core file set only - If the state file is missing or not initialized: - If the GitHub repo exists, first snapshot the current local files, then restore from GitHub, then overwrite the local file set - If the GitHub repo does not exist, create it as private and upload the local file set directly to GitHub - On success, write `initialized: true` - If already initialized, sync local saved changes directly to GitHub ### 3. Sync after saved changes After initialization is complete, use the same script again whenever the tracked files may have changed. Behavior: - Reads the fixed file set directly from the workspace - Writes each tracked file directly to the GitHub private repo - Also maintains `README.md` and `restore.sh` in the GitHub repo - Does not keep a persistent local export mirror ## Preview / dry-run design (not implemented yet) If preview support is added later, it should report intent without making changes. The preview should show these four things: 1. **Planned path** - `restore from remote` - `first-time init + upload` - `sync upload` - `no-op` 2. **Affected files** - Which of the fixed core files would be overwritten locally - Or which of the fixed core files would be written to GitHub 3. **Safety actions** - Whether a local timestamped snapshot would be created before remote restore - The expected backup path under `skills/soul-undead/local-backups/<timestamp>/` 4. **Precondition status** - Whether `gh auth status` passes - Whether the default repo exists - Whether the state file is initialized Preview mode should never: - overwrite local files - create or update the GitHub repo - write remote file contents - write `initialized: true` ## Failure handling Use these failure rules: ### GitHub auth failure - Do not continue - Tell the user to run `gh auth login` ### Missing dependency - Do not continue - Tell the user which dependency is missing: `git`, `gh`, or `python3` ### Repo does not exist during first use - Treat it as first-time initialization - Create the private repo - Upload the local fixed file set directly to GitHub - Only then write `initialized: true` ### Remote restore fails - Do not write `initialized: true` - Keep the local backup snapshot that was created before overwrite - Tell the user restore failed and where the local snapshot is stored ### Remote restore succeeds but the restored version is wrong - Treat the local pre-restore snapshot as the rollback source of truth - Restore the desired files back from `local-backups/<timestamp>/` into the workspace - After confirming the workspace is correct again, sync that corrected local version back to GitHub ### Sync/push fails - Do not change initialization state - Tell the user the sync failed - Leave the local files untouched so sync can be retried later ## Defaults - Workspace path: `~/.openclaw/workspace` - State file: `~/.openclaw/workspace/skills/soul-undead/.workspace-backup-state.json` - Local restore-safety backup path: `~/.openclaw/workspace/skills/soul-undead/local-backups/<timestamp>/` - Repository visibility: **private** - Repository name: `soul-undead` - Tracked files: fixed core file set only ## Notes - On a new machine, remote restore wins over freshly generated local default md files during first initialization. - The remote repo stores helper files such as `README.md` and `restore.sh` alongside the tracked markdown files. - This skill is intentionally minimal: no whole-workspace scan, no persistent local export repo mirror.

path: README.md
content: # soul-undead

A publishable OpenClaw skill project for backing up and restoring core workspace markdown files with a GitHub repository.

## Purpose

`soul-undead` manages this fixed set of core files:

- `AGENTS.md`
- `HEARTBEAT.md`
- `IDENTITY.md`
- `SOUL.md`
- `TOOLS.md`
- `USER.md`
- `MEMORY.md`

It supports two primary flows:

1. **Sync local core files to GitHub**
2. **Restore from GitHub to local workspace**

Before a remote restore overwrites local files, it creates a local timestamped snapshot for rollback safety.

## Included in this publishable project

- `SKILL.md`
- `scripts/init_or_sync.sh`
- `assets/logic-diagram-zh.png`
- `assets/logic-diagram-en.png`

## Not included in the publishable project

These are runtime artifacts and should not be committed or published:

- `local-backups/`
- `.workspace-backup-state.json`

They are created automatically when the installed skill runs.

## Diagrams

### English

![soul-undead logic diagram (EN)](assets/logic-diagram-en.png)


## Notes

- The default repo name is `soul-undead`.
- The skill uses `gh`, `git`, and `python3`.
- `gh auth login` must succeed before restore or sync.
- On first initialization, if the remote repo already exists, the skill restores remote files to local after creating a local snapshot.
- If the restored remote version is wrong, roll back from `local-backups/<timestamp>/` and sync the corrected local version back to GitHub.


path: README_CN.md
content: **中文版本：**

# soul-undead

一个可发布的 OpenClaw 技能项目，用于通过 GitHub 仓库备份和恢复核心工作区 Markdown 文件。

## 目的

`soul-undead` 管理以下固定核心文件：
- `AGENTS.md`
- `HEARTBEAT.md`
- `IDENTITY.md`
- `SOUL.md`
- `TOOLS.md`
- `USER.md`
- `MEMORY.md`

支持两种主要流程：
1. **将本地核心文件同步到 GitHub**
2. **从 GitHub 恢复到本地工作区**

远程恢复覆盖本地文件前，会自动创建带时间戳的本地快照以确保回滚安全。

## 项目包含文件

- `SKILL.md`
- `scripts/init_or_sync.sh`
- `assets/logic-diagram-zh.png`
- `assets/logic-diagram-en.png`

## 项目不包含文件

以下为运行时产物，不应提交或发布：
- `local-backups/`
- `.workspace-backup-state.json`

安装技能运行时会自动创建。

## 逻辑图

### 中文版
![soul-undead 逻辑图 (ZH)](assets/logic-diagram-zh.png)

## 注意事项

- 默认仓库名为 `soul-undead`。
- 技能依赖 `gh`、`git` 和 `python3`。
- 恢复或同步前必须完成 `gh auth login`。
- 首次初始化时，若远程仓库已存在，则先创建本地快照，再将远程文件恢复到本地。
- 若恢复的远程版本错误，可从 `local-backups/<timestamp>/` 回滚，并将修正后的本地版本同步回 GitHub。


path: scripts/init_or_sync.sh
content: #!/usr/bin/env bash
set -euo pipefail

REPO_NAME="${OPENCLAW_BACKUP_REPO:-soul-undead}"
WORKSPACE_DIR="${OPENCLAW_WORKSPACE:-$HOME/.openclaw/workspace}"
GITHUB_OWNER="${GITHUB_OWNER:-}"
FILES=(AGENTS.md HEARTBEAT.md IDENTITY.md SOUL.md TOOLS.md USER.md MEMORY.md)

need_cmd() {
  command -v "$1" >/dev/null 2>&1 || {
    echo "Missing required command: $1"
    exit 1
  }
}

need_cmd git
need_cmd gh
need_cmd python3

if ! gh auth status >/dev/null 2>&1; then
  echo "GitHub CLI is not authenticated."
  echo "Please run: gh auth login"
  exit 2
fi

if [ -z "$GITHUB_OWNER" ]; then
  GITHUB_OWNER="$(gh api user --jq .login)"
fi

SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
SKILL_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
STATE_FILE="${OPENCLAW_BACKUP_STATE_FILE:-$SKILL_DIR/.workspace-backup-state.json}"
LOCAL_BACKUP_ROOT="$SKILL_DIR/local-backups"
mkdir -p "$WORKSPACE_DIR" "$LOCAL_BACKUP_ROOT"

is_initialized() {
  python3 - <<'PY' "$STATE_FILE"
import json, os, sys
p = sys.argv[1]
if not os.path.exists(p):
    print('false')
    raise SystemExit(0)
try:
    with open(p, 'r', encoding='utf-8') as f:
        data = json.load(f)
    print('true' if data.get('initialized') is True else 'false')
except Exception:
    print('false')
PY
}

write_initialized() {
  mkdir -p "$(dirname "$STATE_FILE")"
  python3 - <<'PY' "$STATE_FILE" "$REPO_NAME"
import json, sys
p, repo = sys.argv[1], sys.argv[2]
with open(p, 'w', encoding='utf-8') as f:
    json.dump({"initialized": True, "repo": repo}, f, ensure_ascii=False, indent=2)
PY
}

repo_exists() {
  gh repo view "$GITHUB_OWNER/$REPO_NAME" >/dev/null 2>&1
}

create_local_snapshot_before_restore() {
  local ts snapshot_dir copied=false
  ts="$(date '+%Y-%m-%d_%H-%M-%S')"
  snapshot_dir="$LOCAL_BACKUP_ROOT/$ts"
  mkdir -p "$snapshot_dir"
  for f in "${FILES[@]}"; do
    if [ -f "$WORKSPACE_DIR/$f" ]; then
      cp "$WORKSPACE_DIR/$f" "$snapshot_dir/$f"
      copied=true
    fi
  done
  if [ "$copied" = true ]; then
    echo "Local pre-restore backup saved to: $snapshot_dir"
  else
    rmdir "$snapshot_dir" 2>/dev/null || true
  fi
}

restore_from_remote() {
  local tmpdir
  tmpdir="$(mktemp -d)"
  trap 'rm -rf "$tmpdir"' RETURN
  create_local_snapshot_before_restore
  git clone "https://github.com/$GITHUB_OWNER/$REPO_NAME.git" "$tmpdir/repo" >/dev/null 2>&1
  for f in "${FILES[@]}"; do
    if [ -f "$tmpdir/repo/$f" ]; then
      cp "$tmpdir/repo/$f" "$WORKSPACE_DIR/$f"
      echo "Restored: $WORKSPACE_DIR/$f"
    fi
  done
}

upsert_remote_file() {
  local file_path="$1"
  local remote_name="${2:-$(basename "$file_path")}"
  local api_path content_b64 response_sha
  api_path="repos/$GITHUB_OWNER/$REPO_NAME/contents/$remote_name"
  content_b64="$(base64 < "$file_path" | tr -d '\n')"
  response_sha="$(gh api "$api_path" --jq '.sha' 2>/dev/null || true)"

  if [ -n "$response_sha" ]; then
    gh api -X PUT "$api_path" \
      -f message="Sync $remote_name from OpenClaw workspace" \
      -f content="$content_b64" \
      -f sha="$response_sha" >/dev/null
  else
    gh api -X PUT "$api_path" \
      -f message="Add $remote_name from OpenClaw workspace" \
      -f content="$content_b64" >/dev/null
  fi
}

sync_workspace_files_to_remote() {
  local changed=false
  local tmpdir restore_path readme_path

  if ! repo_exists; then
    gh repo create "$GITHUB_OWNER/$REPO_NAME" --private --description 'OpenClaw workspace core markdown files' >/dev/null
  fi

  for f in "${FILES[@]}"; do
    if [ -f "$WORKSPACE_DIR/$f" ]; then
      upsert_remote_file "$WORKSPACE_DIR/$f" "$f"
      changed=true
      echo "Synced: $f"
    fi
  done

  tmpdir="$(mktemp -d)"
  trap 'rm -rf "$tmpdir"' RETURN

  restore_path="$tmpdir/restore.sh"
  cat > "$restore_path" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${OPENCLAW_WORKSPACE:-$HOME/.openclaw/workspace}"
SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
mkdir -p "$TARGET_DIR"

for f in AGENTS.md HEARTBEAT.md IDENTITY.md SOUL.md TOOLS.md USER.md MEMORY.md; do
  if [ -f "$SCRIPT_DIR/$f" ]; then
    cp "$SCRIPT_DIR/$f" "$TARGET_DIR/$f"
    echo "Restored: $TARGET_DIR/$f"
  fi
done

echo "Done."
EOF
  upsert_remote_file "$restore_path" "restore.sh"

  readme_path="$tmpdir/README.md"
  cat > "$readme_path" <<'EOF'
# OpenClaw workspace core backup

This repository stores core OpenClaw workspace markdown files for backup and recovery.

## Included files

- AGENTS.md
- HEARTBEAT.md
- IDENTITY.md
- SOUL.md
- TOOLS.md
- USER.md
- MEMORY.md

## Restore

```bash
bash restore.sh
```

By default, files are restored to `~/.openclaw/workspace`.
EOF
  upsert_remote_file "$readme_path" "README.md"

  rm -rf "$tmpdir"
  trap - RETURN

  if [ "$changed" = true ]; then
    echo "Sync complete: https://github.com/$GITHUB_OWNER/$REPO_NAME"
  else
    echo "No tracked files found to sync."
  fi
}

if [ "$(is_initialized)" != "true" ]; then
  if repo_exists; then
    echo "First initialization: remote repo exists, restoring local files first."
    restore_from_remote
    write_initialized
    echo "Initialization complete."
    exit 0
  else
    echo "First initialization: remote repo not found, creating private repo and uploading local files."
    sync_workspace_files_to_remote
    write_initialized
    echo "Initialization complete."
    exit 0
  fi
fi

sync_workspace_files_to_remote


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)