From 60a50bdda0c0b0f4b4004c32e020cfbf72b79d73 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 1 Oct 2026 18:05:50 +0200 Subject: [PATCH 1/6] Add a skill for upstreaming commits / PRs --- .claude/skills/upstream/SKILL.md | 141 +++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 .claude/skills/upstream/SKILL.md diff --git a/.claude/skills/upstream/SKILL.md b/.claude/skills/upstream/SKILL.md new file mode 100644 index 00000000000..0ba55d07449 --- /dev/null +++ b/.claude/skills/upstream/SKILL.md @@ -0,0 +1,141 @@ +--- +name: upstream +description: Upstream a Determinate Nix change (a commit rev or a DeterminateSystems/nix-src PR number) to upstream Nix (NixOS/nix). Creates a branch and worktree from origin/master, cherry-picks the commits, builds and tests, drafts a PR description for the user to review, and only after approval pushes the branch and opens the PR. Use when the user asks to upstream, cherry-pick to upstream, or open an upstream PR for a Determinate Nix change. +argument-hint: [more revs/PRs...] [branch-name] +user-invocable: true +--- + +# Upstreaming a Determinate Nix change to NixOS/nix + +Arguments: `$ARGUMENTS` + +Each argument is either a commit rev (SHA, tag, branch) in Determinate Nix, or a pull request number of https://github.com/DeterminateSystems/nix-src. Several may be given; they are cherry-picked in the order given. An argument that is neither a rev nor a number is used as the branch name. + +## Remotes + +* `origin` is upstream Nix, `git@github.com:NixOS/nix.git`. The new branch is pushed there and the PR is opened against its `master` branch. +* `detsys` is Determinate Nix, `git@github.com:DeterminateSystems/nix-src.git`. Its main branch is `main`. + +Verify both with `git remote get-url origin` and `git remote get-url detsys` before doing anything. If `detsys` is missing, add it with `git remote add detsys git@github.com:DeterminateSystems/nix-src.git`. Stop and tell the user if `origin` is not NixOS/nix. + +Start by updating both: `git fetch origin master` and `git fetch detsys main`. + +## Step 1: Determine the commits to cherry-pick + +For a **commit rev**: `git rev-parse --verify '^{commit}'`. If that fails, run `git fetch detsys ` and retry with `FETCH_HEAD`. + +For a **PR number** `N`, query it: + +``` +gh pr view N --repo DeterminateSystems/nix-src --json number,title,body,url,state,mergeCommit,headRefOid,baseRefName,commits +``` + +Then pick the commits depending on how the PR was merged (nix-src allows merge commits, squash merges and rebase merges): + +* `state` is `MERGED` and `mergeCommit.oid` has two parents (check with `git cat-file -p | grep -c '^parent '`): it is a real merge commit. The PR's own commits are `git rev-list --reverse --no-merges ^1..^2`. This excludes commits that were merged from `main` into the PR branch. +* `state` is `MERGED` and the merge commit has one parent and the PR has one commit, or the merge commit's subject matches the PR title with `(#N)` appended: squash merge. Cherry-pick `mergeCommit.oid` itself. +* `state` is `MERGED` and the merge commit has one parent but the PR lists several commits: rebase merge. `mergeCommit.oid` is the last of the rebased commits; take the last `length(commits)` commits ending there, `git rev-list --reverse -n `, and confirm that their subjects match the subjects of the PR's `commits` list. If they don't match, show both lists to the user and ask. +* `state` is `OPEN`: `git fetch detsys refs/pull/N/head`, then use `git rev-list --reverse --no-merges $(git merge-base detsys/main FETCH_HEAD)..FETCH_HEAD`. +* `state` is `CLOSED` (not merged): tell the user and stop. + +Print the resulting list with `git log --oneline --no-walk ` and check it for commits that make no sense upstream: bumps of `.version-determinate`, edits under `doc/manual/source/release-notes-determinate/`, generated Determinate release notes, or merges. Leave those out and say so in the final report. If a commit is only partly Determinate-specific (for example a code change plus a Determinate release-note file), keep it; the Determinate-only hunks are dealt with during the cherry-pick. + +## Step 2: Create the branch and worktree + +Choose a short kebab-case branch name that describes the change, in the style of existing upstream branches such as `fix-gc-interrupt-crash` or `progress-bar-signals`. No `username/` prefix, no ticket number. If the user supplied a branch name, use it as is. + +Create the worktree as a sibling of the main checkout, named `nix-`: + +``` +main=$(git worktree list --porcelain | head -n1 | cut -d' ' -f2-) +dir=$(dirname "$main")/nix- +git worktree add -b "$dir" origin/master +``` + +If the directory or branch already exists, pick a different name rather than reusing or deleting anything. Run every later command in that worktree, using `git -C "$dir"` for git and `cd "$dir" && ...` for everything else. Never touch the worktree the skill was started from. + +## Step 3: Cherry-pick + +``` +git -C "$dir" cherry-pick +``` + +Do not pass `-x`: Determinate commit hashes mean nothing in the upstream repository; the PR description links to the Determinate PR instead. Keep the original author, message and trailers. In particular keep any `Assisted-by:` trailers, which upstream's contributing guidelines require for AI-assisted commits. Do not add trailers of your own. + +### Simple conflicts: resolve them yourself + +Resolve and continue (`git add` the files, then `git cherry-pick --continue`, keeping the original commit message) when a conflict is one of these: + +* Context drift: neighbouring code changed, includes reordered, a function moved or renamed, whitespace or formatting differences. +* A file that was renamed or moved upstream. Apply the hunk to the file's new location. +* Hunks touching Determinate-only files, such as `doc/manual/source/release-notes-determinate/` or `.version-determinate`. Drop those hunks. If the change is user-visible and deserves a release note upstream, add one under `doc/manual/rl-next/` instead, in the format used by the existing files there. +* Trivial API differences that need a one- or two-line adaptation whose correctness is obvious. + +After resolving, rebuild the relevant part if practical, and mention every hand-resolved conflict in the final report. + +### Bigger conflicts: stop and ask + +Do not guess when any of these apply: + +* The commit relies on functionality that does not exist upstream yet (a class, function, setting, experimental feature, or an earlier Determinate commit that was never upstreamed). +* The same area was redesigned upstream, so the change needs to be reimplemented rather than merged. +* The conflict spans many files or you are unsure that a resolution preserves the intended behaviour. + +In that case leave the cherry-pick in its conflicted state (do not abort) and report to the user: which commit, which files, what the missing prerequisite or divergence is, and the options you see, typically skipping that commit, upstreaming the prerequisite first, adapting the change by hand, or abandoning. Ask how to proceed and wait for the answer before doing anything else. + +### After the cherry-picks + +Review the result: + +``` +git -C "$dir" log --oneline origin/master..HEAD +git -C "$dir" diff --stat origin/master..HEAD +git -C "$dir" diff origin/master..HEAD | grep -n -i 'determinate\|version-determinate' +``` + +Anything Determinate-specific that leaked through has to be removed with a fixup to the commit that introduced it. Use `git -C "$dir" commit --fixup ` followed by `GIT_SEQUENCE_EDITOR=true git -C "$dir" rebase -i --autosquash origin/master`. + +## Step 4: Format and test + +Run the formatter from the dev shell, which is how upstream CI checks formatting: + +``` +cd "$dir" && nix develop -c ./maintainers/format.sh +``` + +If it changed files, fold them into the commit that introduced them with the fixup and autosquash procedure above. + +Then build and test. Build the default package, which runs the unit tests and functional tests as part of its build: + +``` +cd "$dir" && nix build -L . +``` + +This takes a long time. Run it in the background with a generous timeout and wait for it to finish; do not poll. If the change adds or modifies tests, confirm from the build log that they ran. If something fails, decide whether it is caused by the cherry-picked change (fix it, with a fixup into the right commit, and rebuild) or is a pre-existing failure on `origin/master` (check by looking at the failing test on `origin/master`; if it fails there too, say so in the report and carry on). + +## Step 5: Draft the PR description, then stop for review + +Write the PR description to a file in the scratchpad directory, for example `/upstream-pr-.md`. Start from upstream's template, `.github/PULL_REQUEST_TEMPLATE.md` in the worktree (not the one in the Determinate checkout), and keep its structure and its `## Motivation` and `## Context` sections. + +Content guidelines, matching the user's existing upstream PRs: + +* When upstreaming a PR, start from the Determinate PR's own description (the `body` field from `gh pr view`) rather than writing a new one. Reuse its text, adapting it where needed: drop anything that only applies to Determinate Nix (Determinate release notes, Determinate version numbers, internal ticket references such as Sentry reports or Linear issues that upstream readers cannot see, mentions of commits that were left out), and map it onto the upstream template's sections. Keep the author's wording where it still applies. +* For a bare commit rev, find the PR that contains it with `gh pr list --repo DeterminateSystems/nix-src --search --state all --json number,url,body` and do the same with that PR's description. If there is none, write the Motivation yourself from the commit messages: a few sentences or a short bullet list saying what the change does and why. +* End the Motivation with a link to the Determinate PR, for example `Taken from https://github.com/DeterminateSystems/nix-src/pull/N.` If there is no PR, say the commit was taken from Determinate Nix `main`. +* Context: only fill it in when there is something to say, such as the implementation strategy for a non-trivial change, related upstream issues (search with `gh issue list --repo NixOS/nix --search '...'`), or reading order for a large diff. Leave the template's placeholder comments in place otherwise. +* Leave the rest of the template (the leading comment block and the footer) untouched. +* Title: for a single commit, its subject line; otherwise a concise imperative summary, like a commit subject. Put the proposed title on the first line of the file as `Title: ...` so the user can edit it too, and strip that line before using the file as the body. +* Do not add any line attributing the PR to an agent or tool, such as "Generated with", "Co-Authored-By" or "Assisted-by", to the title or the description. Upstream's contributing guidelines require PR descriptions to be human-authored, which is why the user reviews and edits this draft before it is submitted. + +Now report to the user and stop. The report must contain: the branch name and worktree path, the list of cherry-picked commits and any that were dropped, conflicts you resolved by hand, the build and test outcome (with the failing output if something failed), the path of the draft file, and the draft's contents. Ask the user to review or edit the file and to confirm that the PR may be created. Do not push and do not create the PR until they confirm. + +## Step 6: After approval, push and create the PR + +Re-read the draft file first, since the user may have edited it. Then: + +``` +git -C "$dir" push -u origin +gh pr create --repo NixOS/nix --base master --head --title "" --body-file <body-file> +``` + +Report the PR URL. Leave the worktree in place and mention that it can be removed later with `git worktree remove "$dir"`. From 1290d255818a07f93aa28c7f0099f7c4298e8676 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra <edolstra@gmail.com> Date: Fri, 2 Oct 2026 14:30:07 +0200 Subject: [PATCH 2/6] upstream skill: Follow skill authoring best practices * Don't rely on a shell variable for the worktree path, since variables don't persist between commands. An empty `$dir` would have made `git -C ""` silently operate on the original worktree. * Refer to "the Step 5 report" consistently. * Add a progress checklist with the approval gate as its own item. * Use the third person in the description. Assisted-by: Claude Fable 5.1 <noreply@anthropic.com> --- .claude/skills/upstream/SKILL.md | 48 +++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/.claude/skills/upstream/SKILL.md b/.claude/skills/upstream/SKILL.md index 0ba55d07449..c5de4394eef 100644 --- a/.claude/skills/upstream/SKILL.md +++ b/.claude/skills/upstream/SKILL.md @@ -1,6 +1,6 @@ --- name: upstream -description: Upstream a Determinate Nix change (a commit rev or a DeterminateSystems/nix-src PR number) to upstream Nix (NixOS/nix). Creates a branch and worktree from origin/master, cherry-picks the commits, builds and tests, drafts a PR description for the user to review, and only after approval pushes the branch and opens the PR. Use when the user asks to upstream, cherry-pick to upstream, or open an upstream PR for a Determinate Nix change. +description: Upstreams a Determinate Nix change (a commit rev or a DeterminateSystems/nix-src PR number) to upstream Nix (NixOS/nix). Creates a branch and worktree from origin/master, cherry-picks the commits, builds and tests, drafts a PR description for the user to review, and only after approval pushes the branch and opens the PR. Use when the user asks to upstream, cherry-pick to upstream, or open an upstream PR for a Determinate Nix change. argument-hint: <commit-rev | nix-src PR number> [more revs/PRs...] [branch-name] user-invocable: true --- @@ -11,6 +11,19 @@ Arguments: `$ARGUMENTS` Each argument is either a commit rev (SHA, tag, branch) in Determinate Nix, or a pull request number of https://github.com/DeterminateSystems/nix-src. Several may be given; they are cherry-picked in the order given. An argument that is neither a rev nor a number is used as the branch name. +Copy this checklist and check off items as you complete them: + +``` +- [ ] Verify and fetch the remotes +- [ ] Step 1: Determine the commits to cherry-pick +- [ ] Step 2: Create the branch and worktree +- [ ] Step 3: Cherry-pick +- [ ] Step 4: Format and test +- [ ] Step 5: Draft the PR description and report +- [ ] STOP: wait for the user to approve the draft +- [ ] Step 6: Push and create the PR +``` + ## Remotes * `origin` is upstream Nix, `git@github.com:NixOS/nix.git`. The new branch is pushed there and the PR is opened against its `master` branch. @@ -38,7 +51,7 @@ Then pick the commits depending on how the PR was merged (nix-src allows merge c * `state` is `OPEN`: `git fetch detsys refs/pull/N/head`, then use `git rev-list --reverse --no-merges $(git merge-base detsys/main FETCH_HEAD)..FETCH_HEAD`. * `state` is `CLOSED` (not merged): tell the user and stop. -Print the resulting list with `git log --oneline --no-walk <commits>` and check it for commits that make no sense upstream: bumps of `.version-determinate`, edits under `doc/manual/source/release-notes-determinate/`, generated Determinate release notes, or merges. Leave those out and say so in the final report. If a commit is only partly Determinate-specific (for example a code change plus a Determinate release-note file), keep it; the Determinate-only hunks are dealt with during the cherry-pick. +Print the resulting list with `git log --oneline --no-walk <commits>` and check it for commits that make no sense upstream: bumps of `.version-determinate`, edits under `doc/manual/source/release-notes-determinate/`, generated Determinate release notes, or merges. Leave those out and say so in the Step 5 report. If a commit is only partly Determinate-specific (for example a code change plus a Determinate release-note file), keep it; the Determinate-only hunks are dealt with during the cherry-pick. ## Step 2: Create the branch and worktree @@ -48,16 +61,19 @@ Create the worktree as a sibling of the main checkout, named `nix-<branch>`: ``` main=$(git worktree list --porcelain | head -n1 | cut -d' ' -f2-) -dir=$(dirname "$main")/nix-<branch> -git worktree add -b <branch> "$dir" origin/master +worktree=$(dirname "$main")/nix-<branch> +git worktree add -b <branch> "$worktree" origin/master +echo "$worktree" ``` -If the directory or branch already exists, pick a different name rather than reusing or deleting anything. Run every later command in that worktree, using `git -C "$dir"` for git and `cd "$dir" && ...` for everything else. Never touch the worktree the skill was started from. +If the directory or branch already exists, pick a different name rather than reusing or deleting anything. + +Shell variables do not persist between commands, so note the absolute path printed above and substitute it for `<worktree>` in every later command. Run every later command in that worktree, using `git -C <worktree>` for git and `cd <worktree> && ...` for everything else. Never touch the worktree the skill was started from. ## Step 3: Cherry-pick ``` -git -C "$dir" cherry-pick <commits...> +git -C <worktree> cherry-pick <commits...> ``` Do not pass `-x`: Determinate commit hashes mean nothing in the upstream repository; the PR description links to the Determinate PR instead. Keep the original author, message and trailers. In particular keep any `Assisted-by:` trailers, which upstream's contributing guidelines require for AI-assisted commits. Do not add trailers of your own. @@ -71,7 +87,7 @@ Resolve and continue (`git add` the files, then `git cherry-pick --continue`, ke * Hunks touching Determinate-only files, such as `doc/manual/source/release-notes-determinate/` or `.version-determinate`. Drop those hunks. If the change is user-visible and deserves a release note upstream, add one under `doc/manual/rl-next/` instead, in the format used by the existing files there. * Trivial API differences that need a one- or two-line adaptation whose correctness is obvious. -After resolving, rebuild the relevant part if practical, and mention every hand-resolved conflict in the final report. +After resolving, rebuild the relevant part if practical, and mention every hand-resolved conflict in the Step 5 report. ### Bigger conflicts: stop and ask @@ -88,19 +104,19 @@ In that case leave the cherry-pick in its conflicted state (do not abort) and re Review the result: ``` -git -C "$dir" log --oneline origin/master..HEAD -git -C "$dir" diff --stat origin/master..HEAD -git -C "$dir" diff origin/master..HEAD | grep -n -i 'determinate\|version-determinate' +git -C <worktree> log --oneline origin/master..HEAD +git -C <worktree> diff --stat origin/master..HEAD +git -C <worktree> diff origin/master..HEAD | grep -n -i 'determinate\|version-determinate' ``` -Anything Determinate-specific that leaked through has to be removed with a fixup to the commit that introduced it. Use `git -C "$dir" commit --fixup <sha>` followed by `GIT_SEQUENCE_EDITOR=true git -C "$dir" rebase -i --autosquash origin/master`. +Anything Determinate-specific that leaked through has to be removed with a fixup to the commit that introduced it. Use `git -C <worktree> commit --fixup <sha>` followed by `GIT_SEQUENCE_EDITOR=true git -C <worktree> rebase -i --autosquash origin/master`. ## Step 4: Format and test Run the formatter from the dev shell, which is how upstream CI checks formatting: ``` -cd "$dir" && nix develop -c ./maintainers/format.sh +cd <worktree> && nix develop -c ./maintainers/format.sh ``` If it changed files, fold them into the commit that introduced them with the fixup and autosquash procedure above. @@ -108,10 +124,10 @@ If it changed files, fold them into the commit that introduced them with the fix Then build and test. Build the default package, which runs the unit tests and functional tests as part of its build: ``` -cd "$dir" && nix build -L . +cd <worktree> && nix build -L . ``` -This takes a long time. Run it in the background with a generous timeout and wait for it to finish; do not poll. If the change adds or modifies tests, confirm from the build log that they ran. If something fails, decide whether it is caused by the cherry-picked change (fix it, with a fixup into the right commit, and rebuild) or is a pre-existing failure on `origin/master` (check by looking at the failing test on `origin/master`; if it fails there too, say so in the report and carry on). +This takes a long time. Run it in the background with a generous timeout and wait for it to finish; do not poll. If the change adds or modifies tests, confirm from the build log that they ran. If something fails, decide whether it is caused by the cherry-picked change (fix it, with a fixup into the right commit, and rebuild) or is a pre-existing failure on `origin/master` (check by looking at the failing test on `origin/master`; if it fails there too, say so in the Step 5 report and carry on). ## Step 5: Draft the PR description, then stop for review @@ -134,8 +150,8 @@ Now report to the user and stop. The report must contain: the branch name and wo Re-read the draft file first, since the user may have edited it. Then: ``` -git -C "$dir" push -u origin <branch> +git -C <worktree> push -u origin <branch> gh pr create --repo NixOS/nix --base master --head <branch> --title "<title>" --body-file <body-file> ``` -Report the PR URL. Leave the worktree in place and mention that it can be removed later with `git worktree remove "$dir"`. +Report the PR URL. Leave the worktree in place and mention that it can be removed later with `git worktree remove <worktree>`. From 583b49e49e233370130015e8bb2e668469d1a6b3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra <edolstra@gmail.com> Date: Fri, 2 Oct 2026 14:56:41 +0200 Subject: [PATCH 3/6] Add a skill for downstreaming commits / PRs Assisted-by: Claude Fable 5.1 <noreply@anthropic.com> --- .claude/skills/downstream/SKILL.md | 90 ++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .claude/skills/downstream/SKILL.md diff --git a/.claude/skills/downstream/SKILL.md b/.claude/skills/downstream/SKILL.md new file mode 100644 index 00000000000..cf7508194d3 --- /dev/null +++ b/.claude/skills/downstream/SKILL.md @@ -0,0 +1,90 @@ +--- +name: downstream +description: Downstreams an upstream Nix change (a commit rev or a NixOS/nix PR number) to Determinate Nix (DeterminateSystems/nix-src). Creates a branch and worktree from detsys/main, cherry-picks the commits, proposes upstream prerequisites if the change turns out to need them, builds and tests, pushes the branch and opens a PR against main. Use when the user asks to downstream, backport or cherry-pick an upstream Nix commit or PR into Determinate Nix. +argument-hint: <commit-rev | NixOS/nix PR number> [more revs/PRs...] [branch-name] +user-invocable: true +--- + +# Downstreaming an upstream Nix change to DeterminateSystems/nix-src + +Arguments: `$ARGUMENTS` + +Each argument is either a commit rev in upstream Nix, or a pull request number of https://github.com/NixOS/nix. Several may be given; they are cherry-picked in the order given. An argument that is neither a rev nor a number is used as the branch name. + +Copy this checklist and check off items as you complete them: + +``` +- [ ] Verify and fetch the remotes +- [ ] Step 1: Determine the commits to cherry-pick +- [ ] Step 2: Create the branch and worktree +- [ ] Step 3: Cherry-pick, building and testing along the way +- [ ] Step 4: Format and run the full tests +- [ ] Step 5: Push and create the PR +``` + +## Remotes + +* `origin` is upstream Nix, `git@github.com:NixOS/nix.git`. Its main branch is `master`. +* `detsys` is Determinate Nix, `git@github.com:DeterminateSystems/nix-src.git`. The new branch is pushed there and the PR is opened against its `main` branch. + +Verify both with `git remote get-url` before doing anything. If `detsys` is missing, add it. Stop and tell the user if `origin` is not NixOS/nix. + +Start by updating both: `git fetch origin master` and `git fetch detsys main`. + +## Step 1: Determine the commits to cherry-pick + +For a commit rev, that commit. For a PR, the PR's own commits (see `gh pr view N --repo NixOS/nix --json title,body,url,state,mergeCommit,commits`), without merge commits. Leave out commits that Determinate Nix already has. + +## Step 2: Create the branch and worktree + +Choose a short kebab-case branch name that describes the change, in the style of existing Determinate Nix branches such as `pin-fibers` or `wasm-no-suspend`. No `username/` prefix, no ticket number. If the user supplied a branch name, use it as is. + +Create the worktree as a sibling of the main checkout, named `nix-<branch>`: + +``` +main=$(git worktree list --porcelain | head -n1 | cut -d' ' -f2-) +worktree=$(dirname "$main")/nix-<branch> +git worktree add --no-track -b <branch> "$worktree" detsys/main +echo "$worktree" +``` + +If the directory or branch already exists, pick a different name rather than reusing or deleting anything. + +Shell variables do not persist between commands, so note the absolute path printed above and substitute it for `<worktree>` in every later command. Run every later command in that worktree, using `git -C <worktree>` for git and `cd <worktree> && ...` for everything else. Never touch the worktree the skill was started from. + +## Step 3: Cherry-pick, building and testing along the way + +``` +git -C <worktree> cherry-pick -x <commits...> +``` + +Keep the original author, message and trailers. Do not add trailers of your own. + +After each non-trivial cherry-pick (one that needed conflict resolution, or that is large or touches code Determinate Nix has changed), build and run the relevant tests before continuing, so that a problem is found at the commit that causes it. `AGENTS.md` in the worktree describes how to build and how to run individual tests; the `debug-fast` variant is enough here. + +Resolve simple conflicts yourself, such as context drift, files that Determinate Nix renamed, or trivial API differences whose adaptation is obviously correct. Fix small build or test failures caused by a cherry-picked commit by amending that commit. Mention every such intervention in the final report. + +For a bigger conflict or failure, first investigate whether the change depends on upstream commits that Determinate Nix does not have yet. If so, propose cherry-picking those prerequisites as well: tell the user which commits (and upstream PRs) they are and why the change needs them, and wait for the answer. If the problem is something else, for example Determinate Nix redesigned the same area, or you are unsure that a resolution preserves the intended behaviour, do not guess: leave things as they are, explain the problem and the options you see, and ask how to proceed. + +## Step 4: Format and run the full tests + +Run `nix develop -c ./maintainers/format.sh` in the worktree and fold any changes into the commits that introduced them. Then do the release build and run the full functional tests as described in `AGENTS.md`. This takes a long time; run it in the background and wait for it to finish. + +Handle failures as in Step 3. A failure that also occurs on `detsys/main` is not caused by the change; mention it in the final report and carry on. Do not create the PR while the build or tests fail because of the change. + +## Step 5: Push and create the PR + +Write the PR description to a file in the scratchpad directory, starting from `.github/PULL_REQUEST_TEMPLATE.md` in the worktree: + +* Motivation: reuse the upstream PR's own description, or summarise the commit messages if there is no PR. End with a link to the source, for example `Cherry-picked from https://github.com/NixOS/nix/pull/N.` +* Context: list any prerequisites that were included and why, and any adaptation that was needed for Determinate Nix. Leave the template's placeholder comments in place if there is nothing to say. +* Title: the upstream PR's title, or the commit's subject line. + +Then: + +``` +git -C <worktree> push -u detsys <branch>:refs/heads/<branch> +gh pr create --repo DeterminateSystems/nix-src --base main --head <branch> --title "<title>" --body-file <body-file> +``` + +Finish with the final report: the PR URL, the branch name and worktree path, the cherry-picked commits (marking which were prerequisites), commits that were left out and why, conflicts and failures you fixed by hand, and the build and test outcome. Mention that the worktree can be removed later with `git worktree remove <worktree>`. From c2474902be7e97e69ecfb90cd5f612cb29102dd2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra <edolstra@gmail.com> Date: Fri, 2 Oct 2026 14:56:41 +0200 Subject: [PATCH 4/6] upstream skill: Don't let the new branch track the base branch `git worktree add -b <branch> <path> origin/master` makes the new branch track `origin/master`, so depending on `push.default`, the later `git push -u origin <branch>` can try to push to `master`. Create the branch with `--no-track` and push with an explicit refspec. Assisted-by: Claude Fable 5.1 <noreply@anthropic.com> --- .claude/skills/upstream/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.claude/skills/upstream/SKILL.md b/.claude/skills/upstream/SKILL.md index c5de4394eef..9ffae940f08 100644 --- a/.claude/skills/upstream/SKILL.md +++ b/.claude/skills/upstream/SKILL.md @@ -62,7 +62,7 @@ Create the worktree as a sibling of the main checkout, named `nix-<branch>`: ``` main=$(git worktree list --porcelain | head -n1 | cut -d' ' -f2-) worktree=$(dirname "$main")/nix-<branch> -git worktree add -b <branch> "$worktree" origin/master +git worktree add --no-track -b <branch> "$worktree" origin/master echo "$worktree" ``` @@ -150,7 +150,7 @@ Now report to the user and stop. The report must contain: the branch name and wo Re-read the draft file first, since the user may have edited it. Then: ``` -git -C <worktree> push -u origin <branch> +git -C <worktree> push -u origin <branch>:refs/heads/<branch> gh pr create --repo NixOS/nix --base master --head <branch> --title "<title>" --body-file <body-file> ``` From f0ca1c4802b4138cb1aa013841d287d6b7fbce2c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra <edolstra@gmail.com> Date: Fri, 2 Oct 2026 15:03:57 +0200 Subject: [PATCH 5/6] upstream skill: Simplify Like the downstream skill, rely on the agent's judgement rather than prescribing an algorithm for determining the commits of a PR, for classifying conflicts and for writing the PR description. Also build and test after each non-trivial cherry-pick. Assisted-by: Claude Fable 5.1 <noreply@anthropic.com> --- .claude/skills/upstream/SKILL.md | 102 +++++++------------------------ 1 file changed, 22 insertions(+), 80 deletions(-) diff --git a/.claude/skills/upstream/SKILL.md b/.claude/skills/upstream/SKILL.md index 9ffae940f08..b4e8da0bc36 100644 --- a/.claude/skills/upstream/SKILL.md +++ b/.claude/skills/upstream/SKILL.md @@ -9,7 +9,7 @@ user-invocable: true Arguments: `$ARGUMENTS` -Each argument is either a commit rev (SHA, tag, branch) in Determinate Nix, or a pull request number of https://github.com/DeterminateSystems/nix-src. Several may be given; they are cherry-picked in the order given. An argument that is neither a rev nor a number is used as the branch name. +Each argument is either a commit rev in Determinate Nix, or a pull request number of https://github.com/DeterminateSystems/nix-src. Several may be given; they are cherry-picked in the order given. An argument that is neither a rev nor a number is used as the branch name. Copy this checklist and check off items as you complete them: @@ -17,8 +17,8 @@ Copy this checklist and check off items as you complete them: - [ ] Verify and fetch the remotes - [ ] Step 1: Determine the commits to cherry-pick - [ ] Step 2: Create the branch and worktree -- [ ] Step 3: Cherry-pick -- [ ] Step 4: Format and test +- [ ] Step 3: Cherry-pick, building and testing along the way +- [ ] Step 4: Format and run the full tests - [ ] Step 5: Draft the PR description and report - [ ] STOP: wait for the user to approve the draft - [ ] Step 6: Push and create the PR @@ -29,29 +29,13 @@ Copy this checklist and check off items as you complete them: * `origin` is upstream Nix, `git@github.com:NixOS/nix.git`. The new branch is pushed there and the PR is opened against its `master` branch. * `detsys` is Determinate Nix, `git@github.com:DeterminateSystems/nix-src.git`. Its main branch is `main`. -Verify both with `git remote get-url origin` and `git remote get-url detsys` before doing anything. If `detsys` is missing, add it with `git remote add detsys git@github.com:DeterminateSystems/nix-src.git`. Stop and tell the user if `origin` is not NixOS/nix. +Verify both with `git remote get-url` before doing anything. If `detsys` is missing, add it. Stop and tell the user if `origin` is not NixOS/nix. Start by updating both: `git fetch origin master` and `git fetch detsys main`. ## Step 1: Determine the commits to cherry-pick -For a **commit rev**: `git rev-parse --verify '<rev>^{commit}'`. If that fails, run `git fetch detsys <rev>` and retry with `FETCH_HEAD`. - -For a **PR number** `N`, query it: - -``` -gh pr view N --repo DeterminateSystems/nix-src --json number,title,body,url,state,mergeCommit,headRefOid,baseRefName,commits -``` - -Then pick the commits depending on how the PR was merged (nix-src allows merge commits, squash merges and rebase merges): - -* `state` is `MERGED` and `mergeCommit.oid` has two parents (check with `git cat-file -p <oid> | grep -c '^parent '`): it is a real merge commit. The PR's own commits are `git rev-list --reverse --no-merges <oid>^1..<oid>^2`. This excludes commits that were merged from `main` into the PR branch. -* `state` is `MERGED` and the merge commit has one parent and the PR has one commit, or the merge commit's subject matches the PR title with `(#N)` appended: squash merge. Cherry-pick `mergeCommit.oid` itself. -* `state` is `MERGED` and the merge commit has one parent but the PR lists several commits: rebase merge. `mergeCommit.oid` is the last of the rebased commits; take the last `length(commits)` commits ending there, `git rev-list --reverse -n <count> <oid>`, and confirm that their subjects match the subjects of the PR's `commits` list. If they don't match, show both lists to the user and ask. -* `state` is `OPEN`: `git fetch detsys refs/pull/N/head`, then use `git rev-list --reverse --no-merges $(git merge-base detsys/main FETCH_HEAD)..FETCH_HEAD`. -* `state` is `CLOSED` (not merged): tell the user and stop. - -Print the resulting list with `git log --oneline --no-walk <commits>` and check it for commits that make no sense upstream: bumps of `.version-determinate`, edits under `doc/manual/source/release-notes-determinate/`, generated Determinate release notes, or merges. Leave those out and say so in the Step 5 report. If a commit is only partly Determinate-specific (for example a code change plus a Determinate release-note file), keep it; the Determinate-only hunks are dealt with during the cherry-pick. +For a commit rev, that commit. For a PR, the PR's own commits (see `gh pr view N --repo DeterminateSystems/nix-src --json title,body,url,state,mergeCommit,commits`), without merge commits. Leave out commits that make no sense upstream, such as Determinate version bumps and Determinate release notes, and commits that upstream already has. ## Step 2: Create the branch and worktree @@ -70,88 +54,46 @@ If the directory or branch already exists, pick a different name rather than reu Shell variables do not persist between commands, so note the absolute path printed above and substitute it for `<worktree>` in every later command. Run every later command in that worktree, using `git -C <worktree>` for git and `cd <worktree> && ...` for everything else. Never touch the worktree the skill was started from. -## Step 3: Cherry-pick +## Step 3: Cherry-pick, building and testing along the way ``` git -C <worktree> cherry-pick <commits...> ``` -Do not pass `-x`: Determinate commit hashes mean nothing in the upstream repository; the PR description links to the Determinate PR instead. Keep the original author, message and trailers. In particular keep any `Assisted-by:` trailers, which upstream's contributing guidelines require for AI-assisted commits. Do not add trailers of your own. - -### Simple conflicts: resolve them yourself - -Resolve and continue (`git add` the files, then `git cherry-pick --continue`, keeping the original commit message) when a conflict is one of these: - -* Context drift: neighbouring code changed, includes reordered, a function moved or renamed, whitespace or formatting differences. -* A file that was renamed or moved upstream. Apply the hunk to the file's new location. -* Hunks touching Determinate-only files, such as `doc/manual/source/release-notes-determinate/` or `.version-determinate`. Drop those hunks. If the change is user-visible and deserves a release note upstream, add one under `doc/manual/rl-next/` instead, in the format used by the existing files there. -* Trivial API differences that need a one- or two-line adaptation whose correctness is obvious. - -After resolving, rebuild the relevant part if practical, and mention every hand-resolved conflict in the Step 5 report. - -### Bigger conflicts: stop and ask - -Do not guess when any of these apply: - -* The commit relies on functionality that does not exist upstream yet (a class, function, setting, experimental feature, or an earlier Determinate commit that was never upstreamed). -* The same area was redesigned upstream, so the change needs to be reimplemented rather than merged. -* The conflict spans many files or you are unsure that a resolution preserves the intended behaviour. - -In that case leave the cherry-pick in its conflicted state (do not abort) and report to the user: which commit, which files, what the missing prerequisite or divergence is, and the options you see, typically skipping that commit, upstreaming the prerequisite first, adapting the change by hand, or abandoning. Ask how to proceed and wait for the answer before doing anything else. - -### After the cherry-picks - -Review the result: - -``` -git -C <worktree> log --oneline origin/master..HEAD -git -C <worktree> diff --stat origin/master..HEAD -git -C <worktree> diff origin/master..HEAD | grep -n -i 'determinate\|version-determinate' -``` - -Anything Determinate-specific that leaked through has to be removed with a fixup to the commit that introduced it. Use `git -C <worktree> commit --fixup <sha>` followed by `GIT_SEQUENCE_EDITOR=true git -C <worktree> rebase -i --autosquash origin/master`. +Do not pass `-x`: Determinate commit hashes mean nothing in the upstream repository. Keep the original author, message and trailers, in particular any `Assisted-by:` trailers, which upstream requires for AI-assisted commits. Do not add trailers of your own. -## Step 4: Format and test +After each non-trivial cherry-pick (one that needed conflict resolution, or that is large or touches code that differs upstream), build and run the relevant tests before continuing, so that a problem is found at the commit that causes it. -Run the formatter from the dev shell, which is how upstream CI checks formatting: +Resolve simple conflicts yourself, such as context drift, files that were renamed upstream, or trivial API differences whose adaptation is obviously correct. Drop hunks that touch Determinate-only files (`.version-determinate`, `doc/manual/source/release-notes-determinate/`); if the change deserves a release note upstream, add one under `doc/manual/rl-next/` instead. Fix small build or test failures caused by a cherry-picked commit by amending that commit. Mention every such intervention in the Step 5 report. -``` -cd <worktree> && nix develop -c ./maintainers/format.sh -``` +For a bigger conflict or failure, first investigate whether the change depends on Determinate Nix commits that were never upstreamed. If so, tell the user which commits (and nix-src PRs) they are and why the change needs them, propose upstreaming them as well or first, and wait for the answer. If the problem is something else, for example upstream redesigned the same area, or you are unsure that a resolution preserves the intended behaviour, do not guess: leave things as they are, explain the problem and the options you see, and ask how to proceed. -If it changed files, fold them into the commit that introduced them with the fixup and autosquash procedure above. +When done, check that nothing Determinate-specific is left in `git -C <worktree> diff origin/master..HEAD`. -Then build and test. Build the default package, which runs the unit tests and functional tests as part of its build: +## Step 4: Format and run the full tests -``` -cd <worktree> && nix build -L . -``` +Run `nix develop -c ./maintainers/format.sh` in the worktree and fold any changes into the commits that introduced them. Then run `nix build -L .` in the worktree, which also runs the unit and functional tests. This takes a long time; run it in the background and wait for it to finish. -This takes a long time. Run it in the background with a generous timeout and wait for it to finish; do not poll. If the change adds or modifies tests, confirm from the build log that they ran. If something fails, decide whether it is caused by the cherry-picked change (fix it, with a fixup into the right commit, and rebuild) or is a pre-existing failure on `origin/master` (check by looking at the failing test on `origin/master`; if it fails there too, say so in the Step 5 report and carry on). +Handle failures as in Step 3. A failure that also occurs on `origin/master` is not caused by the change; mention it in the Step 5 report and carry on. ## Step 5: Draft the PR description, then stop for review -Write the PR description to a file in the scratchpad directory, for example `<scratchpad>/upstream-pr-<branch>.md`. Start from upstream's template, `.github/PULL_REQUEST_TEMPLATE.md` in the worktree (not the one in the Determinate checkout), and keep its structure and its `## Motivation` and `## Context` sections. - -Content guidelines, matching the user's existing upstream PRs: +Write the PR description to a file in the scratchpad directory, starting from upstream's `.github/PULL_REQUEST_TEMPLATE.md` in the worktree: -* When upstreaming a PR, start from the Determinate PR's own description (the `body` field from `gh pr view`) rather than writing a new one. Reuse its text, adapting it where needed: drop anything that only applies to Determinate Nix (Determinate release notes, Determinate version numbers, internal ticket references such as Sentry reports or Linear issues that upstream readers cannot see, mentions of commits that were left out), and map it onto the upstream template's sections. Keep the author's wording where it still applies. -* For a bare commit rev, find the PR that contains it with `gh pr list --repo DeterminateSystems/nix-src --search <sha> --state all --json number,url,body` and do the same with that PR's description. If there is none, write the Motivation yourself from the commit messages: a few sentences or a short bullet list saying what the change does and why. -* End the Motivation with a link to the Determinate PR, for example `Taken from https://github.com/DeterminateSystems/nix-src/pull/N.` If there is no PR, say the commit was taken from Determinate Nix `main`. -* Context: only fill it in when there is something to say, such as the implementation strategy for a non-trivial change, related upstream issues (search with `gh issue list --repo NixOS/nix --search '...'`), or reading order for a large diff. Leave the template's placeholder comments in place otherwise. -* Leave the rest of the template (the leading comment block and the footer) untouched. -* Title: for a single commit, its subject line; otherwise a concise imperative summary, like a commit subject. Put the proposed title on the first line of the file as `Title: ...` so the user can edit it too, and strip that line before using the file as the body. -* Do not add any line attributing the PR to an agent or tool, such as "Generated with", "Co-Authored-By" or "Assisted-by", to the title or the description. Upstream's contributing guidelines require PR descriptions to be human-authored, which is why the user reviews and edits this draft before it is submitted. +* Put the proposed title on the first line as `Title: ...` so the user can edit it too: the Determinate PR's title, or the commit's subject line. +* Motivation: reuse the Determinate PR's own description, or summarise the commit messages if there is no PR. Drop anything that only applies to Determinate Nix or that upstream readers cannot see, such as internal ticket references. End with a link to the source, for example `Taken from https://github.com/DeterminateSystems/nix-src/pull/N.` +* Context: only fill it in when there is something to say. Leave the template's placeholder comments in place otherwise. +* Do not add any line attributing the PR to an agent or tool ("Generated with", "Co-Authored-By", "Assisted-by"). Upstream requires PR descriptions to be human-authored, which is why the user reviews and edits this draft before it is submitted. -Now report to the user and stop. The report must contain: the branch name and worktree path, the list of cherry-picked commits and any that were dropped, conflicts you resolved by hand, the build and test outcome (with the failing output if something failed), the path of the draft file, and the draft's contents. Ask the user to review or edit the file and to confirm that the PR may be created. Do not push and do not create the PR until they confirm. +Now report to the user and stop. The report must contain: the branch name and worktree path, the cherry-picked commits and any that were left out, conflicts and failures you fixed by hand, the build and test outcome, the path of the draft file, and the draft's contents. Ask the user to review or edit the file and to confirm that the PR may be created. Do not push and do not create the PR until they confirm. ## Step 6: After approval, push and create the PR -Re-read the draft file first, since the user may have edited it. Then: +Re-read the draft file first, since the user may have edited it, and strip the `Title:` line from the body. Then: ``` git -C <worktree> push -u origin <branch>:refs/heads/<branch> gh pr create --repo NixOS/nix --base master --head <branch> --title "<title>" --body-file <body-file> ``` -Report the PR URL. Leave the worktree in place and mention that it can be removed later with `git worktree remove <worktree>`. +Report the PR URL. Mention that the worktree can be removed later with `git worktree remove <worktree>`. From 82dc741b56bc5974bfd8d815a5dce6f1101abb9d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra <edolstra@gmail.com> Date: Wed, 7 Oct 2026 14:06:07 +0200 Subject: [PATCH 6/6] upstream/downstream skills: Condense Drop detail that an agent already knows, such as how to create a worktree, how to pick a branch name, and the exact git/gh invocations. Keep only the repo-specific constraints. Assisted-by: Claude Fable 5.1 <noreply@anthropic.com> --- .claude/skills/downstream/SKILL.md | 50 ++++++++---------------------- .claude/skills/upstream/SKILL.md | 48 +++++++--------------------- 2 files changed, 25 insertions(+), 73 deletions(-) diff --git a/.claude/skills/downstream/SKILL.md b/.claude/skills/downstream/SKILL.md index cf7508194d3..f18f5309f53 100644 --- a/.claude/skills/downstream/SKILL.md +++ b/.claude/skills/downstream/SKILL.md @@ -24,67 +24,43 @@ Copy this checklist and check off items as you complete them: ## Remotes -* `origin` is upstream Nix, `git@github.com:NixOS/nix.git`. Its main branch is `master`. +* `origin` is upstream Nix, `git@github.com:NixOS/nix.git`, main branch `master`. * `detsys` is Determinate Nix, `git@github.com:DeterminateSystems/nix-src.git`. The new branch is pushed there and the PR is opened against its `main` branch. -Verify both with `git remote get-url` before doing anything. If `detsys` is missing, add it. Stop and tell the user if `origin` is not NixOS/nix. - -Start by updating both: `git fetch origin master` and `git fetch detsys main`. +Verify both before doing anything. Add `detsys` if it is missing; stop and tell the user if `origin` is not NixOS/nix. Then fetch `origin master` and `detsys main`. ## Step 1: Determine the commits to cherry-pick -For a commit rev, that commit. For a PR, the PR's own commits (see `gh pr view N --repo NixOS/nix --json title,body,url,state,mergeCommit,commits`), without merge commits. Leave out commits that Determinate Nix already has. +For a commit rev, that commit. For a PR, the PR's own commits (`gh pr view N --repo NixOS/nix`), without merge commits. Leave out commits that Determinate Nix already has. ## Step 2: Create the branch and worktree -Choose a short kebab-case branch name that describes the change, in the style of existing Determinate Nix branches such as `pin-fibers` or `wasm-no-suspend`. No `username/` prefix, no ticket number. If the user supplied a branch name, use it as is. - -Create the worktree as a sibling of the main checkout, named `nix-<branch>`: - -``` -main=$(git worktree list --porcelain | head -n1 | cut -d' ' -f2-) -worktree=$(dirname "$main")/nix-<branch> -git worktree add --no-track -b <branch> "$worktree" detsys/main -echo "$worktree" -``` - -If the directory or branch already exists, pick a different name rather than reusing or deleting anything. - -Shell variables do not persist between commands, so note the absolute path printed above and substitute it for `<worktree>` in every later command. Run every later command in that worktree, using `git -C <worktree>` for git and `cd <worktree> && ...` for everything else. Never touch the worktree the skill was started from. +Create the branch from `detsys/main` without tracking it, in a new worktree that is a sibling of the main checkout named `nix-<branch>`. Use the branch name the user supplied, if any. If the directory or branch already exists, pick a different name rather than reusing or deleting anything. Do all further work in that worktree; never touch the one the skill was started from. ## Step 3: Cherry-pick, building and testing along the way -``` -git -C <worktree> cherry-pick -x <commits...> -``` - -Keep the original author, message and trailers. Do not add trailers of your own. +Cherry-pick with `-x`. Keep the original author, message and trailers; do not add trailers of your own. -After each non-trivial cherry-pick (one that needed conflict resolution, or that is large or touches code Determinate Nix has changed), build and run the relevant tests before continuing, so that a problem is found at the commit that causes it. `AGENTS.md` in the worktree describes how to build and how to run individual tests; the `debug-fast` variant is enough here. +After each non-trivial cherry-pick (one that needed conflict resolution, or that is large or touches code Determinate Nix has changed), build and run the relevant tests before continuing, so that a problem is found at the commit that causes it. `AGENTS.md` in the worktree describes how; the `debug-fast` variant is enough here. -Resolve simple conflicts yourself, such as context drift, files that Determinate Nix renamed, or trivial API differences whose adaptation is obviously correct. Fix small build or test failures caused by a cherry-picked commit by amending that commit. Mention every such intervention in the final report. +Resolve simple conflicts yourself, such as context drift, renamed files, or trivial API differences whose adaptation is obviously correct. Fix small build or test failures caused by a cherry-picked commit by amending that commit. Mention every such intervention in the final report. -For a bigger conflict or failure, first investigate whether the change depends on upstream commits that Determinate Nix does not have yet. If so, propose cherry-picking those prerequisites as well: tell the user which commits (and upstream PRs) they are and why the change needs them, and wait for the answer. If the problem is something else, for example Determinate Nix redesigned the same area, or you are unsure that a resolution preserves the intended behaviour, do not guess: leave things as they are, explain the problem and the options you see, and ask how to proceed. +For a bigger conflict or failure, first investigate whether the change depends on upstream commits that Determinate Nix does not have yet. If so, propose cherry-picking those prerequisites as well: tell the user which commits (and upstream PRs) they are and why the change needs them, and wait for the answer. If the problem is something else, for example Determinate Nix redesigned the same area, or you are unsure that a resolution preserves the intended behaviour, do not guess: explain the problem and the options you see, and ask how to proceed. ## Step 4: Format and run the full tests -Run `nix develop -c ./maintainers/format.sh` in the worktree and fold any changes into the commits that introduced them. Then do the release build and run the full functional tests as described in `AGENTS.md`. This takes a long time; run it in the background and wait for it to finish. +Run `nix develop -c ./maintainers/format.sh` and fold any changes into the commits that introduced them. Then do the release build and run the full functional tests as described in `AGENTS.md`; this takes a long time, so run it in the background. Handle failures as in Step 3. A failure that also occurs on `detsys/main` is not caused by the change; mention it in the final report and carry on. Do not create the PR while the build or tests fail because of the change. ## Step 5: Push and create the PR -Write the PR description to a file in the scratchpad directory, starting from `.github/PULL_REQUEST_TEMPLATE.md` in the worktree: +Write the PR description starting from `.github/PULL_REQUEST_TEMPLATE.md` in the worktree: +* Title: the upstream PR's title, or the commit's subject line. * Motivation: reuse the upstream PR's own description, or summarise the commit messages if there is no PR. End with a link to the source, for example `Cherry-picked from https://github.com/NixOS/nix/pull/N.` * Context: list any prerequisites that were included and why, and any adaptation that was needed for Determinate Nix. Leave the template's placeholder comments in place if there is nothing to say. -* Title: the upstream PR's title, or the commit's subject line. -Then: - -``` -git -C <worktree> push -u detsys <branch>:refs/heads/<branch> -gh pr create --repo DeterminateSystems/nix-src --base main --head <branch> --title "<title>" --body-file <body-file> -``` +Push the branch to `detsys` and open the PR with `gh pr create --repo DeterminateSystems/nix-src --base main`. -Finish with the final report: the PR URL, the branch name and worktree path, the cherry-picked commits (marking which were prerequisites), commits that were left out and why, conflicts and failures you fixed by hand, and the build and test outcome. Mention that the worktree can be removed later with `git worktree remove <worktree>`. +Finish with the final report: the PR URL, the branch name and worktree path, the cherry-picked commits (marking which were prerequisites), commits that were left out and why, conflicts and failures you fixed by hand, and the build and test outcome. Mention that the worktree can be removed later with `git worktree remove`. diff --git a/.claude/skills/upstream/SKILL.md b/.claude/skills/upstream/SKILL.md index b4e8da0bc36..b557c06e625 100644 --- a/.claude/skills/upstream/SKILL.md +++ b/.claude/skills/upstream/SKILL.md @@ -27,58 +27,39 @@ Copy this checklist and check off items as you complete them: ## Remotes * `origin` is upstream Nix, `git@github.com:NixOS/nix.git`. The new branch is pushed there and the PR is opened against its `master` branch. -* `detsys` is Determinate Nix, `git@github.com:DeterminateSystems/nix-src.git`. Its main branch is `main`. +* `detsys` is Determinate Nix, `git@github.com:DeterminateSystems/nix-src.git`, main branch `main`. -Verify both with `git remote get-url` before doing anything. If `detsys` is missing, add it. Stop and tell the user if `origin` is not NixOS/nix. - -Start by updating both: `git fetch origin master` and `git fetch detsys main`. +Verify both before doing anything. Add `detsys` if it is missing; stop and tell the user if `origin` is not NixOS/nix. Then fetch `origin master` and `detsys main`. ## Step 1: Determine the commits to cherry-pick -For a commit rev, that commit. For a PR, the PR's own commits (see `gh pr view N --repo DeterminateSystems/nix-src --json title,body,url,state,mergeCommit,commits`), without merge commits. Leave out commits that make no sense upstream, such as Determinate version bumps and Determinate release notes, and commits that upstream already has. +For a commit rev, that commit. For a PR, the PR's own commits (`gh pr view N --repo DeterminateSystems/nix-src`), without merge commits. Leave out commits that make no sense upstream, such as Determinate version bumps and Determinate release notes, and commits that upstream already has. ## Step 2: Create the branch and worktree -Choose a short kebab-case branch name that describes the change, in the style of existing upstream branches such as `fix-gc-interrupt-crash` or `progress-bar-signals`. No `username/` prefix, no ticket number. If the user supplied a branch name, use it as is. - -Create the worktree as a sibling of the main checkout, named `nix-<branch>`: - -``` -main=$(git worktree list --porcelain | head -n1 | cut -d' ' -f2-) -worktree=$(dirname "$main")/nix-<branch> -git worktree add --no-track -b <branch> "$worktree" origin/master -echo "$worktree" -``` - -If the directory or branch already exists, pick a different name rather than reusing or deleting anything. - -Shell variables do not persist between commands, so note the absolute path printed above and substitute it for `<worktree>` in every later command. Run every later command in that worktree, using `git -C <worktree>` for git and `cd <worktree> && ...` for everything else. Never touch the worktree the skill was started from. +Create the branch from `origin/master` without tracking it, in a new worktree that is a sibling of the main checkout named `nix-<branch>`. Use the branch name the user supplied, if any. If the directory or branch already exists, pick a different name rather than reusing or deleting anything. Do all further work in that worktree; never touch the one the skill was started from. ## Step 3: Cherry-pick, building and testing along the way -``` -git -C <worktree> cherry-pick <commits...> -``` - -Do not pass `-x`: Determinate commit hashes mean nothing in the upstream repository. Keep the original author, message and trailers, in particular any `Assisted-by:` trailers, which upstream requires for AI-assisted commits. Do not add trailers of your own. +Cherry-pick without `-x`: Determinate commit hashes mean nothing in the upstream repository. Keep the original author, message and trailers, in particular any `Assisted-by:` trailers, which upstream requires for AI-assisted commits. Do not add trailers of your own. After each non-trivial cherry-pick (one that needed conflict resolution, or that is large or touches code that differs upstream), build and run the relevant tests before continuing, so that a problem is found at the commit that causes it. -Resolve simple conflicts yourself, such as context drift, files that were renamed upstream, or trivial API differences whose adaptation is obviously correct. Drop hunks that touch Determinate-only files (`.version-determinate`, `doc/manual/source/release-notes-determinate/`); if the change deserves a release note upstream, add one under `doc/manual/rl-next/` instead. Fix small build or test failures caused by a cherry-picked commit by amending that commit. Mention every such intervention in the Step 5 report. +Resolve simple conflicts yourself, such as context drift, renamed files, or trivial API differences whose adaptation is obviously correct. Drop hunks that touch Determinate-only files (`.version-determinate`, `doc/manual/source/release-notes-determinate/`); if the change deserves a release note upstream, add one under `doc/manual/rl-next/` instead. Fix small build or test failures caused by a cherry-picked commit by amending that commit. Mention every such intervention in the Step 5 report. -For a bigger conflict or failure, first investigate whether the change depends on Determinate Nix commits that were never upstreamed. If so, tell the user which commits (and nix-src PRs) they are and why the change needs them, propose upstreaming them as well or first, and wait for the answer. If the problem is something else, for example upstream redesigned the same area, or you are unsure that a resolution preserves the intended behaviour, do not guess: leave things as they are, explain the problem and the options you see, and ask how to proceed. +For a bigger conflict or failure, first investigate whether the change depends on Determinate Nix commits that were never upstreamed. If so, tell the user which commits (and nix-src PRs) they are and why the change needs them, propose upstreaming them as well or first, and wait for the answer. If the problem is something else, for example upstream redesigned the same area, or you are unsure that a resolution preserves the intended behaviour, do not guess: explain the problem and the options you see, and ask how to proceed. -When done, check that nothing Determinate-specific is left in `git -C <worktree> diff origin/master..HEAD`. +When done, check that nothing Determinate-specific is left in the diff against `origin/master`. ## Step 4: Format and run the full tests -Run `nix develop -c ./maintainers/format.sh` in the worktree and fold any changes into the commits that introduced them. Then run `nix build -L .` in the worktree, which also runs the unit and functional tests. This takes a long time; run it in the background and wait for it to finish. +Run `nix develop -c ./maintainers/format.sh` and fold any changes into the commits that introduced them. Then run `nix build -L .`, which also runs the unit and functional tests; this takes a long time, so run it in the background. Handle failures as in Step 3. A failure that also occurs on `origin/master` is not caused by the change; mention it in the Step 5 report and carry on. ## Step 5: Draft the PR description, then stop for review -Write the PR description to a file in the scratchpad directory, starting from upstream's `.github/PULL_REQUEST_TEMPLATE.md` in the worktree: +Write the PR description to a file, starting from upstream's `.github/PULL_REQUEST_TEMPLATE.md` in the worktree: * Put the proposed title on the first line as `Title: ...` so the user can edit it too: the Determinate PR's title, or the commit's subject line. * Motivation: reuse the Determinate PR's own description, or summarise the commit messages if there is no PR. Drop anything that only applies to Determinate Nix or that upstream readers cannot see, such as internal ticket references. End with a link to the source, for example `Taken from https://github.com/DeterminateSystems/nix-src/pull/N.` @@ -89,11 +70,6 @@ Now report to the user and stop. The report must contain: the branch name and wo ## Step 6: After approval, push and create the PR -Re-read the draft file first, since the user may have edited it, and strip the `Title:` line from the body. Then: - -``` -git -C <worktree> push -u origin <branch>:refs/heads/<branch> -gh pr create --repo NixOS/nix --base master --head <branch> --title "<title>" --body-file <body-file> -``` +Re-read the draft file first, since the user may have edited it, and strip the `Title:` line from the body. Push the branch to `origin` and open the PR with `gh pr create --repo NixOS/nix --base master`. -Report the PR URL. Mention that the worktree can be removed later with `git worktree remove <worktree>`. +Report the PR URL. Mention that the worktree can be removed later with `git worktree remove`.