diff --git a/.agents/skills/updatefirstmate/SKILL.md b/.agents/skills/updatefirstmate/SKILL.md index 36e9a80b937..004b59f4f4e 100644 --- a/.agents/skills/updatefirstmate/SKILL.md +++ b/.agents/skills/updatefirstmate/SKILL.md @@ -29,6 +29,7 @@ This touches only the firstmate repo and its own worktrees, never anything under bin/fm-update.sh ``` It fast-forwards this firstmate repo's default branch from origin, then updates every registered local or remote secondmate home through its placement-specific guarded path. + Origin is the only source it advances from, so in a fork, upstream work reaches homes only after it has landed on the fork's own default branch; CONTRIBUTING.md's "Fork remotes and upstream sync" owns that deliberate sync procedure. It prints one status line per target (`updated ..` / `already current` / `skipped: `), followed by two action lines that tell you exactly what to do next: - `reread-firstmate: yes|no` - `nudge-secondmates: fm-...|none` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 02c3a28af4a..32db5d80a8c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,8 +3,9 @@ Thanks for wanting to contribute. One rule up front: -**Human-authored pull requests targeting `main` must be raised through [`no-mistakes`](https://github.com/kunchenguid/no-mistakes).** +**Human-authored pull requests targeting the upstream repository's `main` must be raised through [`no-mistakes`](https://github.com/kunchenguid/no-mistakes).** We require this to reduce the maintainer's burden of reviewing and merging contributions. +The `Require no-mistakes` check is scoped to the upstream repository, so a downstream fork sets its own delivery rigor per change and legitimately raises direct pull requests on its own `main`. `no-mistakes` puts a local git proxy in front of your real remote. Pushing through it runs an AI-driven review/test/lint pipeline in an isolated worktree, forwards the push upstream only after every check passes, and opens a clean PR automatically. @@ -16,7 +17,8 @@ GitHub Actions and Dependabot are exempt so their automation keeps working, but ## Workflow -1. Fork the repo, then clone the parent repo or set your local `origin` back to the parent (`git@github.com:kunchenguid/firstmate.git`). +1. Fork the repo, then clone your fork so `origin` is the repository you can push to. + Add the upstream repository as a separate read-only remote with `git remote add upstream https://github.com/kunchenguid/firstmate`. 2. Create a branch and make your changes. 3. Initialize the gate with your fork as the push target: `no-mistakes init --fork-url git@github.com:/firstmate.git` (contributing to firstmate requires **no-mistakes v1.46.0+** for structured attestation; without a fork, plain `no-mistakes init` still works for maintainers with push access). 4. Commit your changes. @@ -32,6 +34,30 @@ GitHub Actions and Dependabot are exempt so their automation keeps working, but See the [no-mistakes quick start](https://kunchenguid.github.io/no-mistakes/start-here/quick-start/) for the full first-run walkthrough. +## Fork remotes and upstream sync + +A downstream fork keeps two remotes with different rights, and every contributor and agent in that fork depends on the distinction. +`origin` is the fork you can push to, and it is the only repository that receives branches, pull requests, and merges. +`upstream` is the parent repository, and it is read-only: never push to it, and never open a pull request against it from a fork that is operating independently. +Confirm which one you are about to write to with `git remote get-url origin` before any push or pull-request creation, because the two remotes differ only by owner in the URL. + +Firstmate homes self-update by fast-forwarding from `origin`, which `bin/fm-update.sh` and the [`updatefirstmate`](.agents/skills/updatefirstmate/SKILL.md) skill own. +That is the reason a fork cannot pick up upstream work simply by fetching it: the work has to reach the fork's own default branch first. +Sync the fork deliberately, as its own reviewable change: + +1. `git fetch upstream` and start a branch from the fork's current `main`. +2. `git merge upstream/main` on that branch, producing a merge commit whose first parent is the fork's `main` and whose second parent is the upstream commit being synced. + Merge rather than rebase, so every home can fast-forward onto the result instead of being asked to reconcile rewritten history. +3. Resolve conflicts with evidence rather than preference, and keep a local fix whenever it still covers a case the upstream change does not. +4. Run the repo's gates on the merge result, then push the branch to `origin` and open the pull request on the fork. +5. Land it with the configured merge authority, after which every home fast-forwards to it in the ordinary way. + +After any remote retarget, re-run `no-mistakes init` and inspect the gate mirror's own `git remote -v` before trusting the next pipeline run. +The pipeline rebases and opens pull requests from that mirror's `origin`, not from the checkout you are working in, so a mirror still pointing at the old remote sends work to the wrong repository while every local check still looks correct. + +Treehouse pool worktrees are `git worktree` entries that share the primary checkout's object store and configuration, so they inherit its remotes rather than defining their own. +Correcting the remotes once in the primary checkout is therefore what makes every existing and future pool worktree correct. + ## Repo conventions - This repo is a template for running a firstmate orchestrator agent. diff --git a/docs/documentation-audiences.json b/docs/documentation-audiences.json index 8bb68bd4ba2..c02fb2a66ab 100644 --- a/docs/documentation-audiences.json +++ b/docs/documentation-audiences.json @@ -432,6 +432,10 @@ "path": "docs/verification/runtime-backends.md", "audience": "maintainer-verification" }, + { + "path": "docs/verification/self-update.md", + "audience": "maintainer-verification" + }, { "path": "docs/verification/stow-memory.md", "audience": "maintainer-verification" diff --git a/docs/verification/self-update.md b/docs/verification/self-update.md new file mode 100644 index 00000000000..4e5662e7e39 --- /dev/null +++ b/docs/verification/self-update.md @@ -0,0 +1,53 @@ +# Self-update verification + +Active evidence that `/updatefirstmate` advances a firstmate home from its own `origin`. +The procedure this evidence exercises is owned by [`updatefirstmate`](../../.agents/skills/updatefirstmate/SKILL.md) for the agent path and by [`CONTRIBUTING.md`](../../CONTRIBUTING.md) ("Fork remotes and upstream sync") for the maintainer path. + +## Origin is the only update source + +Verified 2026-09-01 against `cm-maple7/firstmate` with a throwaway home cloned from the fork and deliberately set one commit behind its default branch. + +Setup: + +```sh +git clone https://github.com/cm-maple7/firstmate.git "$HOME_DIR" +git -C "$HOME_DIR" remote -v +origin https://github.com/cm-maple7/firstmate.git (fetch) +origin https://github.com/cm-maple7/firstmate.git (push) + +git -C "$HOME_DIR" reset --hard HEAD~1 +git -C "$HOME_DIR" log --oneline -1 +d77251e fix(bin): absorb background-run stale wakes and trust declared pauses over ci-monitoring (#2) +``` + +Run: + +```sh +FM_ROOT_OVERRIDE="$HOME_DIR" FM_HOME="$HOME_DIR" bash bin/fm-update.sh +firstmate: updated d77251e..6aa4beb (instructions changed: AGENTS.md, bin, .agents/skills) +reread-firstmate: yes +nudge-secondmates: none + +git -C "$HOME_DIR" log --oneline -1 +6aa4beb Merge pull request #5 from cm-maple7/fm/fm-fork-as-origin-followthrough +``` + +The home advanced by fast-forward to the fork's default branch, and the updater reported the tracked instruction surface as changed so the caller re-reads `AGENTS.md`. +`6aa4beb` is the merge that landed the upstream sync on the fork, so this run also demonstrates the full chain: upstream work reaches a home only after landing on the fork's own default branch. + +Refresh this record by repeating the three commands above whenever the update path or the fork's remote layout changes. + +## Pool worktrees inherit the primary checkout's remotes + +Verified 2026-09-01 on the same fork. +Treehouse pool worktrees are `git worktree` entries sharing the primary checkout's git directory, so they read its remote configuration rather than defining their own. + +```sh +git -C "$POOL_WORKTREE" rev-parse --git-common-dir +/Users/charlie/src/firstmate/.git + +git -C "$POOL_WORKTREE" remote get-url origin +https://github.com/cm-maple7/firstmate.git +``` + +Correcting the remotes once in the primary checkout is therefore what makes every existing and future pool worktree correct; no per-worktree repair step exists or is needed.