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.jsonhas 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.jsoncontains 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 -10in 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.jsoninstead 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
.gitignoreexists - Private GitHub repo created: https://github.com/Mauronic/firstascent-claw
- No
ghCLI 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
.gitignoreexcludingnode_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
ghCLI - 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:
- 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. - 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. - 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.
| Trigger | Message Format | Example |
|---|---|---|
| Cron | auto: <changed files list> | auto: tasks.json, memory/2026-04-03.md |
| Task done | done: <displayId> <title> | done: JAM-18 Workspace Backup & Version Control |
| Manual | <user message> | restored tasks.json after data wipe |
| Memory flush | memory: 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.jsonmust 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:
- ✅ GitHub account (Mauronic)
- ✅ Private repo created: https://github.com/Mauronic/firstascent-claw
Total remaining Pete time: ~7 minutes.
10. Implementation Scope
David builds:
.gitignoreat~/.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.
- Git setup script (
workspace/scripts/git-init.sh):
- Remove any existing
.gitfromworkspace/(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
- 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
--messageif provided, otherwiseauto: <file1>, <file2>, ...(cap at 5 files, append(+N more)) git commit -m "<message>"thengit push- Log success/failure to stdout (captured by cron)
- OpenClaw cron job: Run
workspace-commit.shevery 30 minutes
- 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 -5shows commits with descriptive messages (not bare timestamps)git remote -vshows the private GitHub repo- Repo root is
~/.openclaw/, not~/.openclaw/workspace/ openclaw.jsonIS in the repo (config backup)client_secret.jsonis NOT in the repo (.gitignoreworking)agents/,media/,node_modules/,.next/are NOT in the repoworkspace-builder/IS in the repo (David's workspace)cron/jobs.jsonIS 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 showgit@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, anynode_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 beauto: 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 -1within 30 seconds — message should bedone: 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 betesting 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
.gitignoremust 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.gitignoreis 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 logand 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