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
21 changes: 15 additions & 6 deletions src/gateway/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ export interface SyncResult {
}

/**
* Sync moltbot config from container to R2 for persistence.
*
* Sync moltbot config and workspace from container to R2 for persistence.
*
* This function:
* 1. Mounts R2 if not already mounted
* 2. Verifies source has critical files (prevents overwriting good backup with empty data)
* 3. Runs rsync to copy config to R2
* 3. Runs rsync to copy config and workspace to R2
* 4. Writes a timestamp file for tracking
*
* Persisted paths:
* - /root/.clawdbot/ → R2/clawdbot/ (config: clawdbot.json, agent settings)
* - /root/clawd/ → R2/clawd/ (workspace: memory, tools, custom files)
* - /root/clawd/skills/ → R2/skills/ (legacy backwards compatibility)
*
* @param sandbox - The sandbox instance
* @param env - Worker environment bindings
Expand Down Expand Up @@ -57,17 +62,21 @@ export async function syncToR2(sandbox: Sandbox, env: MoltbotEnv): Promise<SyncR
};
}

// Run rsync to backup config to R2
// Run rsync to backup config and workspace to R2
// Note: Use --no-times because s3fs doesn't support setting timestamps
const syncCmd = `rsync -r --no-times --delete --exclude='*.lock' --exclude='*.log' --exclude='*.tmp' /root/.clawdbot/ ${R2_MOUNT_PATH}/clawdbot/ && rsync -r --no-times --delete /root/clawd/skills/ ${R2_MOUNT_PATH}/skills/ && date -Iseconds > ${R2_MOUNT_PATH}/.last-sync`;
// Three sync operations:
// 1. /root/.clawdbot/ → R2/clawdbot/ (config)
// 2. /root/clawd/ → R2/clawd/ (full workspace: memory, tools, custom files)
// 3. /root/clawd/skills/ → R2/skills/ (legacy backwards compatibility)
const syncCmd = `rsync -r --no-times --delete --exclude='*.lock' --exclude='*.log' --exclude='*.tmp' /root/.clawdbot/ ${R2_MOUNT_PATH}/clawdbot/ && rsync -r --no-times --delete --exclude='*.lock' --exclude='*.log' --exclude='*.tmp' --exclude='.git' --exclude='node_modules' /root/clawd/ ${R2_MOUNT_PATH}/clawd/ && rsync -r --no-times --delete /root/clawd/skills/ ${R2_MOUNT_PATH}/skills/ && date -Iseconds > ${R2_MOUNT_PATH}/.last-sync`;

try {
const proc = await sandbox.startProcess(syncCmd);
await waitForProcess(proc, 30000); // 30 second timeout for sync

// Check for success by reading the timestamp file
// (process status may not update reliably in sandbox API)
// Note: backup structure is ${R2_MOUNT_PATH}/clawdbot/ and ${R2_MOUNT_PATH}/skills/
// Note: backup structure is ${R2_MOUNT_PATH}/clawdbot/, ${R2_MOUNT_PATH}/clawd/, and ${R2_MOUNT_PATH}/skills/
const timestampProc = await sandbox.startProcess(`cat ${R2_MOUNT_PATH}/.last-sync`);
await waitForProcess(timestampProc, 5000);
const timestampLogs = await timestampProc.getLogs();
Expand Down
20 changes: 17 additions & 3 deletions start-moltbot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,28 @@ else
echo "R2 not mounted, starting fresh"
fi

# Restore skills from R2 backup if available (only if R2 is newer)
# Restore full workspace from R2 backup if available (only if R2 is newer)
# This includes memory, tools, and custom files created by agents
WORKSPACE_DIR="/root/clawd"
if [ -d "$BACKUP_DIR/clawd" ] && [ "$(ls -A $BACKUP_DIR/clawd 2>/dev/null)" ]; then
if should_restore_from_r2; then
echo "Restoring full workspace from $BACKUP_DIR/clawd..."
mkdir -p "$WORKSPACE_DIR"
cp -a "$BACKUP_DIR/clawd/." "$WORKSPACE_DIR/"
echo "Restored workspace from R2 backup"
fi
fi

# Restore skills from R2 backup if available (legacy path, backwards compatibility)
# Note: skills are now included in the full workspace backup above, but we keep this
# for backwards compatibility with existing R2 backups that only have skills/
SKILLS_DIR="/root/clawd/skills"
if [ -d "$BACKUP_DIR/skills" ] && [ "$(ls -A $BACKUP_DIR/skills 2>/dev/null)" ]; then
if should_restore_from_r2; then
echo "Restoring skills from $BACKUP_DIR/skills..."
echo "Restoring skills from legacy path $BACKUP_DIR/skills..."
mkdir -p "$SKILLS_DIR"
cp -a "$BACKUP_DIR/skills/." "$SKILLS_DIR/"
echo "Restored skills from R2 backup"
echo "Restored skills from R2 backup (legacy)"
fi
fi

Expand Down