CommunityCoding & Developmentgithub.com

land-renovate

Batch-land open Renovate PRs in the current repo. Enumerate Renovate-authored PRs, classify each as GREEN / CONFLICTING / REAL_FAILURE / HOLD, approve and rebase-merge the safe ones in ascending PR-number order, nudge conflicting ones with the rebase checkbox, and stop cleanly on real failures or cross-file HOLD cases. Use when the user says "/land-renovate", "land the Renovate PRs", "clear the Renovate queue", or wants to merge a batch of dependency-update PRs.

What is land-renovate?

land-renovate is a Claude Code agent skill that batch-land open Renovate PRs in the current repo. Enumerate Renovate-authored PRs, classify each as GREEN / CONFLICTING / REAL_FAILURE / HOLD, approve and rebase-merge the safe ones in ascending PR-number order, nudge conflicting ones with the rebase checkbox, and stop cleanly on real failures or cross-file HOLD cases. Use when the user says "/land-renovate", "land the Renovate PRs", "clear the Renovate queue", or wants to merge a batch of dependency-update PRs.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/langri-sha/skills/tree/main/land-renovate

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

What does land-renovate do?

Walk the queue of open Renovate PRs in the current repo and land the safe ones: enumerate, classify, approve + rebase-merge in ascending PR-number order, nudge the rest with the rebase checkbox, and stop cleanly on real failures or HOLD cases.

This operates entirely on existing remote PRs through gh. It does not call /create-commit, /create-pr, or /wrap, and it does not author local commits.

Arguments

ArgumentDefaultDescription
limit=N30Cap how many PRs to walk.
<pr-number>...all Renovate-authored open PRsSpace-separated PR numbers; operate only on those.

Defaults: current repo (from gh repo view --json nameWithOwner), Renovate-authored open PRs, ascending PR-number order, no label filter.

Workflow

1. Resolve the repo

REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)

2. Enumerate Renovate PRs

List open Renovate-authored PRs, oldest (lowest number) first:

gh pr list -R "$REPO" --author "app/renovate" --state open --limit 30 \
  --json number,title,mergeable,mergeStateStatus,statusCheckRollup

Sort ascending by number and walk them in that order. If explicit PR numbers were passed as arguments, restrict the set to those.

Note: gh pr list often returns mergeable: UNKNOWN because GitHub computes mergeability lazily. A gh pr view <n> --json mergeable on a single PR forces the computation. When a PR's mergeable is UNKNOWN, re-read it with gh pr view before classifying.

3. Classify each PR

Bucket each PR using statusCheckRollup + mergeable + mergeStateStatus:

BucketSignalAction
GREENno FAILURE/CANCELLED/TIMED_OUT in rollup, nothing pending, mergeable=MERGEABLEapprove + rebase-merge (step 4)
CONFLICTINGmergeable=CONFLICTING or mergeStateStatus=DIRTYtick the rebase checkbox (step 5), monitor
REAL_FAILURErollup contains a FAILURE not auto-fixable by post-upgradeskip; leave for human triage
HOLDcross-file coordination needed (manual checklist — see below)surface for human; do not proceed

A check in the rollup is pending when a CheckRun has status != COMPLETED or a StatusContext has state of PENDING/EXPECTED. It is a failure when a CheckRun.conclusion is FAILURE/CANCELLED/TIMED_OUT/ ACTION_REQUIRED/STARTUP_FAILURE, or a StatusContext.state is FAILURE/ ERROR.

HOLD checklist (manual — not hard-coded)

HOLD detection is a judgement call the agent makes, not an automated rule. Treat a PR as a HOLD candidate when landing it in isolation would break something that lives in another file, for example:

  • terraform-version pin mismatch — a Terraform provider/CLI bump that needs a matching pin updated elsewhere (e.g. .terraform-version, CI workflow, or a required_version constraint) before it is safe.
  • schema bumps requiring code edits — a dependency upgrade whose new major changes a schema/type that hand-written code still depends on; the post-upgrade hooks can't generate the code edit.
  • any upgrade whose changelog calls for a coordinated edit the post-upgrade job won't perform.

When a PR looks like a HOLD, surface it and ask the user — do not auto-merge and do not tick the rebase checkbox. Keep walking the rest of the queue.

4. Approve + merge (GREEN)

gh pr review "$PR" -R "$REPO" --approve \
  --body "LGTM — auto-approved as part of Renovate batch landing."
gh pr merge "$PR" -R "$REPO" --rebase --delete-branch

5. Tick the rebase checkbox (CONFLICTING)

Flip Renovate's rebase checkbox so it rebases the branch, then monitor:

body=$(gh pr view "$PR" -R "$REPO" --json body -q .body)
new=$(printf '%s' "$body" | sed 's|^\( *\)- \[ \] <!-- rebase-check -->|\1- [x] <!-- rebase-check -->|')
printf '%s' "$new" | gh pr edit "$PR" -R "$REPO" --body-file - >/dev/null

Capture the current head SHA as the baseline before ticking the box, then run the monitor (step 6) so you can tell the rebase apart from the state you started from:

BASELINE=$(gh pr view "$PR" -R "$REPO" --json headRefOid -q .headRefOid)

Never tick the rebase checkbox on a REAL_FAILURE — it wastes Renovate cycles and hides the real problem.

6. Monitor until settled

The bundled scripts/monitor-renovate-pr.sh polls a single PR until its checks settle and prints a verdict the agent consumes via the Monitor tool.

scripts/monitor-renovate-pr.sh <pr-number> <repo> <baseline-head-sha-short>
  • Polls gh pr view --json headRefOid,mergeable,mergeStateStatus,statusCheckRollup every 45s (POLL_INTERVAL override) and prints a line only when the signature ${head:0:9}|<mergeable>:<state>|ok=N pend=M fail=K changes.
  • Emits a verdict once the head has moved off the baseline, no checks are pending, and the signature is stable across two consecutive polls.
  • Final stdout line is one of:
    • GREEN: #<n> ready to merge → go back to step 4 and approve + merge.
    • NOT-GREEN: #<n> settled failures=X mergeable=Y state=Z → re-classify; it is now a REAL_FAILURE or HOLD.
  • Optional env: POLL_INTERVAL (seconds, default 45), MAX_POLLS (give up after N polls, 0 = unlimited; on exhaustion emits NOT-GREEN: #<n> timeout ...).

Why a poll loop and not gh pr checks --watch

gh pr checks <n> --watch is fine for a PR that is already mergeable and just has checks running, but it actively misleads on the rebase path this skill exists for:

  • It exits green on the stale head. Right after the rebase checkbox is ticked, the PR's current checks are already terminal — they passed on the pre-rebase (conflicting) head. --watch sees "no pending checks" and returns success immediately, before Renovate has even rebased. The head moved off baseline condition is exactly what guards against that false-green.
  • It only knows checks, not mergeability. The GREEN verdict needs mergeable=MERGEABLE + mergeStateStatus=CLEAN, and CONFLICTING is detected via those fields — which gh pr checks never reports. A single gh pr view poll covers both in one shot.
  • The head can move twice (Renovate push, then the app-bot post-upgrade push). There is a window between them where the known checks are momentarily complete; --watch can exit in that gap. The "no pending and stable for two polls" guard rides past it.

7. Expected post-rebase commit chain

After the rebase checkbox is ticked (or Renovate rebases on its own), a GREEN landing typically flows through this chain — knowing it tells you the monitor's churn is expected, not a failure:

  1. Renovate pushes a new head as renovate[bot].
  2. pull_request workflows fire. check.yml's post-upgrade step runs eslint --fix, prettier --write, vitest --update, projen, and a beachball change entry.
  3. If the post-upgrade step produced a diff, the commit-upgrade-changes job mints an App token via actions/create-github-app-token@v2 and pushes the fix as <app-slug>[bot]. That bot push re-triggers the pull_request workflows, so the head moves a second time and checks re-run.
  4. Final ready state: mergeable=MERGEABLE, mergeStateStatus=CLEAN, all checks SUCCESS/SKIPPED.

Because the head can move twice (Renovate, then the app bot), the monitor keys its verdict on "head moved off baseline + no pending + two stable polls" rather than the first push it sees.

Stopping conditions

  • No GREEN PRs remain — done.
  • REAL_FAILURE — skip it, continue with the next PR; never auto-rebase a REAL_FAILURE.
  • HOLD candidate — surface it for a human decision; do not auto-merge.
  • User cancels.

Constraints

  • Commit subjects must not contain issue/PR refs (project rule). Not applicable to merging remote PRs here, but if this skill is ever extended to author a local commit, keep refs out of the subject — put them in the body. See /create-commit.
  • Never tick the rebase checkbox on a REAL_FAILURE.
  • Never auto-merge a HOLD candidate.
  • HOLD detection is a manual checklist, not a hard-coded rule. Recognize the categories above and surface candidates; don't try to automate the decision.

Testing notes

Dry-run classification

Enumerate and eyeball the buckets without touching anything:

gh pr list -R "$REPO" --author "app/renovate" --state open \
  --json number,title,mergeable,mergeStateStatus,statusCheckRollup \
  | jq -r '.[] | "\(.number)\t\(.mergeable)\t\(.mergeStateStatus)\t\(.title)"'

Add a rollup summary per PR to spot pending/failed checks:

gh pr list -R "$REPO" --author "app/renovate" --state open \
  --json number,statusCheckRollup \
  | jq -r '.[] | "\(.number)\t" + ([.statusCheckRollup[] | .conclusion // .state] | join(","))'

Monitor smoke test

Run the monitor against a known PR with a fake baseline SHA (so the head already counts as "moved") and a short interval to watch the state lines and the final verdict:

POLL_INTERVAL=2 MAX_POLLS=4 \
  scripts/monitor-renovate-pr.sh <known-pr> "$REPO" deadbeef0

You should see one state line per signature change, then a GREEN: / NOT-GREEN: verdict. Passing the PR's real head as the baseline instead exercises the no-rebase path: the head never moves, so it never settles and the run ends on the MAX_POLLS timeout.

Out of scope

  • Hard-coded HOLD detection rules (start as the manual checklist above; extend later).
  • Wiring this skill into any orchestration layer.

Related Skills