SOPs
Repo Sync Policy
Why this exists
Section titled “Why this exists”Until 2026-04-30 every repo lived on every machine — Studio, MacBook Pro, VPS, Remote Mac. That worked at five repos. With 134 it means:
- Pullall and post-push-sync iterate across the whole fleet on every operation, even when 80% of repos have no business on the target machine.
- Dirty-check pings every repo on every machine, which fills the pre-prompt status line with noise (a Chrome extension showing dirty on the VPS is meaningless).
- A half-rewritten repo can show up dirty on a machine that has no use for it.
Per-repo allocation cuts the iteration count, narrows the blast radius, and makes “what is on this machine and why” intentional instead of historical.
The Sync header
Section titled “The Sync header”Every repo declares its allocation as a single line at the top of <repo>/CLAUDE.md, immediately after the H1 title:
# <repo-name>
> **Sync:** studio, mbpThat is the source of truth. Tooling reads this line; humans read this line. One line, one place.
Allowed values
Section titled “Allowed values”Always enumerate the actual machines. The valid tokens are:
studiombpvpsremote-mac
Plus one shorthand:
all— equivalent tostudio, mbp, vps, remote-mac
Banned: any grouped moniker like desk, studio-only, vps-only, desk+vps. The convention is “list the machines, full names, no decoder ring.” If you find a moniker in an existing repo, expand it to the explicit machine list. The parser rejects unknown tokens and refuses to run — that is the enforcement.
Examples
Section titled “Examples”| Repo type | Sync line |
|---|---|
| Default — dev tooling, daily-driver Mac apps | Sync: studio, mbp |
| Chrome extension or Chrome automation | Sync: studio, mbp, remote-mac |
| Production VPS service with local development | Sync: studio, mbp, vps |
| Foundational shared tooling | Sync: all |
| Heavy local-only tooling (iCloud watcher, NAS scan) | Sync: studio |
| VPS-resident service with no active local dev | Sync: vps |
Default for new repos
Section titled “Default for new repos”When you create a new repo, the default Sync line is:
> **Sync:** studio, mbpThat covers active development on both desk Macs. Add vps if the repo runs a service there, add remote-mac if it drives Chrome unattended, switch to all if it is foundational shared tooling.
Categories — when to use each
Section titled “Categories — when to use each”Sync: all — foundational shared tooling
Section titled “Sync: all — foundational shared tooling”Every machine needs this to participate in the fleet. Examples (not exhaustive):
cc— root configuration, hooks, repo registryvoice-pipeline— speak-claude-response.py, voice classifier, must run on every machine that hears Jamesgmail-helper— used cross-machinepullall— the sync tool itself; if it is missing, you cannot get itauto-journal— runs from any machine that observes the daytms-internal— the wiki, useful from every machine- Customer CRM repos that touch shared business data —
claude-code-crm,ai-assistant,allthingshandy,gokartpark-website
Sync: studio, mbp — dev tooling and daily-driver Mac apps
Section titled “Sync: studio, mbp — dev tooling and daily-driver Mac apps”Default for things you build, edit, or run interactively on a desk Mac:
github-helper— files issues and PRs from the dev machine, no business on a headless serverfreeflow-james,freeflow-button— Mac apps with Xcode/Makefile buildsdoodles,james-voice— creative output, edited locally- Blog and website repos in active iteration —
themarketingshow,mytechsupport - One-off Mac utilities —
finder-copy-path,finder-move,mission-control
Sync: studio, mbp, remote-mac — Chrome extensions and Chrome automation
Section titled “Sync: studio, mbp, remote-mac — Chrome extensions and Chrome automation”Per the global CLAUDE.md “Chrome automation” rule, unattended browser work runs only on Remote Mac. The repos that drive that work need to live there. Development still happens on the desk Macs, so it is studio + mbp + remote-mac, not remote-mac alone:
fb-name-learner,fb-spam-remover,fb-group-monitor,fb-messenger-ghl,fb-messenger-voice-noter,fb-messenger-voice-transcriber,fb-birthday-greeter,fb-email-slurper-3000,fb-follower-trackerconference-talk-reader— Chrome extensionlinkedin-followers-ghl,linkedin-auto-poster— browser automation against LinkedInfb-auto-poster— Chrome AppleScript poster
Sync: studio, mbp, vps — production VPS service with local development
Section titled “Sync: studio, mbp, vps — production VPS service with local development”The repo runs a service on the VPS but you also touch the code on a desk Mac:
webhook-receiver— VPS webhook routerremote-claude— VPS web interfacedmarc-monitor— VPS DMARC SMTP serverupdate-manager— VPS cron orchestrator- Any FastAPI service with a
systemctlunit on the VPS
Sync: vps — VPS-resident service with no active local dev
Section titled “Sync: vps — VPS-resident service with no active local dev”Rare. Use only when you genuinely never edit it from a desk Mac. Most production services move into studio, mbp, vps because dev iteration eventually happens.
Sync: studio — heavy local-only
Section titled “Sync: studio — heavy local-only”Things that physically cannot or should not roam:
meal-tracker— iCloud Photos watcher, runs on Studionas-crawler— Drive-mounted NAS scan, Studio’s mount- Any launchd job tied to a Studio-specific path
Sync: remote-mac — Remote-Mac-resident only
Section titled “Sync: remote-mac — Remote-Mac-resident only”Rare. Use when the agent code physically lives on remote-mac and is not edited from a desk Mac (e.g., openclaw-specific files).
Tooling behavior
Section titled “Tooling behavior”The following tools read the Sync header on startup and filter their work to the current machine:
pullall/pullall— clones repos that should be on this machine, pulls existing ones, removes ones that should NOT be on this machine only with explicit confirmation.cc/post-push-sync.sh— after a push, only triggers a pull on machines whose tag includes the pushed repo.pullall/check-dirty.py— only reports dirty state for repos that should be on this machine. Stops surfacing noise for repos that have no business here.
Unknown or missing tokens
Section titled “Unknown or missing tokens”- Unknown token (e.g.,
desk): parser refuses to run, prints which repo and which token, exits 1. Forces the writer to fix the header. - Missing Sync header entirely: parser treats as
allduring the rollout window (so the system keeps working while we sweep). Once the sweep is complete, missing-header behavior switches to “fail loud” — every repo must declare.
Adding or removing a machine from a repo
Section titled “Adding or removing a machine from a repo”To add a machine: edit the > **Sync:** line in <repo>/CLAUDE.md, push. Next pullall on the new machine clones it. No extra step.
To remove a machine: edit the line, push. Next pullall on the now-excluded machine asks for explicit confirmation before deleting that repo’s local clone. Pruning is destructive — the prompt is non-negotiable.
Sweep state
Section titled “Sweep state”The categorization sweep across all 134 repos runs as a one-time background pass on 2026-04-30. Output: a proposed tag per repo with a one-line justification. Reviewed in batches before any header is written. Final matrix lives at infrastructure/repo-machine-matrix (auto-generated from headers).
Why this is a doc, not a hook
Section titled “Why this is a doc, not a hook”The convention here is enforced by the parser refusing to run on unknown tokens and the Sync header being a required field once the sweep lands. No memory needed — the policy IS the source of truth, and the tooling checks against it.
Related
Section titled “Related”- Machines — IPs, SSH aliases, identity tags
- Repo Naming — naming convention for new repos