A Claude Code plugin that catches the multi-agent stale-write race at git push time — the failure mode where two sessions both push to the same branch, one's git pull --rebase succeeds cleanly, but the file contents it writes are stale from before the other session's push landed. Git sees no conflict. The push lands. Work silently regresses.
No published tool catches this. Worktrees, branch protection, file leases, and merge queues all miss it — they solve filesystem isolation, concurrent writes, or test-detectable regressions. This catches the content-staleness case directly.
Installs a pre-push git hook into whatever repo Claude Code is running in. On every push to a protected branch (default main):
-
Tier 1 (exact-blob revert). For each file changed, hash the new content. Walk back 20 commits on the protected branch. If the new content matches any non-current historical blob → refuse the push. Near-zero false positives.
-
Tier 2 (line-overlap revert). For each file, count lines being removed by the push and lines added to that file on the branch in the last 6 hours. If the overlap is ≥ 60% of the recently-added lines → refuse.
Either check firing prints a clear diagnostic naming the files and the suspected past state.
Bypass mechanisms:
git push --no-verify— standard git escape hatch.- Commit message starting with
Revert:orRevert "— skip the check (deliberate revert).
Tunable via the plugin's configSchema:
SYNC_GUARD_PROTECTED_BRANCH(defaultmain)SYNC_GUARD_WINDOW_HOURS(default6)SYNC_GUARD_THRESHOLD_PCT(default60)SYNC_GUARD_SKIP_PATTERNS(default: common dependency lockfiles)
sync-guard/
├── .claude-plugin/
│ ├── plugin.json # plugin manifest with tunable configSchema
│ └── marketplace.json # community-marketplace submission metadata
├── hooks/
│ ├── hooks.json # wires SessionStart → install.sh
│ └── session-start.sh # idempotently installs lib/pre-push.sh into the active repo
├── lib/
│ └── pre-push.sh # the two-tier detector
├── skills/
│ └── multi-agent-git/
│ └── SKILL.md # auto-loaded discipline rules for agents
├── README.md
└── LICENSE
The bundled skill (multi-agent-git) is auto-loaded by Claude Code in any session where the plugin is active. It teaches the agent the in-session half of the defense — Edit-not-Write for existing files, re-Read after rebase, and how to respond when the hook fires.
/plugin marketplace add DomVinyard/sync-guard
/plugin install sync-guard
Clone the repo and symlink it under .claude/plugins/ in your project, or copy to ~/.claude/plugins/sync-guard/ for user-level install:
git clone https://github.com/DomVinyard/sync-guard ~/.claude/plugins/sync-guardThen start (or restart) any Claude Code session in a git repo. The SessionStart hook copies lib/pre-push.sh into that repo's .git/hooks/pre-push (idempotent, won't overwrite an existing hook unless it carries the sync-guard signature).
- Existing pre-push hooks: if
.git/hooks/pre-pushexists and isn't tagged with the sync-guard signature line, the installer leaves it alone and prints a one-line notice. You can manually compose the two hooks if needed. - Offline / fetch failures: if
git fetchfails, the hook passes through with a notice rather than blocking. Offline pushes shouldn't be blocked. - Non-protected branches: only the branch named in
SYNC_GUARD_PROTECTED_BRANCHis inspected. Feature-branch pushes go through unconditionally. - Binary files: skipped automatically (binary diffs aren't comparable line-by-line).
- Lockfiles: the default skip pattern matches the common ones across pnpm, npm, yarn, bun, cargo, gem, composer, poetry, uv, and go. Extend
SYNC_GUARD_SKIP_PATTERNSfor project-specific generated files. - Renames: treated as add + delete in v1. Tier 1 may miss them. The in-session
Editrule covers most cases.
Logged on 2026-05-20: in a session on DomVinyard/dom.vin, a parallel Claude-on-the-Web session Write-overwrote two files using pre-merge content held in its context, silently undoing two recently-merged PRs. The push was a clean fast-forward. The regression deployed to production. After researching the space, no existing tool catches this failure mode at push time. This plugin closes that gap.
MIT. See LICENSE.