LaunchAgent Migration Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Consolidate scattered LaunchAgent/cron automation into a single, maintainable system with clear ownership, deduplication, and missing scheduled jobs added.
Architecture: All scripts live in business-builder/scripts/ (canonical source). LaunchAgents reference those scripts directly. OpenClaw workspace copies are eliminated as duplicates. Missing scheduled automation (OKR scheduler, Turso backup) gets new LaunchAgents.
Tech Stack: macOS LaunchAgents (plist), bash scripts, git
Current State Analysis
LaunchAgent Inventory (~/Library/LaunchAgents/)
| # | File | Label | Purpose | Schedule | Status |
|---|---|---|---|---|---|
| 1 | ai.openclaw.gateway.plist | ai.openclaw.gateway | OpenClaw Gateway (v2026.2.23) — VP communication layer | RunAtLoad + KeepAlive (always running) | Active (PID 8770) |
| 2 | com.macclaw.jarvis-limit-check.plist | com.macclaw.jarvis-limit-check | Monitors tmux vice-claude session for Claude usage limits | Every 300s (5 min) | Active |
| 3 | com.macclaw.daily-git-push.plist | com.macclaw.daily-git-push | Daily auto-backup: sync core files + git push | 12:00 + 23:50 KST | Active |
Crontab
| Schedule | Script | Purpose |
|---|---|---|
*/30 * * * * | /Users/nbs22/ObsidianVault/.scripts/auto-sync.sh | Obsidian vault git auto-sync |
Script Duplication Problem
Scripts exist in two locations with varying degrees of drift:
| Script | OpenClaw (~/.openclaw/workspace/scripts/) | Business-Builder (scripts/) | Drift? |
|---|---|---|---|
check-jarvis-limit.sh | Yes | Yes | Identical |
telegram-reply.sh | Yes | Yes | Identical |
vp_prompt_inject.sh | Yes (HTTP API version) | Yes (tmux direct version) | DIVERGED |
daily-git-push.sh | Yes | No | OpenClaw-only |
start-vice-claude.sh | Yes | No | OpenClaw-only |
okr-weekly-review.sh | Yes | No | OpenClaw-only |
vice-reply.sh | No | Yes | BB-only |
ceo-reply.sh | No | Yes | BB-only |
report.sh | No | Yes | BB-only (= vice-reply.sh duplicate) |
scheduler-report.sh | No | Yes | BB-only |
okr-scheduler.sh | No | Yes | BB-only |
backup-turso.sh | No | Yes | BB-only |
LaunchAgent Issues
- Both LaunchAgents point to OpenClaw scripts (
~/.openclaw/workspace/scripts/) instead of the git-tracked canonical source (business-builder/scripts/). If OpenClaw workspace is reset or changed, automation breaks. - Script duplication: 3 scripts exist in both locations.
vp_prompt_inject.shhas diverged. - Missing LaunchAgents: Several scripts have no automated schedule:
okr-scheduler.sh— comment says "6 hours" but no LaunchAgent existsbackup-turso.sh— no scheduled backupokr-weekly-review.sh— comment says "Monday 09:00" but no LaunchAgent
report.shandvice-reply.share identical —report.shis the old name,vice-reply.shis the current canonical name (per MEMORY.md).report.shshould be a symlink or removed.scheduler-report.shuses Turso HTTP API directly whilevice-reply.shuses@libsql/clientvia Node.js — inconsistent DB access pattern.
Migration Tasks
Task 1: Consolidate script canonical location to business-builder
Files:
- Move:
~/.openclaw/workspace/scripts/daily-git-push.sh->scripts/daily-git-push.sh - Move:
~/.openclaw/workspace/scripts/start-vice-claude.sh->scripts/start-vice-claude.sh - Move:
~/.openclaw/workspace/scripts/okr-weekly-review.sh->scripts/okr-weekly-review.sh - Delete from OpenClaw:
check-jarvis-limit.sh,telegram-reply.sh(duplicates) - Keep in OpenClaw:
vp_prompt_inject.sh(OpenClaw-specific HTTP API version)
Step 1: Copy OpenClaw-only scripts to business-builder
BB="/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts"
OC="/Users/nbs22/.openclaw/workspace/scripts"
cp "$OC/daily-git-push.sh" "$BB/daily-git-push.sh"
cp "$OC/start-vice-claude.sh" "$BB/start-vice-claude.sh"
cp "$OC/okr-weekly-review.sh" "$BB/okr-weekly-review.sh"
chmod +x "$BB/daily-git-push.sh" "$BB/start-vice-claude.sh" "$BB/okr-weekly-review.sh"
Step 2: Update daily-git-push.sh paths
The script already uses $HOME/.openclaw/workspace and $BB variables correctly. No path changes needed inside the script.
Step 3: Remove duplicates from OpenClaw
OC="/Users/nbs22/.openclaw/workspace/scripts"
rm "$OC/check-jarvis-limit.sh"
rm "$OC/telegram-reply.sh"
Keep vp_prompt_inject.sh in OpenClaw (HTTP API version used by VP directly).
Step 4: Commit
cd "/Users/nbs22/(Claude)/(claude).projects/business-builder"
git add scripts/daily-git-push.sh scripts/start-vice-claude.sh scripts/okr-weekly-review.sh
git commit -m "chore: consolidate scripts from openclaw to business-builder canonical location"
Task 2: Remove report.sh duplicate (alias of vice-reply.sh)
Files:
- Delete:
scripts/report.sh - Create symlink:
scripts/report.sh->scripts/vice-reply.sh
Step 1: Verify report.sh and vice-reply.sh are identical
diff scripts/report.sh scripts/vice-reply.sh
Expected: identical (they are).
Step 2: Replace report.sh with symlink
cd "/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts"
rm report.sh
ln -s vice-reply.sh report.sh
This maintains backward compatibility for any script calling report.sh.
Step 3: Commit
cd "/Users/nbs22/(Claude)/(claude).projects/business-builder"
git add scripts/report.sh
git commit -m "chore: replace report.sh with symlink to vice-reply.sh (deduplicate)"
Task 3: Migrate LaunchAgent plist paths to business-builder
Files:
- Modify:
~/Library/LaunchAgents/com.macclaw.jarvis-limit-check.plist - Modify:
~/Library/LaunchAgents/com.macclaw.daily-git-push.plist
Step 1: Update jarvis-limit-check.plist
Change ProgramArguments from:
/Users/nbs22/.openclaw/workspace/scripts/check-jarvis-limit.sh
To:
/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts/check-jarvis-limit.sh
Full plist content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.macclaw.jarvis-limit-check</string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts/check-jarvis-limit.sh vice-claude >> /Users/nbs22/.openclaw/logs/jarvis-limit-check.log 2>&1</string>
</array>
<key>StartInterval</key>
<integer>300</integer>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/nbs22/.openclaw/logs/jarvis-limit-check.stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/nbs22/.openclaw/logs/jarvis-limit-check.stderr.log</string>
</dict>
</plist>
Step 2: Update daily-git-push.plist
Change ProgramArguments from:
/Users/nbs22/.openclaw/workspace/scripts/daily-git-push.sh
To:
/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts/daily-git-push.sh
Full plist content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.macclaw.daily-git-push</string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts/daily-git-push.sh</string>
</array>
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Hour</key>
<integer>12</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<dict>
<key>Hour</key>
<integer>23</integer>
<key>Minute</key>
<integer>50</integer>
</dict>
</array>
<key>StandardOutPath</key>
<string>/Users/nbs22/.openclaw/logs/daily-git-push.stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/nbs22/.openclaw/logs/daily-git-push.stderr.log</string>
</dict>
</plist>
Step 3: Reload LaunchAgents
launchctl unload ~/Library/LaunchAgents/com.macclaw.jarvis-limit-check.plist
launchctl load ~/Library/LaunchAgents/com.macclaw.jarvis-limit-check.plist
launchctl unload ~/Library/LaunchAgents/com.macclaw.daily-git-push.plist
launchctl load ~/Library/LaunchAgents/com.macclaw.daily-git-push.plist
Step 4: Verify both agents are running
launchctl list | grep macclaw
Expected: both show with exit code 0.
Task 4: Add missing LaunchAgent for OKR scheduler (6-hour cycle)
Files:
- Create:
~/Library/LaunchAgents/com.macclaw.okr-scheduler.plist
Step 1: Create plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.macclaw.okr-scheduler</string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts/okr-scheduler.sh >> /Users/nbs22/.openclaw/logs/okr-scheduler.log 2>&1</string>
</array>
<key>StartInterval</key>
<integer>21600</integer>
<key>StandardOutPath</key>
<string>/Users/nbs22/.openclaw/logs/okr-scheduler.stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/nbs22/.openclaw/logs/okr-scheduler.stderr.log</string>
</dict>
</plist>
Step 2: Load LaunchAgent
launchctl load ~/Library/LaunchAgents/com.macclaw.okr-scheduler.plist
Step 3: Verify
launchctl list | grep okr-scheduler
Expected: shows with exit code 0 or -.
Task 5: Add missing LaunchAgent for Turso backup (daily)
Files:
- Create:
~/Library/LaunchAgents/com.macclaw.turso-backup.plist
Step 1: Create plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.macclaw.turso-backup</string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts/backup-turso.sh >> /Users/nbs22/.openclaw/logs/turso-backup.log 2>&1</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>4</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/Users/nbs22/.openclaw/logs/turso-backup.stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/nbs22/.openclaw/logs/turso-backup.stderr.log</string>
</dict>
</plist>
Step 2: Load LaunchAgent
launchctl load ~/Library/LaunchAgents/com.macclaw.turso-backup.plist
Step 3: Verify
launchctl list | grep turso-backup
Task 6: Add missing LaunchAgent for OKR weekly review (Monday 09:00)
Files:
- Create:
~/Library/LaunchAgents/com.macclaw.okr-weekly-review.plist
Step 1: Create plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.macclaw.okr-weekly-review</string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>/Users/nbs22/(Claude)/(claude).projects/business-builder/scripts/okr-weekly-review.sh >> /Users/nbs22/.openclaw/logs/okr-weekly-review.log 2>&1</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key>
<integer>1</integer>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/Users/nbs22/.openclaw/logs/okr-weekly-review.stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/nbs22/.openclaw/logs/okr-weekly-review.stderr.log</string>
</dict>
</plist>
Step 2: Update okr-weekly-review.sh to use business-builder paths
The script currently references $PROJECT_ROOT/scripts/report.sh. After Task 2, report.sh is a symlink to vice-reply.sh, so this works. No changes needed.
Step 3: Load LaunchAgent
launchctl load ~/Library/LaunchAgents/com.macclaw.okr-weekly-review.plist
Completion Checklist
After all tasks:
| Check | Verification Command |
|---|---|
| All 6 LaunchAgents loaded | launchctl list | grep -E 'macclaw|openclaw' — expect 6 entries |
| No duplicate scripts in OpenClaw | ls ~/.openclaw/workspace/scripts/ — only vp_prompt_inject.sh and start-vice-claude.sh remain |
| All plists point to business-builder | grep -l 'openclaw/workspace/scripts' ~/Library/LaunchAgents/*.plist — expect 0 results |
| report.sh is symlink | ls -la scripts/report.sh — shows -> vice-reply.sh |
| jarvis-limit-check working | cat ~/.openclaw/workspace/memory/jarvis-limit-state.json — recent timestamp |
| daily-git-push scheduled | launchctl list | grep daily-git-push — exit 0 |
| OKR scheduler running | Wait 6h or bash scripts/okr-scheduler.sh manual test |
| Turso backup scheduled | launchctl list | grep turso-backup — loaded |
| OKR weekly review scheduled | launchctl list | grep okr-weekly-review — loaded |
Final State
After migration:
~/Library/LaunchAgents/
ai.openclaw.gateway.plist → OpenClaw gateway (unchanged)
com.macclaw.jarvis-limit-check.plist → scripts/check-jarvis-limit.sh (path updated)
com.macclaw.daily-git-push.plist → scripts/daily-git-push.sh (path updated)
com.macclaw.okr-scheduler.plist → scripts/okr-scheduler.sh (NEW)
com.macclaw.turso-backup.plist → scripts/backup-turso.sh (NEW)
com.macclaw.okr-weekly-review.plist → scripts/okr-weekly-review.sh (NEW)
business-builder/scripts/ (canonical source for all scripts)
backup-turso.sh
ceo-reply.sh
check-jarvis-limit.sh
daily-git-push.sh (moved from openclaw)
okr-scheduler.sh
okr-weekly-review.sh (moved from openclaw)
report.sh -> vice-reply.sh (symlink)
scheduler-report.sh
start-vice-claude.sh (moved from openclaw)
telegram-reply.sh
vice-reply.sh
vp_prompt_inject.sh
~/.openclaw/workspace/scripts/ (VP-specific only)
vp_prompt_inject.sh (HTTP API version, VP-specific)
Risk Notes
ai.openclaw.gateway.plist: NOT touched. This is OpenClaw's own managed plist with secrets. Changing it could break VP communication.- Parentheses in paths:
(Claude)/(claude).projectscontains special characters. All plist entries must quote or escape properly. macOS LaunchAgent handles this natively in<string>XML elements. okr-weekly-review.shreferences$PROJECT_ROOT/projects/jarvis-system/apps/worker: Requires@libsql/clientto be installed there. Verify withls projects/jarvis-system/apps/worker/node_modules/@libsql/before enabling the LaunchAgent.