Pull Request Skill
Create a draft pull request with a clear title and explicit description of changes, then drive it through CI review rounds to ready.
Instructions
- Analyze branch changes: Understand all commits since diverging from main
- Push to remote: Ensure all commits are pushed
- Create draft PR: Always open as draft for review before merging
- Drive review rounds: trigger CI reviews on the draft and only flip to ready once every verdict is a go (see "Review rounds" below)
PR Title Format
Follow conventional commit format for the PR title:
<type>: <description>
Types
feat: New feature or capabilityfix: Bug fixrefactor: Code restructuringdocs: Documentation changeschore: Maintenance tasksperf: Performance improvements
Title Rules
- Keep under 70 characters
- Use lowercase, imperative mood
- No period at the end
- If
*_ee.rsfiles were modified, prefix with[ee]:[ee] <type>: <description>
PR Body Format
The body MUST be explicit about what changed. Structure:
## Summary
<Clear description of what this PR does and why>
## Changes
- <Specific change 1>
- <Specific change 2>
- <Specific change 3>
## Test plan
- [ ] <How to verify change 1>
- [ ] <How to verify change 2>
The harness/tooling that invoked the skill may add its own attribution trailer; the skill itself does not prescribe one.
Screenshots (required for frontend changes)
If git diff main...HEAD --name-only matches ^frontend/, the PR body must include
screenshots of the affected UI. Skip only when there is no visible UI effect (types,
tests, build config) — and say so in the body.
-
Verify the change in the browser (AGENTS.md → "Verifying Frontend Changes").
-
Screenshot each affected page with
mcp__playwright__browser_take_screenshot(save to a file). -
Host each image and get its Markdown embed by pushing to the public
windmill-labs/agent-screenshots-internalrepo. Pipe base64 through stdin — passing it as-f content=…fails withargument list too longon real images:REPO=windmill-labs/agent-screenshots-internal IMG=screenshot.png # repeat per page DEST="shots/$(git branch --show-current)/$(date +%s)-$(basename "$IMG")" base64 -w0 "$IMG" | jq -Rs --arg m "add $DEST" '{message:$m, content:.}' \ | gh api -X PUT "repos/$REPO/contents/$DEST" --input - >/dev/null echo ""Derive
$DESTfrom the file name (as above) so distinct pages never collide — a fixed name would make same-second uploads reuse one path, and the secondPUTthen 422s (the Contents API needs the existing file'sshato overwrite). -
Put the printed
lines under a## Screenshotsheading in the PR body.
Requires gh (repo scope), jq, base64 — all in the devShell. The host repo is
public (so the raw URLs render for reviewers without a token) and its history is
permanent — never screenshot pages that show secrets or sensitive values (workspace
variables, resource values, instance settings, OAuth/SMTP config); deleting the file
can't undo an accidental capture. (GitHub's drag-and-drop uploader needs a browser
session and can't be driven from a token.)
If gh can't push to the host repo (e.g. a CI token scoped only to windmill), do
not fail the PR or skip silently — hand the upload to the user, who has push access,
and continue once they confirm it's done.
Execution Steps
-
Run
git statusto check for uncommitted changes -
Run
git log main..HEAD --onelineto see all commits in this branch -
Run
git diff main...HEADto see the full diff against main -
Review the diff before creating the PR — run both reviews, do not skip:
local-review— Claude-native branch-diff-reviewer (/local-reviewin Claude Code,$local-reviewin Codex,pi --skill local-review//skill:local-reviewin Pi).local-review-codex— cold Codex pass, the same review CI runs, for an independent perspective the Claude pass misses (/local-review-codexin Claude Code, orbash .agents/skills/local-review-codex/run.sh). If thecodexCLI is missing or older than the version pinned in that skill, note it in your summary and continue — never block the PR on codex being unavailable.
Run both — they catch different things. If either surfaces issues, fix them and commit before proceeding.
-
Screenshots for frontend changes: if
git diff main...HEAD --name-onlymatches^frontend/, capture and embed screenshots of the affected UI per "Screenshots" above before writing the PR body (skip only if there is no visible UI effect). -
Check if remote branch exists and is up to date:
git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null || echo "no upstream" -
Push to remote if needed:
git push -u origin HEAD -
Create draft PR using gh CLI:
gh pr create --draft --title "<type>: <description>" --body "$(cat <<'EOF' ## Summary <description> ## Changes - <change 1> - <change 2> ## Test plan - [ ] <test 1> - [ ] <test 2> EOF )" -
Return the PR URL to the user
-
Drive the PR through CI review rounds to ready (see "Review rounds" below)
Review rounds (draft → ready)
A PR leaves draft only after a clean CI review round. Never run gh pr ready before that.
-
Trigger a round and wait for it: launch the waiter as a background Bash task (a round takes 10–30 min; you are woken when it exits — do not stop the session or poll in the foreground while it runs):
bash .agents/skills/pr/review-round.sh <PR_NUMBER>It comments
/reviewon the PR — which runs the Codex, Claude and Pi CI reviewers even on a draft — waits for the spawnedPR Review Commandsworkflow run(s) to complete, then prints one verdict line per reviewer and saves the full review comments to files. -
Judge the round. Codex is mandatory; Claude, Pi and cubic count whenever they posted. Every review starts with one of the three
REVIEW.mdverdicts:- Codex verdict missing → the round is void: comment
/codexon the PR, wait for it the same way, and judge again. - Any "Should address issues before merging" → fix the P0/P1 findings (and the nits while you're there), commit, push, and start a new round (step 1).
- Only "Mergeable, but should ideally address nits" and/or "Good to merge" → fix the nits too; a nit that is wrong or genuinely not worth fixing may instead be dismissed by replying to the review comment with your reasoning. Push nit-only fixes without starting another full round.
- Codex verdict missing → the round is void: comment
-
Flip to ready with the marker comment. The review workflows skip the redundant
ready_for_review-triggered round when the PR author has posted a marker naming the current head SHA and the PR's latest Codex review posted before the marker has a non-blocking verdict (reviewer evidence — a bare marker with no round behind it, or one whose last pre-marker Codex verdict is "Should address issues", skips nothing). Keep the prefix exact and use the full 40-char SHA of the head you are flipping:-
every verdict was "Good to merge" (head unchanged since the round):
✅ Review round clean @ <head-sha> -
nit-only round, nits fixed or dismissed afterwards (head may have moved past the reviewed SHA — say so):
✅ Review round clean @ <head-sha> — nit-only verdicts at <round-sha>; nits addressed in <commit sha(s)> / dismissed in review replies
gh pr comment <PR_NUMBER> --body "✅ Review round clean @ $(git rev-parse HEAD)" gh pr ready <PR_NUMBER>If any P0/P1 finding is unaddressed or the head moved for reasons other than nit fixes, do not post the marker or flip — run another round instead.
-
EE Companion PR (when *_ee.rs files were modified)
The *_ee.rs files in the windmill repo are symlinks to windmill-ee-private — changes won't appear in git diff of the windmill repo. Instead, check the EE repo for uncommitted or unpushed changes.
Follow the full EE PR workflow in docs/enterprise.md. The key PR-specific details:
- Find the EE repo/worktree: see "Finding the EE Repo" in
docs/enterprise.md - Check for changes:
git -C <ee-path> status --short- If there are no changes in the EE repo, skip this entire section
- Follow steps 1–5 from the "EE PR Workflow" in
docs/enterprise.md - Create the companion PR (title does NOT get the
[ee]prefix):gh pr create --draft --repo windmill-labs/windmill-ee-private --title "<type>: <description>" --body "$(cat <<'EOF' Companion PR for windmill-labs/windmill#<PR_NUMBER> EOF )" - Commit
ee-repo-ref.txtand push the updated windmill branch