Doctrine
Commit + push, always — GitHub is SSOT, local state is a cache
Commit + push, always — GitHub is SSOT, local state is a cache
Rule
1. Pull before work. Every session runs git pull origin <branch> before reading or editing files. Local state is a cache of GitHub. Stale caches cause merge conflicts, duplicate work, and invisible divergence.
2. Push after every commit. Every git commit is immediately followed by git push. A commit without a push is a doctrine violation. Report format: git_pushed: origin/<branch>.
3. No conditional pushes. The prior rule said "if a task requires a push." That condition is eliminated. Every commit requires a push. There are no local-only commits in this fleet.
Why
On 2026-04-24, a 10-agent cross-machine audit found all 4 repos diverged between MacBook Air and iMac:
- ORA: Air had 42 commits iMac didn't have (entries 0026–0041 missing on iMac)
- Camber: iMac had 16 unpushed commits on main + was 2 behind origin
- Heartwood: Both machines had 1 unpushed commit on main — different commits, same parent
- Orbit: Air had a duplicate-rename commit that diverged from origin's version
Root cause in every case: a session committed but didn't push. The drift compounded silently because no subsequent session pulled before starting work.
The initial instinct was to build a cross-machine sync script (SSH + compare HEADs + auto-fix). That's the wrong abstraction. Git via GitHub is already the sync mechanism. The machines don't need to talk to each other — they need to talk to origin.
Enforcement
The standing rule in ora/CLAUDE.md § GIT DISCIPLINE has been amended. The proof format now requires git_pushed: origin/<branch> in addition to git_committed: sha=<hash>.