Skill: reed1898/claw-roam (version 1.0.3)

--- name: claw-roam description: Sync OpenClaw workspace between multiple machines (local Mac and remote VPS) via Git. Enables seamless migration of OpenClaw personality, memory, and skills. Use when user wants to (1) push workspace changes to remote before shutdown, (2) pull latest workspace on a new machine, (3) check sync status between machines, (4) migrate OpenClaw to another machine. --- # Claw Roam - OpenClaw Workspace Sync Sync your OpenClaw workspace across machines via Git. This allows you to: - Work on local Mac as primary, seamlessly switch to VPS when traveling - Maintain continuous memory and personality across different machines - Backup your OpenClaw state to remote Git repository ## Quick Start Recommended branch model for multi-device: - `main` = shared baseline - `remote` = this server - `local` = your laptop/desktop ```bash # Check status (current branch) claw-roam status # One-command full sync (recommended) claw-roam sync # Or step by step: # Commit+push current branch claw-roam push "msg" # Pull latest for current branch claw-roam pull # (Optional) merge another device branch into current branch claw-roam merge-from local claw-roam merge-from remote ``` ## Commands ### push Commit and push workspace to remote Git repository. ```bash claw-roam push [message] ``` - If no message provided, uses timestamp as default - Automatically adds all changes (git add -A) - Skips push if no changes detected ### pull Pull latest workspace from remote and sync. ```bash claw-roam pull ``` - Fetches latest changes from remote - Applies changes to current workspace - Stops and restarts OpenClaw gateway to apply changes (VPS mode) ### status Check sync status between local and remote. ```bash claw-roam status ``` - Shows current branch and commit - Shows unpushed commits (if any) - Shows uncommitted changes - Suggests next action ### sync (One-Command Full Sync) ```bash claw-roam sync ``` Performs the complete sync workflow in one command: 1. **Commit and push current branch** - Saves your local changes 2. **Merge main into current branch** - Gets latest from shared main 3. **Push to main branch** - Shares your changes with other machines **Workflow diagram:** ``` ┌─────────────┐ commit+push ┌─────────────┐ │ local │ ───────────────────▶│ origin/local│ │ 分支 │ │ │ └──────┬──────┘ └─────────────┘ │ │ merge main ▼ ┌─────────────┐ merge+push ┌─────────────┐ │ local │ ───────────────────▶│ main │ │ 分支 │ │ (shared) │ └─────────────┘ └──────┬──────┘ │ ┌──────────────────────┘ │ pull ▼ ┌─────────────┐ │ remote │ │ 分支 │ └─────────────┘ ``` **Recommended daily workflow:** ```bash # On each machine, just run: claw-roam sync ``` This ensures: - Your changes are saved to your branch - You get latest changes from other machines (via main) - Other machines can get your changes (via main) ## Setup 1. **Initialize Git repo in workspace** (if not already done): ```bash cd ~/.openclaw/workspace git init git remote add origin <your-repo-url> ``` 2. **Create initial commit**: ```bash git add -A git commit -m "initial" git push -u origin main ``` 3. **On VPS machine** - clone the repo: ```bash cd ~ git clone <your-repo-url> openclaw-workspace ln -s openclaw-workspace ~/.openclaw/workspace ``` ## Branch Workflow (Recommended) For multiple machines, use this branch strategy: ``` local (Mac) ──┐ ├──► main (shared) ◄── merge & push remote (VPS) ─┘ ``` ### Setup Each Machine **Local Mac:** ```bash cd ~/.openclaw/workspace git checkout -b local git push -u origin local ``` **Remote VPS:** ```bash cd ~/.openclaw/workspace git checkout -b remote git push -u origin remote ``` ### Daily Workflow **On each machine:** 1. **Get latest from main** (获取其他机器的最新内容): ```bash claw-roam merge-from main ``` 2. **Work normally**, then push your changes: ```bash claw-roam push "update memory" ``` 3. **Share to main** (让其他机器能获取): ```bash git checkout main git merge local -m "merge: local -> main" git push origin main git checkout local ``` ### Quick Sync (One-liner) ```bash # Pull from main, then push to main claw-roam merge-from main && git checkout main && git merge local && git push && git checkout local ``` ### Conflict Resolution If `merge-from main` has conflicts: ```bash # Keep your version git checkout --ours <conflicted-file> git add -A && git commit -m "merge: resolved conflicts" # Or keep main's version git checkout --theirs <conflicted-file> git add -A && git commit -m "merge: resolved conflicts" ``` ## Simple Workflow: Local Primary + VPS Backup For simpler setups without branches: ### Daily Usage (Local Mac) Just use OpenClaw normally. Before shutdown: ```bash claw-roam push "end of day sync" ``` Or let it auto-push via cron: ```bash # Add to crontab */10 * * * * cd ~/.openclaw/workspace && git add -A && git commit -m "auto: $(date)" && git push ``` ### Switching to VPS 1. Ensure local has pushed: `claw-roam push` 2. On VPS: `claw-roam pull` 3. Update Telegram webhook to point to VPS (if using webhook mode) 4. Continue using alternative bot token on VPS ### Returning to Local 1. On VPS: `claw-roam push` 2. On local: `claw-roam pull` 3. Update Telegram webhook back to local (if needed) ## What Gets Synced **Synced (preserved across machines):** - `SOUL.md` - Your agent's personality - `MEMORY.md` - Long-term memory - `memory/*.md` - Daily conversation logs - `skills/` - All installed skills - `AGENTS.md`, `USER.md` - Context files - `TOOLS.md` - Device configurations - `HEARTBEAT.md` - Periodic tasks **Not Synced (machine-specific):** - Session database (SQLite) - But this is rebuilt from memory files - Gateway runtime state - Platform-specific paths in configs ## Troubleshooting ### "Repository not found" Run setup steps above to initialize Git repository. ### "Merge conflicts" If you edited on both machines without syncing: ```bash # On the machine with changes you want to keep git pull --strategy=ours git push ``` ### "Permission denied" Ensure your Git remote is configured with proper authentication (SSH key or token). ## Scripts Use bundled scripts directly: ```bash ~/.openclaw/workspace/skills/claw-roam/scripts/claw-roam.sh push ~/.openclaw/workspace/skills/claw-roam/scripts/claw-roam.sh pull ~/.openclaw/workspace/skills/claw-roam/scripts/claw-roam.sh status ```

path: _meta.json
content: ownerId: kn79dwsk2915p6nkctkd21mv7580md2r
slug: claw-roam
version: 1.0.1
publishedAt: 1770393455279

path: scripts/claw-roam.sh
content: #!/bin/bash

# claw-roam - OpenClaw Workspace Sync Tool
# Usage: claw-roam [push|pull|status|merge-from|sync] [options]

set -e

WORKSPACE_DIR="${HOME}/.openclaw/workspace"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

cd "$WORKSPACE_DIR"

show_help() {
    cat << EOF
Claw Roam - Sync OpenClaw workspace between machines

Usage:
    claw-roam push [message]         Commit+push current branch
    claw-roam pull                   Pull latest for current branch
    claw-roam status                 Check sync status
    claw-roam merge-from <branch>    Merge another branch into current branch
    claw-roam sync                   Full sync: push local, merge main, push to main
    claw-roam help                   Show this help

Examples:
    claw-roam push "before travel"
    claw-roam pull
    claw-roam status
    claw-roam merge-from local
    claw-roam sync
EOF
}

cmd_push() {
    local message="${1:-auto: $(date '+%Y-%m-%d %H:%M:%S')}"
    
    # Check if git repo exists
    if [ ! -d ".git" ]; then
        echo "❌ Not a git repository. Run 'git init' first."
        exit 1
    fi
    
    # Check if there are changes
    if [ -z "$(git status --porcelain)" ]; then
        echo "✅ No changes to push (already up to date)"
        git log -1 --oneline
        exit 0
    fi
    
    echo "📦 Adding changes..."
    git add -A
    
    echo "💾 Committing: $message"
    git commit -m "$message"
    
    echo "🚀 Pushing to remote..."
    git push
    
    echo "✅ Push complete!"
    git log -1 --oneline
}

cmd_pull() {
    # Check if git repo exists
    if [ ! -d ".git" ]; then
        echo "❌ Not a git repository. Run 'git init' first."
        exit 1
    fi
    
    echo "📥 Fetching from remote..."
    git fetch origin
    
    local local_commit=$(git rev-parse HEAD)
    local remote_commit=$(git rev-parse origin/$(git branch --show-current))
    
    if [ "$local_commit" = "$remote_commit" ]; then
        echo "✅ Already up to date"
        git log -1 --oneline
        exit 0
    fi
    
    echo "🔄 Pulling changes..."
    git pull origin $(git branch --show-current)
    
    echo "✅ Pull complete!"
    git log -1 --oneline
    
    # If on VPS, suggest restarting gateway
    if [ -n "$OPENCLAW_VPS" ] || [ -f "/etc/openclaw/vps" ]; then
        echo ""
        echo "💡 VPS detected. Restart OpenClaw gateway to apply changes:"
        echo "   openclaw gateway restart"
    fi
}

cmd_merge_from() {
    local from_branch="${1:-}"
    [ -n "$from_branch" ] || { echo "❌ missing branch name"; echo "   usage: claw-roam merge-from <branch>"; exit 1; }

    if [ ! -d ".git" ]; then
        echo "❌ Not a git repository."
        exit 1
    fi

    local cur_branch
    cur_branch=$(git branch --show-current)
    echo "🔀 Merging from: $from_branch -> $cur_branch"

    echo "📥 Fetching..."
    git fetch origin --prune

    echo "🔧 Merge..."
    git merge "origin/${from_branch}" -m "merge: ${from_branch} -> ${cur_branch}" || {
      echo "❌ Merge failed (likely conflicts). Resolve them, then run:"
      echo "   git status"
      echo "   git add -A && git commit"
      exit 1
    }

    echo "✅ Merge complete."
    git log -1 --oneline
}

cmd_status() {
    # Check if git repo exists
    if [ ! -d ".git" ]; then
        echo "❌ Not a git repository"
        echo ""
        echo "Setup steps:"
        echo "   cd ~/.openclaw/workspace"
        echo "   git init"
        echo "   git remote add origin <your-repo-url>"
        echo "   git add -A && git commit -m 'initial' && git push -u origin main"
        exit 1
    fi

    echo "📍 Current branch: $(git branch --show-current)"
    echo "🔖 Latest commit:  $(git log -1 --oneline)"
    echo ""

    # Check for unpushed commits
    local unpushed=$(git log --branches --not --remotes --oneline 2>/dev/null || echo "")
    if [ -n "$unpushed" ]; then
        echo "⚠️  Unpushed commits:"
        echo "$unpushed" | head -5
        local count=$(echo "$unpushed" | wc -l | tr -d ' ')
        [ "$count" -gt 5 ] && echo "   ... and $((count - 5)) more"
        echo ""
        echo "💡 Run: claw-roam push"
    else
        echo "✅ All commits pushed"
    fi

    # Check for uncommitted changes
    if [ -n "$(git status --porcelain)" ]; then
        echo ""
        echo "📝 Uncommitted changes:"
        git status --short
        echo ""
        echo "💡 Run: claw-roam push"
    else
        echo "✅ No uncommitted changes"
    fi

    # Check remote status
    git fetch origin --quiet 2>/dev/null || true
    local behind=$(git rev-list --count HEAD..origin/$(git branch --show-current) 2>/dev/null || echo "0")
    if [ "$behind" -gt 0 ]; then
        echo ""
        echo "🔄 Remote is $behind commit(s) ahead"
        echo "💡 Run: claw-roam pull"
    fi
}

cmd_sync() {
    local current_branch
    current_branch=$(git branch --show-current)
    
    echo "🔄 Full sync workflow: $current_branch -> main"
    echo ""
    
    # Step 1: Commit and push current branch
    echo "Step 1: Commit and push current branch ($current_branch)"
    if [ -n "$(git status --porcelain)" ]; then
        git add -A
        git commit -m "sync: auto-commit on $current_branch"
        echo "✅ Committed changes"
    else
        echo "ℹ️ No changes to commit"
    fi
    
    echo "🚀 Pushing $current_branch..."
    git push origin "$current_branch"
    echo "✅ Pushed $current_branch"
    echo ""
    
    # Step 2: Merge main into current branch
    echo "Step 2: Merge main into $current_branch"
    git fetch origin main
    if git merge-base --is-ancestor origin/main HEAD; then
        echo "ℹ️ Already up to date with main"
    else
        git merge origin/main -m "sync: merge main -> $current_branch" || {
            echo "❌ Merge failed. Resolve conflicts and run: git add -A && git commit"
            exit 1
        }
        echo "✅ Merged main into $current_branch"
    fi
    echo ""
    
    # Step 3: Merge current branch into main and push
    echo "Step 3: Push to main branch"
    git fetch origin main
    local main_branch="main"
    
    # Check if main exists locally
    if ! git show-ref --verify --quiet refs/heads/main; then
        # Check if master exists
        if git show-ref --verify --quiet refs/heads/master; then
            main_branch="master"
        else
            git checkout -b main origin/main
            main_branch="main"
        fi
    fi
    
    # Stash any uncommitted changes before switching
    local had_stash=false
    if [ -n "$(git status --porcelain)" ]; then
        git stash push -m "sync-stash"
        had_stash=true
    fi
    
    git checkout "$main_branch"
    
    # Pull latest main first
    git pull origin "$main_branch" || true
    
    # Merge current branch
    git merge "$current_branch" -m "sync: merge $current_branch -> main"
    
    # Push main
    git push origin "$main_branch"
    echo "✅ Pushed to main"
    
    # Switch back to original branch
    git checkout "$current_branch"
    
    # Restore stash if we had one
    if [ "$had_stash" = true ]; then
        git stash pop || true
    fi
    
    echo ""
    echo "🎉 Sync complete!"
    echo "   $current_branch: $(git log -1 --oneline)"
    echo "   main: $(git log origin/main -1 --oneline)"
}

# Main
case "${1:-help}" in
    push)
        shift
        cmd_push "$@"
        ;;
    pull)
        cmd_pull
        ;;
    status)
        cmd_status
        ;;
    merge-from)
        shift
        cmd_merge_from "$@"
        ;;
    sync)
        cmd_sync
        ;;
    help|--help|-h)
        show_help
        ;;
    *)
        echo "Unknown command: $1"
        show_help
        exit 1
        ;;
esac


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