AGENTS.md: amadan is the source of truth; squash before landing
The "every change lands through a PR" rule pointed at GitHub (gh pr merge, then push main to amadan), while the issues rule already said main lands through `amadan branch merge`. Both were followed. GitHub-first merges ran CI only after the change was on main. Now: push the branch to amadan, describe it with `amadan branch describe`, squash it to one commit, and land it with `amadan branch merge` once CI is green on that tip. GitHub is a mirror that follows amadan's main; no PRs or merges there. The Build & test bullets that called GitHub the source of truth and told you to push main to amadan after a GitHub merge are replaced to match. Bill's ruling, 2026-09-24.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+66
−52
AGENTS.md+66 −52
CI passed — run details
diff --git a/AGENTS.md b/AGENTS.md| index 542447ec0..9415e5890 100644 |
| --- a/AGENTS.md |
| +++ b/AGENTS.md |
| @@ -86,36 +86,58 @@ The rationale is concrete: on September 15, an SES spike created |
| production account. It was removed minutes later, but cleanup does not |
| substitute for approval. |
| -## Every change lands through a PR (Paul's rule, 2026-08-10) |
| - |
| -**Nothing merges to `main` without a pull request.** No local merge to |
| -`main`, no direct commit to `main`, no fast-forward "it's only a docs |
| -change" — every change, however small, goes up as a branch and lands |
| -through a PR. That includes doc-only edits, one-line fixes, and revert |
| -commits. |
| - |
| -Agents: this rule is on you as much as on people. When work is complete, |
| -push the branch and open the PR — never a local merge, never a direct |
| -commit, however small the change. |
| - |
| -**Merging that PR is fine** (Paul, 2026-08-16, clarifying an earlier |
| -wording that read as a blanket ban and cost a session a round trip). The |
| -rule is about how work REACHES `main`, not about whose hand lands it: the |
| -PR has to exist, so that it can carry the context, the iterations and the |
| -several commits that a single squashed push to `main` would flatten. Once |
| -it exists and is green, `gh pr merge` is an ordinary step — followed by |
| -pushing `main` to `amadan`, which is what gates the merged result (see |
| -Build & test). |
| - |
| -Use the judgement the rest of this file asks for: a PR that is still |
| -collecting review, that is gated on something (`#62`), or whose diff you |
| -would want a second pair of eyes on, waits for a person. |
| - |
| -The reason is timing, not ceremony. A locally merged change does still |
| -meet the gate — but only **after** it is on `main`, where a red run is an |
| -incident to clean up rather than a merge that simply doesn't happen. The |
| -PR is the one place the branch's diff is read as a single piece rather |
| -than commit by commit, while the change can still be turned away. |
| +## Every change lands through a reviewed branch on amadan (Paul's rule, 2026-08-10; amadan made the source of truth by Bill, 2026-09-24) |
| + |
| +**Nothing reaches `main` except through a branch landed on amadan.** No |
| +local merge to `main`, no direct commit to `main`, no fast-forward "it's |
| +only a docs change" — every change, however small, goes up as a branch |
| +and lands through `amadan branch merge`. That includes doc-only edits, |
| +one-line fixes, and revert commits. |
| + |
| +**amadan (`carlos/platform` on amadan.net) is the source of truth.** Its |
| +`main` is the real one, its CI is the only CI, and its branch description |
| +is where a change's context lives. GitHub is a mirror of it: do not open |
| +pull requests there, and never merge there. (Until 2026-09-24 this rule |
| +said "through a PR" and pointed at GitHub, while the issues rule below |
| +already said `main` lands through `amadan branch merge`. Both were |
| +followed, and GitHub-first merges ran CI only after the merge. That |
| +contradiction is what this rewrite removes.) |
| + |
| +The steps, for agents and people alike: |
| + |
| +1. **Push the branch to amadan.** The push is what triggers CI. The remote |
| + may be named `amadan` or `origin` depending on the checkout; it is |
| + whichever one points at `amadan.net`. |
| +2. **Describe it** — what changes, why, how it was tested and reviewed. |
| + This is the pull request's job and it carries the same weight: |
| + |
| + amadan branch describe carlos/platform <branch> -body - |
| + |
| +3. **Squash it to one commit** before landing, with a message that says |
| + what the change is and why. `amadan branch merge` has no squash mode, |
| + so this is done on the branch: `main` then gets the hub's merge commit |
| + and exactly one change commit under it, not the branch's iterations. |
| + The iterations are not lost: the description and the reviews record |
| + them. Squashing moves the tip, so CI runs again on it. |
| +4. **Land it once CI is green on that tip:** |
| + |
| + amadan ci status carlos/platform -branch <branch> |
| + amadan branch merge carlos/platform <branch> -expect <tip> -message "..." |
| + |
| + The merge refuses a branch whose CI is not green (exit 2) and, with |
| + `-expect`, one that moved after you checked it. That ordering is the |
| + point: a red run stops the merge instead of landing on `main` as an |
| + incident to clean up. |
| + |
| +**Merging is fine** (Paul, 2026-08-16, clarifying an earlier wording that |
| +read as a blanket ban and cost a session a round trip). The rule is about |
| +how work REACHES `main`, not about whose hand lands it: the described |
| +branch has to exist, so that it can carry the context, the iterations and |
| +the review. Once it is green, `amadan branch merge` is an ordinary step. |
| + |
| +Use the judgement the rest of this file asks for: a branch that is still |
| +collecting review, that is gated on something, or whose diff you would |
| +want a second pair of eyes on, waits for a person. |
| ## Work is tracked on amadan, not GitHub (Paul's rule, 2026-09-05) |
| @@ -171,28 +193,20 @@ anything. |
| records why the switch was safe. `10-gate` is `go build ./...` then |
| `make test`, so CI and what you run locally are one definition rather |
| than two that can drift. |
| -- **CI is triggered by a push to the `amadan` remote, not by GitHub.** |
| - `origin` is still where PRs live and where `main` is source of truth, |
| - but nothing on GitHub runs a build any more. A branch pushed only to |
| - `origin` has been gated by exactly nothing — push it to `amadan` too, |
| - and read the run, before calling it green. |
| -- **After a PR lands, push `main` to `amadan` too.** Merging happens on |
| - `origin`, and nothing moves amadan's `main` by itself, so the mirror |
| - falls behind silently: on 2026-08-31 it was 86 commits and three days |
| - back, which meant the gate had not run on `main` once in that window. |
| - A fast-forward is the whole job, and it is the last step of landing a |
| - change, not a separate chore: |
| - |
| - git fetch origin && git push amadan origin/main:refs/heads/main |
| - |
| - What it buys is the one thing per-branch CI cannot tell you: each |
| - branch was green against the base it was cut from, not against what |
| - landed beside it. Read that run too — a red `main` is worth knowing |
| - about the same day, which is the whole argument for the PR gate one |
| - section up. (The intended end state is an auto-mirror the other way, |
| - amadan to GitHub, so that `main` moves on the hub that gates it and |
| - GitHub follows. Until that exists this push is the habit that stands |
| - in for it.) |
| +- **CI is triggered by a push to amadan, not by GitHub.** Nothing on |
| + GitHub runs a build. A branch that exists only on GitHub has been gated |
| + by exactly nothing. Read a branch's verdict with |
| + `amadan ci status carlos/platform -branch <branch>` (exit 0 pass, 1 |
| + fail, 2 pending, 3 no status yet) before calling it green. |
| +- **After a merge, read `main`'s run too.** Each branch was green against |
| + the base it was cut from, not against what landed beside it. A red |
| + `main` is worth knowing about the same day. On 2026-08-31, when merges |
| + still happened on GitHub, amadan's `main` was 86 commits and three days |
| + behind, and the gate had not run on `main` once in that window; landing |
| + on amadan is what ends that. |
| +- **GitHub follows amadan.** If GitHub's `main` is behind amadan's after a |
| + merge, fast-forward it from amadan; never the other way round, and |
| + never with anything that is not already on amadan's `main`. |
| - `20-cross@5` adds `GOOS=darwin`/`windows`/`linux-arm64` compiles, one |
| per shard. **The gate is not Linux-only**: `internal/host` is linked |
| into the CLI, which people run on Macs, so a Linux-only type assumption |