Mission Control

Artifacts

K
← Back to artifactsOpen JAM-18

Workspace Backup & Version Control

SpecDraftJAM-18Created Apr 3, 2026Updated Apr 4, 202611 min readFull screen ↗

Workspace Backup & Version Control

Exec Summary

Git-based version control for the entire ~/.openclaw/ directory with automated commits and a private GitHub remote. Three commit triggers: (1) cron every 30 minutes, (2) event-driven on task completion, (3) manual "commit workspace" chat command. All commits get descriptive messages, not just timestamps. David builds the scripts; Pete handles a short setup checklist (SSH key addition to GitHub). Private repo already created at https://github.com/Mauronic/firstascent-claw.

1. Problem Statement and Goal

The entire ~/.openclaw/ directory has no version control or off-machine backup. This has caused real pain:

  • Data wipes from code bugs: tasks.json has been wiped to [] three times by build-time validation failures. Each recovery required manual reconstruction from conversation context.
  • No rollback: When a subagent overwrites a file incorrectly, there's no way to recover the previous version.
  • No audit trail: No history of who changed what or when. Agent edits, manual edits, and build artifacts blend together.
  • Single point of failure: All state (config, cron jobs, workspace, skills, memory, tasks, David's workspace) lives on one Mac mini with no off-box copy beyond Time Machine.
  • Config loss risk: openclaw.json contains the entire agent architecture (bindings, hooks, channel config, model routing). Recreating it from scratch would take hours.

Goal: Every meaningful change across the entire OpenClaw installation is version-controlled and recoverable. A private GitHub repo serves as the off-machine backup. Recovery from any bad write is a single git checkout or git revert.

2. Success Metric

  • Pete can run git log --oneline -10 in the workspace and see recent changes with timestamps
  • Pete can recover any file to a previous state with git checkout HEAD~N -- path/to/file
  • The GitHub remote has a current copy of the workspace (pushed within the last hour during active use)
  • The next time a data wipe happens, recovery is git checkout HEAD~1 -- mission-control/data/tasks.json instead of a 30-minute manual reconstruction

3. Current State

  • Backup scope: ~/.openclaw/ (entire OpenClaw installation)
  • Git is initialized in ~/.openclaw/workspace/ but has zero commits. No git init at the ~/.openclaw/ level.
  • No .gitignore exists
  • Private GitHub repo created: https://github.com/Mauronic/firstascent-claw
  • No gh CLI installed
  • No git global user config set
  • workspace/mission-control/node_modules/ is 517MB (must be excluded)
  • workspace/mission-control/.next/ is 12MB (build output, should be excluded)
  • workspace/emt-study/ is 61MB (study materials, should be included but is large)
  • agents/ contains session data (ephemeral, exclude)
  • media/ contains inbound/outbound attachments (large, transient, exclude)
  • Critical config files: openclaw.json (agent config, API keys inline), cron/jobs.json (cron definitions)
  • Critical data files: workspace/mission-control/data/tasks.json, workspace/memory/*.md, workspace/MEMORY.md, workspace/artifacts/*.md, workspace/skills/*/data/*.json
  • David's workspace: workspace-builder/ (should be included)

4. Platform Capabilities

OpenClaw has no built-in workspace backup feature. This is entirely custom infrastructure.

OpenClaw does have:

  • Cron jobs that can run shell scripts on a schedule
  • Heartbeat tasks (HEARTBEAT.md) that can trigger periodic checks
  • Subagent spawning for running maintenance scripts

Git and GitHub are standard tools available on macOS. gh CLI can be installed via Homebrew.

5. Community Patterns

Git-based workspace backup is the standard approach in the OpenClaw community. Most setups use:

  • A private GitHub/GitLab repo for the workspace directory
  • .gitignore excluding node_modules, build output, and secrets
  • Either manual commits or a cron-based auto-commit script
  • Some users use git-auto-commit patterns

No dedicated OpenClaw skill or plugin exists for this.

6. Options

Option A: Git + GitHub with Cron Auto-Commit

  • Initialize git properly, create .gitignore, make first commit
  • Create a private GitHub repo via gh CLI
  • Write a shell script that runs git add -A && git commit -m "auto: <timestamp>" && git push
  • Trigger via OpenClaw cron job every 30 minutes
  • Skip commit if nothing changed (git handles this gracefully)

Pros: Simple, standard, uses tools Pete already knows. Full history. Off-machine backup. Cons: 30-minute granularity means up to 30 min of work could be lost between commits. Auto-commit messages aren't descriptive. Complexity: Low. ~2 hours to build. Maintenance: Near zero.

Option B: Git + GitHub with Event-Driven Commits

Same as A, but also commit after specific events:

  • After every subagent task completion
  • After every task status change
  • After memory flushes

Pros: Finer granularity, commits tied to meaningful events. Cons: More integration points, more complexity, commits on every minor change could be noisy. Complexity: Medium. Additional hooks in AGENTS.md workflows. Maintenance: Low-medium. New workflows need to remember to commit.

Option C: Git + GitHub with Cron + Manual Commit Commands

Option A plus a chat command: "commit workspace" or "save workspace" triggers an immediate commit with a descriptive message.

Pros: Best of both worlds. Auto-commit catches everything, manual commit lets Pete mark important states. Cons: Slightly more to build (chat command handler). Complexity: Low-medium. Maintenance: Near zero.

7. Recommendation

Option C + event-driven commits on task completion.

Three commit triggers, each with descriptive messages:

  1. Cron (every 30 min): Catches everything. Message format: auto: changed files summary (e.g. auto: tasks.json, memory/2026-04-03.md, artifacts/spec_workspace_backup.md). Lists the actual filenames that changed, not just a timestamp.
  2. Event-driven (task moved to Done): Commits immediately when any task reaches Done status. Message format: done: JAM-18 Workspace Backup & Version Control. Tied to the AGENTS.md lifecycle workflow so it fires automatically.
  3. Manual ("commit workspace: <message>"): Pete or Vinny triggers in chat with a descriptive message. Message format: whatever was typed (e.g. commit workspace: restored tasks.json after data wipe).

The auto-commit script is idempotent: if nothing changed, it does nothing. If the push fails (network issue), it logs the failure and retries next cycle.

Commit message strategy

Every commit gets a meaningful message. No bare timestamps.

TriggerMessage FormatExample
Cronauto: <changed files list>auto: tasks.json, memory/2026-04-03.md
Task donedone: <displayId> <title>done: JAM-18 Workspace Backup & Version Control
Manual<user message>restored tasks.json after data wipe
Memory flushmemory: flush to <filename>memory: flush to memory/2026-04-03.md

The cron script generates the file list by running git diff --name-only before committing. If more than 5 files changed, it lists the first 5 and appends (+N more).

8. Security Considerations

  • API keys in openclaw.json: The config file contains inline API keys (Anthropic, Groq, Brave, Google, DeepSeek). Pete accepts this risk for a private repo with sole access. The repo MUST remain private.
  • Google OAuth secret: workspace/client_secret.json must be in .gitignore.
  • Private repo: Already created as private. The init script should verify private status before first push.
  • SSH vs HTTPS: SSH keys are more secure and don't require storing a token in a file. Prefer SSH auth.
  • Failure mode: If push fails, local commits still exist. Data is safe locally; only the off-machine backup is delayed. The cron job should log failures to cron-status.
  • Large files: emt-study/ at 61MB may hit GitHub's soft limits over time. Consider .gitignore-ing binary files within it if any exist, or using Git LFS if needed later.

9. Pete's Setup Checklist

Most setup is already done or will be automated by David. Pete's remaining steps:

Step 1: Add SSH public key to GitHub ✅ ~3 min

  • Who: Pete
  • What: David generates an SSH keypair on the Mac mini. Pete copies the public key and adds it at GitHub > Settings > SSH Keys.
  • Why SSH over HTTPS: No token storage, more secure, never expires.

Step 2: Review .gitignore before first commit ✅ ~2 min

  • Who: Pete (quick review)
  • What: David generates the .gitignore. Pete eyeballs it to confirm nothing sensitive is missing and nothing important is excluded.

Step 3: Approve first push ✅ ~2 min

  • Who: Pete
  • What: After initial commit, Pete confirms the repo contents look right on GitHub before automated pushes begin.

Already done:

Total remaining Pete time: ~7 minutes.

10. Implementation Scope

David builds:

  1. .gitignore at ~/.openclaw/ root:

```

Ephemeral / large

agents/ media/ workspace/mission-control/node_modules/ workspace/mission-control/.next/ workspace/tmp/ workspace-builder/node_modules/ workspace-builder/.next/

Secrets

workspace/client_secret.json

OS / build

.DS_Store *.pyc __pycache__/ *.log .env .env.* ```

Note: openclaw.json is intentionally NOT excluded. It contains API keys but Pete accepts this risk for a private repo. The config is critical for disaster recovery.

  1. Git setup script (workspace/scripts/git-init.sh):
  • Remove any existing .git from workspace/ (stale, zero commits)
  • Initialize git at ~/.openclaw/ level
  • Set git user.name and user.email (use "Vinny" / vinnytheaiassistant@gmail.com)
  • Generate SSH keypair if not present, output public key for Pete to add to GitHub
  • Add remote origin: git@github.com:Mauronic/firstascent-claw.git
  • Make initial commit, push
  1. Auto-commit script (workspace/scripts/workspace-commit.sh):
  • Accept optional --message "custom message" argument
  • cd ~/.openclaw && git add -A
  • Generate changed file list via git diff --cached --name-only
  • If no changes: exit silently
  • Build commit message: use --message if provided, otherwise auto: <file1>, <file2>, ... (cap at 5 files, append (+N more))
  • git commit -m "<message>" then git push
  • Log success/failure to stdout (captured by cron)
  1. OpenClaw cron job: Run workspace-commit.sh every 30 minutes
  1. AGENTS.md updates:
  • Add "commit workspace: <message>" / "save workspace: <message>" chat command that runs workspace-commit.sh --message "<message>"
  • Add to the "move task to done" workflow: after status update, run workspace-commit.sh --message "done: <displayId> <title>"
  • Add to the memory flush workflow: after writing daily notes, run workspace-commit.sh --message "memory: flush to <filename>"

11. Validation Criteria

  • git log --oneline -5 shows commits with descriptive messages (not bare timestamps)
  • git remote -v shows the private GitHub repo
  • Repo root is ~/.openclaw/, not ~/.openclaw/workspace/
  • openclaw.json IS in the repo (config backup)
  • client_secret.json is NOT in the repo (.gitignore working)
  • agents/, media/, node_modules/, .next/ are NOT in the repo
  • workspace-builder/ IS in the repo (David's workspace)
  • cron/jobs.json IS in the repo (cron definitions)

12. Test Plan

Run these tests in order after David completes the build. Each test has a pass/fail criterion.

Test 1: Initial state verification

  • Run cd ~/.openclaw && git status — should show clean working tree
  • Run git remote -v — should show git@github.com:Mauronic/firstascent-claw.git
  • Run git log --oneline -1 — should show initial commit
  • Visit https://github.com/Mauronic/firstascent-claw — should show files, repo should be private
  • Pass: All four checks pass

Test 2: .gitignore validation

  • On GitHub, verify these ARE present: openclaw.json, cron/, workspace/MEMORY.md, workspace/artifacts/, workspace-builder/
  • On GitHub, verify these are NOT present: agents/, media/, workspace/client_secret.json, any node_modules/, any .next/
  • Pass: All inclusions and exclusions correct

Test 3: Cron auto-commit

  • Edit a file: echo "test" >> ~/.openclaw/workspace/memory/test-backup.md
  • Wait 30 minutes (or trigger cron manually)
  • Run git log --oneline -1 — message should be auto: workspace/memory/test-backup.md
  • Check GitHub for the new commit
  • Clean up: rm ~/.openclaw/workspace/memory/test-backup.md
  • Pass: Commit appears locally and on GitHub with correct auto message

Test 4: Task-done event commit

  • In chat: "move test-backup to done" (or move any test task)
  • Run git log --oneline -1 within 30 seconds — message should be done: JAM-XX <title>
  • Pass: Immediate commit with done message format

Test 5: Manual commit command

  • In chat: "commit workspace: testing manual checkpoint"
  • Run git log --oneline -1 — message should be testing manual checkpoint
  • Pass: Immediate commit with user-provided message

Test 6: Recovery test (critical)

  • Note current content of workspace/mission-control/data/tasks.json
  • Corrupt it: echo "[]" > ~/.openclaw/workspace/mission-control/data/tasks.json
  • Recover: cd ~/.openclaw && git checkout HEAD~1 -- workspace/mission-control/data/tasks.json
  • Verify file contents match the original
  • Pass: File recovered with correct content

Test 7: Config recovery test

  • Run git show HEAD:openclaw.json | head -5 — should show valid JSON config
  • Pass: Config file is recoverable from git history

Test 8: Push failure resilience

  • Temporarily break SSH (rename key): mv ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.bak
  • Trigger a commit (edit a file, wait for cron or run manual)
  • Verify local commit exists: git log --oneline -1
  • Restore SSH: mv ~/.ssh/id_ed25519.bak ~/.ssh/id_ed25519
  • Wait for next cron cycle, verify push succeeds
  • Pass: Local commit preserved, push retried and succeeds

12. Category

Tool - new infrastructure capability (version control + backup)

13. Context Loading

  • Build time: David reads this spec + scripts/ directory structure
  • Runtime (cron): The commit script reads nothing; it just runs git commands in the workspace directory
  • Runtime (chat command): AGENTS.md contains the "commit workspace" trigger pattern. No additional context files needed.

14. Guardrails

  • Never commit or push secrets (API keys, tokens, client secrets). The .gitignore must cover these.
  • Never force-push. History must be preserved.
  • Never auto-resolve merge conflicts. If a conflict occurs (shouldn't with single-machine use), log it and alert Pete.
  • The cron job must not block other cron jobs. Keep execution under 30 seconds.
  • Do not commit node_modules/ or build output. The .gitignore is the first thing to validate.
  • Do not create the GitHub repo as public. Verify private status before first push.

15. Handoff

  • David creates the files, runs the init script, verifies the first commit + push
  • Vinny verifies by running git log and checking the GitHub repo
  • Vinny updates JAM-18 status to needs-review with a link to the GitHub repo
  • Pete verifies by checking the repo in his browser and running a recovery test