Install
openclaw skills install @arunjeetsingh/open-prBuild, validate, and open a review-ready PR
openclaw skills install @arunjeetsingh/open-prTake the requested change from the user's message (or $ARGUMENTS on hosts that
substitute it). If it is not explicit, ask what to build before touching anything.
This is the front half of the loop. The back half is address-review-comments for the
PR number; this skill ends by handing off to it.
Invoking this skill authorizes it to take the following actions without pausing for a
per-step confirmation, as part of its normal, disclosed workflow: push a new branch to
the remote, open a pull request, and arm a background watch (see ../WAITING.md) that
later invokes address-review-comments on your behalf when a reviewer responds. If your
environment expects a human to confirm before code leaves the local machine, gate that at
the point you invoke this skill — do not invoke it unless you intend for a PR to actually
be opened. It never merges and never deploys (see below), and it never modifies a branch
or checkout you did not create in Step 1.
gh pr merge.git add/git commit in one shell
command. A failed edit must not let a commit of partial state through.Resolve the repository from the checkout that invoked you — never a hard-coded path. This skill lives in the repo, so a hard-coded path would send a fresh clone's fetches, branches and pushes into somebody else's checkout, or fail outright when it is absent.
Each shell call runs in a fresh process on most hosts, so nothing set here reliably
survives into later steps. Every later block re-derives what it needs from $NAME, which
is the one thing you carry in your head. Pick it once:
set -euo pipefail
NAME=gate # short, no slashes -> the directory wt-$NAME
BRANCH=fix/release-gate # the PR branch
REPO=$(git rev-parse --show-toplevel) # the checkout this skill was invoked from
SCRATCH="${TMPDIR:-/tmp}/openpr-$NAME"; mkdir -p "$SCRATCH"
git -C "$REPO" fetch origin
git -C "$REPO" worktree add "$REPO/../wt-$NAME" -b "$BRANCH" origin/main
cd "$REPO/../wt-$NAME"
Then work only in that worktree. Never git checkout or git switch in the
invoking checkout, whoever it belongs to: it may be somebody's live desk with
uncommitted work. Doing that once moved a live checkout onto a branch mid-session and
interleaved its owner's uncommitted work with new edits in the same files, so every
validation run exercised half-finished code that was not the change under test.
Three sibling traps, each hit for real:
git worktree add -f <dir> <branch> on a branch that is already checked out.
The -f defeats the "already checked out" refusal and both worktrees then share ONE
branch ref, so a merge in the scratch tree silently advances the real branch. To
trial-merge, use a throwaway: git worktree add -b trial/<name> "${TMPDIR:-/tmp}/wt-trial" <branch>, then
git worktree remove --force and git branch -D.ps -eo pid,ppid,etime,command and
confirm the --path/cwd is a worktree you created this session. A long runtime is not
evidence of an orphan.Write code that reads like the code around it — match its comment density, naming and idiom. Then:
Mutation testing is the bar. No guard counts until its defect is reintroduced and the guard is observed going red ON ITS OWN TARGETED ASSERTION. A test that passes proves nothing about a guard; a mutation that turns it red does.
Sharp edges, all of which have cost real time on repos this skill has run against:
HANG as its own outcome (it is neither a pass nor a proper red), and kill the whole
process group (start_new_session=True + os.killpg) or child processes outlive the
harness. Set sys.stdout.reconfigure(line_buffering=True) in any Python harness or a
backgrounded run looks stalled and empty.*.bak beside the source; the
mutated file is left in place.Run the full suite set for whatever you touched. Prove any local dependency you started (e.g. a database replica) is the one you're actually talking to — ports collide across sessions.
Run the same four-lens audit the review skill uses, adversarially verified (a separate skeptic per finding, defaulting to "not real" when uncertain): internal consistency; regression against anything this change touches; staleness and incompleteness; and a platform fact-check with web access for every claim this change makes about a third-party platform, API, or store.
A wrong platform fact is a blocker, not a P2 — it cannot work as written. Never assert third-party behaviour from memory; if you cannot verify it, say so in the text and route it to P2 rather than stating it.
Wait for verification to finish before committing. Raw per-lens findings arrive long
before adversarial skeptics do and look complete. Acting on a first lens before the
skeptics land has cost a public correction on real PRs; the rule is results >= agents,
then commit.
Two mechanical checks before you push, both of which have shipped to a reviewer on real runs:
git diff | grep -n "\\\\'\|'\"'\"'" — empty is the only acceptable result. \' inside
a <<'PY' heredoc writes a literal backslash into the file.The body is the deliverable a reviewer reads first. Use this shape, dropping sections that genuinely do not apply:
Write it to a file in the scratchpad and open with --body-file; these bodies are long
and shell-quoting them corrupts them.
set -euo pipefail
NAME=gate # the same NAME as Step 1
BRANCH=fix/release-gate # the same BRANCH as Step 1
SCRATCH="${TMPDIR:-/tmp}/openpr-$NAME"
# RE-ENTER THE WORKTREE FIRST. This block is a fresh shell, so it starts wherever the skill
# was invoked — which is the checkout Step 1 went out of its way not to touch. `git push -u
# origin HEAD` from there pushes THAT checkout's current branch, and `gh pr create` opens a
# PR for it: somebody else's live desk, published under your title. Assert, don't assume.
REPO=$(git rev-parse --show-toplevel)
cd "$REPO/../wt-$NAME"
[ "$(git rev-parse --abbrev-ref HEAD)" = "$BRANCH" ] || {
echo "expected $BRANCH in wt-$NAME, found $(git rev-parse --abbrev-ref HEAD)" >&2; exit 1; }
# Push second: with no TTY, `gh pr create` aborts on an unpushed branch rather than
# offering to push it.
git push -u origin HEAD
PR_URL=$(gh pr create \
--title "Release gate: prove every capability this checkout needs, not just L1" \
--body-file "$SCRATCH/pr_body.md")
# Guard the capture: a failed create prints nothing, and an empty PR_NUM would make
# Step 6 silently watch whatever PR gh resolves from the branch instead.
PR_NUM=${PR_URL##*/}
[[ "$PR_NUM" =~ ^[0-9]+$ ]] || { echo "gh pr create did not return a PR URL" >&2; exit 1; }
echo "$PR_NUM" > "$SCRATCH/pr_num"
echo "opened #$PR_NUM at $PR_URL"
Titles read like the commit log: an area prefix, then the change in the imperative — not
the ticket, not the mechanism. Bus horn: successive blasts walk all three horns, E2E: seed bus_horns so L8's preservation check stops comparing 0 with 0.
End the body with a line crediting the tool/runtime that generated it (e.g. 🤖 Generated with Claude Code / Codex / OpenClaw), matching whichever is actually running this
skill.
Arm a watch for the reviewer's first batch by default. Skip it only when the user says so for this PR. One watch per PR; do not layer a second polling mechanism on top of it.
Wait the way ../WAITING.md prescribes for your host (OpenClaw cron gate, Claude
Code Monitor, or Codex heartbeat) — the cheapest mechanism your runtime supports, so the
watch costs as little as possible while the PR is quiet. That file carries the loop, the
filter-on-content rule (the reviewer may post under the same account as the author, so an
author filter wakes on your own replies), the filter-verification step, and the
emit-on-terminal-state rule. It also carries the exact per-host arm/find/stop mechanics —
do not restate them here.
Resolve PR and REPO before arming — a watch may inherit nothing from the session that
armed it, so bind them into the watch's own command/prompt rather than assuming context:
set -euo pipefail
NAME=gate # the same NAME as Step 1
SCRATCH="${TMPDIR:-/tmp}/openpr-$NAME"
PR=$(cat "$SCRATCH/pr_num") # written by Step 5
REPO=$(gh repo view --json nameWithOwner --jq .nameWithOwner)
[[ "$PR" =~ ^[0-9]+$ ]] || { echo "no PR number in $SCRATCH/pr_num" >&2; exit 1; }
echo "arm watch with: PR=$PR REPO=$REPO MARKER='<!-- review-pr-state'"
The marker is the HTML comment, not the bare string: only the reviewer writes
<!-- review-pr-state ... -->, while the bare word appears in any reply that discusses
the watch — including yours, which is how this watch has previously spent rounds waking
on its own comments. No EXCLUDE here, because reviewer batches are exactly what this
direction waits for.
Keep whatever identifier your host's arming call returns. It is what stops the watch later, and it is how you tell "already watched" from "arm a second watch on the same PR".
If no watch mechanism is available on this host, say so and leave watching manual. Do
not substitute a raw sleep loop, a cron workaround with no predicate, or a background
process you can't account for later, and do not report the loop as armed when it is not —
an unarmed watch that is believed is worse than none, because nobody goes looking.
When it fires, go to Step 7. Then report: the PR number and link, what it does, what you proved and what you did not, anything that needs a decision, the deploy steps if any, and whether the watch is armed or could not be, and whether it survives the session ending on this host. Then stop — no polling on top of it.
When the repo owner says a review batch has landed (or the watch fires), run
address-review-comments for that PR. That skill owns everything from there: the
loop-state decision, the fixes, its own pre-commit audit, one commit and one reply per
round.
Two things that come back to this skill rather than that one:
CONFLICTING, merge
origin/main into the branch (never rebase a branch the reviewer has commented on, and
never gh pr merge). Check any repo-specific docs about known conflict-prone files
before resolving by hand — some tables/rows are designed to be composed, not chosen.
Prove the result both ways: it must equal theirs plus exactly your edits, and equal
yours plus exactly their edits.gh pr view <n> --json baseRefName before describing someone else's work as external to yours.