From 4c54f61a0020707bd794ec475a265d015111527a Mon Sep 17 00:00:00 2001 From: Chris Grady <17553614+cgfixit@users.noreply.github.com> Date: Wed, 5 Aug 2026 21:34:02 +0000 Subject: [PATCH 1/4] docs(agents): add multi-agent PR coordination rules --- AGENTS.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index bd3ba3e1..c708e98f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -314,6 +314,45 @@ keeping close to this file: - Do not invent commands; mark unknowns as needs verification (see the Build And Run Commands note on Docker above for how to phrase that). +## Multi-Agent PR Coordination + +Multiple coding agents (Grok, Claude, Codex, Kimi, Copilot, etc.) often open +parallel PRs without shared state. That is a coordination failure mode, not a +mystery merge problem. Treat agents as parallel workers on possibly stale +forks. + +Rules for multi-agent CyClaw work: + +1. **One source of truth.** Always `git fetch origin` first. Current + `origin/main` is the only tip that counts. +2. **Start from fresh main.** Before any agent opens a new PR branch, update + local `main` (or hand the agent a branch that already contains current + `origin/main`). Do not let an agent clone an old tip and invent work from it. +3. **After any history rewrite or force-push.** Assume every local clone and + every agent workspace is dirty until it is hard-reset or re-cloned onto the + new remote tips. +4. **Stack or isolate.** Either stack PRs deliberately (`A` → `B` → `C`) or keep + concurrent agent PRs on non-overlapping paths. Do not let three agents edit + the same files blind. +5. **Squash at merge.** Prefer squash-and-merge so agent WIP commits never + become permanent history on `main`. Write one clear final commit message. + +Quick stale-clone test after fetch: + +```bash +git merge-base --is-ancestor HEAD origin/main \ + && echo "OK: linear, pull is fine" \ + || echo "REWRITE/DIVERGED: hard-reset or re-clone" +``` + +If branches have diverged, refuse merge "fixes." Reset to remote truth: + +```bash +git checkout main +git fetch origin +git reset --hard origin/main +``` + ## Known Gotchas Covered by `CLAUDE.md` §4 (torch-first install order, `data/personality/soul.md`/`index/`/`logs/` expected at boot, `/soul/*` fail-closed without `CYCLAW_API_KEY`, loopback-only binding, `sync/` needs `rclone` and tests should mock it). Two with no `CLAUDE.md` equivalent: From cd0f4ac40b3b2309f3f6d51ce41427fedae30f60 Mon Sep 17 00:00:00 2001 From: CyClaw Agent Date: Thu, 6 Aug 2026 00:53:35 +0000 Subject: [PATCH 2/4] fix(docs): flip reversed merge-base ancestry check in AGENTS.md chatgpt-codex-connector flagged that the new "quick stale-clone test" snippet had its git merge-base --is-ancestor arguments backwards: `--is-ancestor HEAD origin/main` asks whether HEAD is an ancestor of origin/main, which is false for any healthy feature branch carrying its own commits -- it would report REWRITE/DIVERGED and send agents into an unneeded hard-reset/re-clone even when the branch already contains current origin/main. Verified empirically: running the old check against a branch that already contains the latest origin/main plus 10 of its own commits prints "REWRITE/DIVERGED" (false positive); the corrected `--is-ancestor origin/main HEAD` correctly prints "OK". Co-Authored-By: CyClaw Agent --- AGENTS.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c708e98f..718af347 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -337,11 +337,14 @@ Rules for multi-agent CyClaw work: 5. **Squash at merge.** Prefer squash-and-merge so agent WIP commits never become permanent history on `main`. Write one clear final commit message. -Quick stale-clone test after fetch: +Quick stale-clone test after fetch (works for local `main` or any feature +branch — it asks "does my current checkout already contain everything on +`origin/main`", not the reverse, so a healthy feature branch with its own +commits still reports OK): ```bash -git merge-base --is-ancestor HEAD origin/main \ - && echo "OK: linear, pull is fine" \ +git merge-base --is-ancestor origin/main HEAD \ + && echo "OK: current branch already contains origin/main" \ || echo "REWRITE/DIVERGED: hard-reset or re-clone" ``` From e9d22103cd84e3d61368bb916e9a31e3ec7c5062 Mon Sep 17 00:00:00 2001 From: CyClaw Agent Date: Thu, 6 Aug 2026 01:15:41 +0000 Subject: [PATCH 3/4] fix(docs): scope the AGENTS.md stale-branch recovery to what's actually stale Two more codex findings on the same section fixed in the prior commit: - The documented recovery (checkout main, fetch, hard-reset main) only helps when local main itself is what's stale. Run the quick-check from a feature branch that's simply behind (the common case for an agent branch cut before a later merge landed on main) and it reports REWRITE/DIVERGED, but resetting main does nothing for that branch -- switching back to it fails the same check and the pre-push gate still refuses it. Verified against this session's own history: PR #804/#809/#810 were in exactly this state (cut before #802 merged) and the fix was `git rebase origin/main` on each feature branch, not a main reset. - `git reset --hard origin/main` was presented unconditionally, with no check for unique local commits or uncommitted work it would discard. `git reset -h` confirms --hard resets HEAD, the index, and the working tree. CLAUDE.md's own Git Safety Protocol treats `reset --hard` as destructive and never to run without explicit confirmation; this doc contradicted that by presenting it as a bare recovery one-liner. Added the feature-branch rebase path as the primary recovery, and gated the main-reset path on `git status --short` being clean and `git log origin/main..main` being empty first. Co-Authored-By: CyClaw Agent --- AGENTS.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 718af347..e1a719e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -348,7 +348,17 @@ git merge-base --is-ancestor origin/main HEAD \ || echo "REWRITE/DIVERGED: hard-reset or re-clone" ``` -If branches have diverged, refuse merge "fixes." Reset to remote truth: +If branches have diverged, refuse merge "fixes." Do not discard work blindly: + +- **On a feature branch that is simply behind** (the common case — an agent + branch cut before a later merge landed on `main`): rebase it onto fresh + `origin/main`, resolve any conflicts, and rerun the check above. Resetting + `main` does not touch the feature branch, so switching back to it after a + `main` reset fails the same check and the pre-push gate still refuses it. +- **On local `main` itself**, and only after confirming there is no unique + local work to lose (`git status --short` is clean and + `git log origin/main..main` prints nothing — otherwise stash or branch off + first): reset to remote truth. ```bash git checkout main From 6a5b251e4b0fc47b613d283aa50ff3cae78b81a2 Mon Sep 17 00:00:00 2001 From: CyClaw Agent Date: Thu, 6 Aug 2026 01:22:31 +0000 Subject: [PATCH 4/4] fix(docs): make the AGENTS.md ancestry snippet clone-shape-independent Two more codex findings on the same stale-clone-test block: - A single-branch or sparse clone's remote.origin.fetch maps only the checked-out branch, so a plain `git fetch origin` never creates `origin/main` -- the ancestry check then fails with "unknown revision" (exit 128), which the `&&`/`||` wrapper reports as REWRITE/DIVERGED even though nothing has actually diverged. Reproduced live: cloned this repo with `--single-branch`, ran the documented `git fetch origin`, confirmed `origin/main` doesn't exist and the check misreports. The snippet now fetches `origin/main` with an explicit destination refspec (`git fetch origin main:refs/remotes/origin/main`), which creates the ref regardless of the configured fetch refspec -- verified this resolves it in the same single-branch clone. - The failure branch of that same snippet still printed "REWRITE/DIVERGED: hard-reset or re-clone" for the ordinarily-behind feature-branch case the prior commit's recovery prose already says to rebase, not reset -- steering an agent that only reads the echoed message toward unneeded destructive recovery. Message is now branch-neutral and points at the recovery section below instead of prescribing one. Co-Authored-By: CyClaw Agent --- AGENTS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e1a719e8..8e563e22 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -324,7 +324,10 @@ forks. Rules for multi-agent CyClaw work: 1. **One source of truth.** Always `git fetch origin` first. Current - `origin/main` is the only tip that counts. + `origin/main` is the only tip that counts — in a single-branch or sparse + clone, `remote.origin.fetch` may map only the checked-out branch, so a + plain `git fetch origin` silently leaves `origin/main` missing; the + snippet below fetches it explicitly rather than assuming it is present. 2. **Start from fresh main.** Before any agent opens a new PR branch, update local `main` (or hand the agent a branch that already contains current `origin/main`). Do not let an agent clone an old tip and invent work from it. @@ -343,9 +346,10 @@ branch — it asks "does my current checkout already contain everything on commits still reports OK): ```bash +git fetch origin main:refs/remotes/origin/main git merge-base --is-ancestor origin/main HEAD \ && echo "OK: current branch already contains origin/main" \ - || echo "REWRITE/DIVERGED: hard-reset or re-clone" + || echo "does not contain current origin/main -- see recovery below" ``` If branches have diverged, refuse merge "fixes." Do not discard work blindly: