Iterate on an open PR's review comments + CI until checks are green and reviewers are satisfied, then hand off to the windowed merge (s6–s12, standalone).
Installs into .claude/skills of the current project.
Are you the author of Keel Pr Loop?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/berkayturanci-keel-pr-loop-voicebridge)
---
name: keel-pr-loop
description: Iterate on an open PR's review comments + CI until checks are green and reviewers are satisfied, then hand off to the windowed merge (s6–s12, standalone).
---
# keel-pr-loop
Use this skill when the user asks to run the keel command `pr-loop` (e.g. `keel pr-loop ...`, `pr-loop <args>`, or `/keel:pr-loop`). It reads every project value from `.keel/project.yaml` via the `keel` CLI.
# /keel:pr-loop
## Live progress — stamp this run (required)
So this run shows live on `keel-visual`'s board, record it with `keel activity` **as you
go**. This command's phases are: `config` → `find` → `open` → `read` → `categorize` → `fix` → `review` → `post` → `recheck` → `collect` → `handoff`. Pick one stable `--run-id` for the whole run
(e.g. `pr-loop-<issue-or-pr>`):
- **Right now, before the work below**, stamp the first phase:
`keel activity .keel/project.yaml --root . --write --command pr-loop --run-id "$RUN" --phase config`
- Re-run with the next `--phase` (`find`, …) **as you advance** through the flow.
- At the end: `keel activity .keel/project.yaml --root . --run-id "$RUN" --done`
Treat this like any other contractual step — do not skip it. The one allowed exception is a
core too old to ship `keel activity` (keel < 1.6.0): then skip it silently and never block
the command.
## Command step evidence
Every numbered step in this command is contractual. Complete the step, record the
evidence it asks for, or explicitly mark it `N/A — <reason>` before moving on. If a step
has an external side effect such as a GitHub comment, issue, review, report, branch, or
PR, the side effect must be posted or written through the selected transport and cited in
the final summary. Never silently skip a step because the runtime, agent, or prompt feels
obvious.
Drive an already-implemented branch from open PR to merge-ready over the fixed keel
backbone (`s6`–`s12`): open the PR, wait for CI, run the review+gate+fix loop, and hand a
clean PR to the windowed, locked merge. **Project-neutral** — every project specific
(`base_branch`, `build_gate_cmd`, `lint_cmd`, `ci_workflows`, `implementer_agents`,
`tier3_globs`, `merge_window`, `merge_window_mode`) is read from `.keel/project.yaml` via
the `keel` CLI. If you are about to type a literal branch name, build command, CI workflow
name, timezone, or agent — stop and read it from config instead.
## Step 0 — Resolve config + plan
```bash
keel validate .keel/project.yaml --root . # abort if config/extensions are invalid
keel plan .keel/project.yaml --root . # the run plan: backbone s6–s12 with this
# project's gates + Lego extensions slotted in
keel plan .keel/project.yaml --root . --command pr-loop --live --json
```
The live plan is the operator-consent preflight. Before pushing, opening/updating a PR,
posting reviews/comments, committing fixes, merging, using secrets, publishing, or calling
production-adjacent systems, parse `contract.operator_consent`; if
`requires_operator_consent` is true, STOP and ask the operator to rerun with the required
`--approve-scope` values. Pass `operator_consent.delegated_agent_scope` into any delegated
review/fix agent brief. Delegates may use only `approved_mutation_scopes`; scope expansion
blocks or escalates.
Read the knobs you will need: `base_branch`, `ci_workflows` (name → path glob),
`build_gate_cmd`, `lint_cmd`, `tier3_globs`, `implementer_agents`, `merge_window`,
`merge_window_mode`.
Resolve GitHub access through the shared runtime contract (`keel capabilities --json` →
`github_transport`). Use the selected transport for all issue/PR/check/comment/review
operations and treat any `github_transport.degraded` operation as an explicit limitation.
Do not duplicate a local `gh` vs MCP capability table in this adapter.
## Step 1 — Find the PR
- If a PR number is given as `$1`, use it. Otherwise auto-detect the open PR for the
current branch through the selected GitHub transport (the first open PR whose head is
the current branch).
- If no PR exists for the current branch, halt and report — do not proceed.
- **Workspace isolation:** this command runs `git commit` / `git push` against the working
tree, so it MUST run from a **linked worktree**, never the user's primary checkout.
Detect with `git rev-parse --git-dir`: the primary checkout returns `.git`; a linked
worktree returns an absolute path containing `/.git/worktrees/<name>`. If the value is
`.git`, ABORT and tell the user to re-run from the PR's worktree (`git worktree list`).
If this command must create the worktree for the PR, use the project's nested convention
(project-specific path layout; stays in the project) — never the user's primary tree.
## Step 2 — Open / confirm the PR (s6 entry)
Push the branch and open the PR against `base_branch` if it is not open yet. Otherwise
push any local commits so the PR head matches your working tree.
## Step 3 — Read everything
Gather the full PR state before deciding anything:
- The conversation timeline (issue-level comments).
- The inline review-comment threads (`file:line` anchored).
- Reviews + the overall review decision.
- The last few CI runs for the branch and their status/conclusion per workflow in
`ci_workflows`.
- If CI is failing and `raw_actions_logs` is supported, fetch the failed-run log (tail it)
so fixes are evidence-based. If raw logs are degraded, quote the check name/details URL
and reproduce locally; do not imply raw-log access was available.
## Step 4 — Categorize feedback
Group every review comment into:
- **Must-fix** — correctness, security, data-safety, and any project-defined
high-risk rules (the tier-3 areas implied by `tier3_globs`).
- **Should-fix** — style, naming, performance.
- **Skip** — opinion differences / wontfix (record the reason).
- **Reply-only** — questions needing a text reply, not a code change.
## Step 5 — Fix and reply (s9 fix loop)
For each must-fix and should-fix, smallest change first:
1. Read the relevant source file.
2. Make the minimal, targeted fix.
3. Run the relevant gates locally: `keel run-gates .keel/project.yaml --root .` (executes
the project's `build_gate_cmd` / `lint_cmd` and any `tester` Lego; critical/major =
block, minor = suggest, nit = advisory).
4. Commit with a clear message (e.g. `fix: address review comment — <short description>`).
Reply to reply-only comments with a text answer; note skipped comments with the reason.
## Step 6 — Self-review before push (mandatory)
Read the full diff against `base_branch` (`git diff origin/<base_branch>...HEAD`) top to
bottom and verify:
- **Scope** — only files within the issue / CI-fix scope changed.
- **Security** — no injection, secrets, or hard-coded credentials introduced.
- **Dead code / stale refs** — no leftovers from deleted or moved code.
- **CI prediction** — for every changed file, answer "what would make CI fail here?"
- **Test coverage** — changed logic has new or existing test coverage.
If self-review finds a problem (out-of-scope change, security risk, CI risk) → return to
Step 5, fix, re-commit, then restart Step 6.
## Step 7 — Push
`git push`. (Under `--dry-run`, log `DRY-RUN: git push` and do not push.)
## Step 8 — Review + gates (s7) — required after every code-change push, CI fixes included
Run **N reviewers** (host agent, or the agent from `--review-delegate`) plus any
`reviewers` Lego extensions. Spawn them in **parallel** in a single Agent-tool message;
give each a fresh codename and the no-cross-reading instruction (a reviewer must never read
another reviewer's output). Each reviewer verifies it is reviewing the **PR head SHA**,
returns structured findings only (severity + `file:line`), and does **not** call any
GitHub write API — this command (the orchestrator) posts. Reviewer count and focus split
follow the project's risk tier from `keel ship`; reviewers draw their rubric (severity
vocabulary, PR-head-SHA verification, return format) from the canonical reviewer rubric,
not from inline heuristics here.
Then run `keel run-gates .keel/project.yaml --root .` (build / lint / **jury** / tester) so
gate findings join the reviewer findings on the same severity scale.
## Step 9 — Post findings (per `--review-comments`, inline-hybrid default)
- **inline** (default): anchor every **critical/major** finding as an inline comment on its
`file:line`, plus a single summary comment. critical/major = **block**; minor = **suggest**;
nit = **advisory**.
- **summary**: post one consolidated comment with all findings in a severity table.
## Step 10 — Re-check CI
Wait for the workflows in `ci_workflows` to go green (`gh pr checks`). Re-kick transient
failures; surface real ones (re-enter Step 5 with the failed-log evidence). Do **not**
advance to the close-out while CI is red.
## Step 11 — Collect findings and close the loop
- **Blocking finding (critical/major) remains** → return to Step 5, fix, re-commit, then
re-run Steps 6 → 7 → 8 → 9 → 10 → 11.
- **No blocking findings AND every suggestion either applied or explicitly user-deferred
(recorded as a tracked issue AND surfaced to the user) AND CI green** → exit the loop.
Nits SHOULD be applied where reasonable; an unapplied nit is noted but does NOT gate exit.
- Cap the fix rounds at the project's round budget (≤3 by default); if the budget is spent
with blockers remaining, stop and report the verdict rather than forcing a merge.
CI green is required on **every** exit path. Never exit this loop with CI red.
## Step 12 — Summary + handoff
Post one summary comment on the PR listing: what was addressed (with file refs), what was
intentionally skipped and why, and the per-reviewer verdicts. Then hand the clean PR to the
windowed, locked merge:
```bash
keel ship .keel/project.yaml --root . --pr <N> # confirm the decision is MERGE
```
The actual **s10 merge** happens only inside the merge window (`keel window`), holding the
merge lock, after a final re-confirm of green CI + zero blocking findings → squash-merge;
then capture the run (for `/keel:wrap`), close the linked issue, and drop the lock. Outside
the window, `merge_window_mode` decides: `pause` halts, `freeze` defers.
## Invariants (never overridable)
merge lock · night no-merge window · fail-soft (a soft gate/extension failure degrades to a
no-op, never aborts) · orchestrator-only-writes (reviewers return findings; this command
posts them) · vendor+model attribution.
## `--dry-run`
Do every read plus `keel validate` / `keel plan` / `keel run-gates`, but redirect every
state-changing `git`/`gh` write to a logged `DRY-RUN: <action>` line. No push, no PR, no
merge.
<!-- keel-generated: surface=skills command=pr-loop keel_version=1.6.5 source_sha256=bd1c409c0142bb4b829563c0daba47704b80b348009100400a8d80fc40077c10 generated_sha256=c155feb758770d85c4a79353b03a55b4b8584f79fc9944dfedc5a8b75627a80c -->