Michiu / marketing reference

Vault mirror setup — runbook

Click-by-click guide for wiring up the iCloud → GitHub vault mirror.

Why this exists: The MICHIU Obsidian vault lives in iCloud (~/Library/Mobile Documents/iCloud~md~obsidian/Documents/MICHIU/). iCloud + git init is a known-bad combo (iCloud rewrites .git/ internals). This runbook sets up a separate local mirror directory, rsynced by a LaunchAgent, that is a proper git repo. The mirror repo on GitHub (quarbstudio/michiu-brand-vault) is then the authoritative source for the webhook-triggered vault sync pipeline in Marketing OS.

Two phases:

  • Phase 1 (low-blast) — scripts are already written; just set up the local mirror. No GitHub repo creation, no LaunchAgent yet. Good for "I want to try a manual sync first."
  • Phase 2 (high-blast) — create the private GitHub repo, clone it as the mirror dir, install the LaunchAgent for automated 15-min syncs, wire the GitHub webhook to /api/webhooks/vault-sync.

Phase 1 — Local mirror (manual sync, no LaunchAgent)

Step 1 — Create the mirror directory

mkdir -p ~/vault-mirrors/michiu-vault
cd ~/vault-mirrors/michiu-vault
git init
git commit --allow-empty -m "init"

The mirror dir must be outside iCloud. ~/vault-mirrors/ is a safe location.

Step 2 — Run a manual sync

cd /path/to/michiu-marketing
bash scripts/vault-sync.sh

The script rsyncs ~/Library/Mobile Documents/iCloud~md~obsidian/Documents/MICHIU/~/vault-mirrors/michiu-vault/, then commits any changes. On the first run it will commit the entire vault (~all .md files).

Expected output:

[2026-05-12 10:00:01] vault-sync: rsync … → ~/vault-mirrors/michiu-vault
[2026-05-12 10:00:03] vault-sync: pushed (312 file(s) changed)

If you see Mirror repo not initialised at …: you skipped Step 1, or you used a different path — set MIRROR_DIR env var to point to the correct directory:

MIRROR_DIR=~/vault-mirrors/michiu-vault bash scripts/vault-sync.sh

Step 3 — Add vault:push to package.json (optional convenience alias)

The script is already invocable as bash scripts/vault-sync.sh. If you want pnpm vault:push, add to package.json scripts:

"vault:push": "bash scripts/vault-sync.sh"

Phase 2 — GitHub repo + LaunchAgent + webhook

Step 1 — Create the private GitHub repo

gh repo create quarbstudio/michiu-brand-vault \
  --private \
  --description "MICHIU Obsidian vault mirror (iCloud → GitHub rsync)" \
  --clone=false

Step 2 — Wire the mirror dir to the GitHub remote

cd ~/vault-mirrors/michiu-vault
git remote add origin https://github.com/quarbstudio/michiu-brand-vault.git
git branch -M main
git push -u origin main

If you haven't set up a PAT yet:

  1. GitHub → Settings → Developer Settings → Personal Access Tokens → Fine-grained tokens → Generate new token.
  2. Resource owner: quarbstudio. Repository: michiu-brand-vault. Permissions: Contents → Read and write.
  3. Copy the token. In your terminal:
    git config --global credential.helper store
    
    Then run git push — macOS will prompt for credentials. Enter your GitHub username and the PAT as the password. The credential gets stored for future pushes.

Step 3 — Verify a push works end-to-end

bash scripts/vault-sync.sh
# Check https://github.com/quarbstudio/michiu-brand-vault — commits should appear

Step 4 — Install the LaunchAgent

# 1. Copy the plist template
cp scripts/vault-sync.launchagent.plist \
   ~/Library/LaunchAgents/com.quarb.michiu-vault-sync.plist

# 2. Replace the PLACEHOLDER_USERNAME with your actual macOS username
sed -i '' "s/PLACEHOLDER_USERNAME/$(whoami)/g" \
  ~/Library/LaunchAgents/com.quarb.michiu-vault-sync.plist

# 3. Also update the vault-sync.sh path if your clone is not at the default location
#    (open the plist in a text editor and check the ProgramArguments string)

# 4. Load the agent
launchctl load ~/Library/LaunchAgents/com.quarb.michiu-vault-sync.plist

# 5. Verify it loaded
launchctl list | grep michiu-vault-sync

Expected output from step 5:

-       0       com.quarb.michiu-vault-sync

The - in the PID column means it's not running right now (it fires on interval). 0 means last exit was clean. If you see a non-zero exit code, check the log:

tail -f ~/Library/Logs/michiu-vault-sync.log

The LaunchAgent fires every 15 minutes and on every login (RunAtLoad: true).

To unload:

launchctl unload ~/Library/LaunchAgents/com.quarb.michiu-vault-sync.plist

Step 5 — Configure the GitHub webhook

This wires GitHub → Marketing OS vault sync pipeline (Inngest vault.changed event).

  1. Go to https://github.com/quarbstudio/michiu-brand-vault/settings/hooks/new.
  2. Payload URL: https://marketing.michiu.quarb.com/api/webhooks/vault-sync
  3. Content type: application/json
  4. Secret: generate a strong random string:
    openssl rand -hex 32
    
    Copy it — you need it in two places (GitHub and Vercel).
  5. Which events: Just the push event.
  6. Click Add webhook.

Then in Vercel → michiu-marketing → Settings → Environment Variables:

Env keyValue
GITHUB_VAULT_SYNC_SECRETthe string from step 4 above
GITHUB_VAULT_REPOquarbstudio/michiu-brand-vault
GITHUB_VAULT_PATa fine-grained PAT with Contents: Read-only on michiu-brand-vault

Trigger a manual redeploy after saving.

Step 6 — Smoke test end-to-end

  1. Make a trivial edit to any .md file in the MICHIU Obsidian vault.
  2. Wait up to 15 minutes for the LaunchAgent (or run bash scripts/vault-sync.sh manually).
  3. Confirm the commit appears in https://github.com/quarbstudio/michiu-brand-vault.
  4. In GitHub → the repo → Settings → Webhooks, confirm the recent delivery shows a green checkmark.
  5. In Vercel → Project → Functions → /api/webhooks/vault-sync → Logs, confirm a POST with 200 appears.
  6. In Supabase → vault_documents table (or via the /admin/marketing-os/vault page), confirm the changed document's updated_at has refreshed.

Troubleshooting

SymptomLikely causeFix
Mirror repo not initialisedMIRROR_DIR doesn't have .git/Run Phase 1 Step 1, or set MIRROR_DIR env var to the correct path
rsync: No such file or directory for vault srciCloud vault path differs on your machineSet VAULT_SRC env var to the correct path; run ls ~/Library/Mobile\ Documents/ | grep obsidian to find it
LaunchAgent exit code non-zeroScript errortail -f ~/Library/Logs/michiu-vault-sync.log to see the error
GitHub webhook 403GITHUB_VAULT_SYNC_SECRET mismatchRe-copy from GitHub → Webhooks → Edit → Secret, update Vercel, redeploy
GitHub webhook 503Vercel env var not set or cold startCheck GITHUB_VAULT_SYNC_SECRET is set; trigger a redeploy
Vault documents not updating in SupabaseGITHUB_VAULT_PAT unset or expiredRegenerate PAT, update Vercel env var, redeploy
git push prompts for credentials every timeCredential helper not configuredRun git config --global credential.helper osxkeychain then push once to store

Env vars summary

# Vault mirror → GitHub webhook → Marketing OS
GITHUB_VAULT_SYNC_SECRET=        # random hex (openssl rand -hex 32) — shared with GitHub webhook
GITHUB_VAULT_REPO=quarbstudio/michiu-brand-vault
GITHUB_VAULT_PAT=                # fine-grained PAT, Contents: Read-only on vault repo

These go in Vercel env vars (Production + Preview). The webhook handler reads them at runtime.

Source: michiu-marketing/docs/platform/vault-mirror-runbook.md. To edit, change the file in the repo and redeploy.