agile-merge-review
Merge plugin (formerly dev-skills) — clears the open-PR queue safely: every PR that lands on main has been rebased, deeply reviewed file-by-file against its Jira ACs, re-verified by a fresh CI run, merged, and closed out in Jira. Uses the gh CLI + git and Jira.
Part of agile-skills. Needs gh + the Atlassian MCP.
Install
/plugin marketplace add cedricfarinazzo/agile-skills
/plugin install agile-merge-review@agile-skills
/reload-plugins
What's in it
| # | Skill | Role |
|---|---|---|
| 11 | agile-11-merge-train | Orchestrator (user-invoked) — processes every open PR sequentially |
| — | merge-update-pr | rebase on main, resolve conflicts, lint-after-rebase, push only if a merge commit was created |
| — | merge-review-pr | deep independent PR review — read every changed file, check vs ACs, verifiable receipt (files-read = diff, cite per lens + AC) |
| — | merge-fix-until-satisfied | fix every finding (Critical + Minor), re-verify, until satisfied (pre-push run id + pushed sha; the caller gates the fresh run) |
| — | merge-jira-postmortem | post structured post-merge comment + transition the Story to Done; return receipt (comment id + done-category) |
The merge-* blocks are unnumbered sub-skills the train composes — each dispatched to its named agile-merge-review:* agent that invokes the sub-skill via the Skill tool and returns a receipt the train verifies; you don't call them directly. Invoke /agile-merge-review:agile-11-merge-train ("merge train", "process all open PRs").
Codex: invoke $agile-11-merge-train. Plugin-local phase agents are Claude Code-only; Codex runs the phase chain inline with concurrency=0 and does not claim named-agent dispatch.
Agents (agents/ dir, one per dispatch point — model/effort scoped to that step's workload):
| Agent | Runs | Model / effort |
|---|---|---|
agile-merge-review:pr-updater | merge-update-pr (3a) | sonnet / low — 3b re-reads every changed file at the reviewed sha, so a bad resolution is caught |
agile-merge-review:pr-reviewer | merge-review-pr (3b) | opus / medium — last read before the base branch; nothing downstream re-reads the code |
agile-merge-review:fix-until-satisfied | merge-fix-until-satisfied (3c) | sonnet / medium |
agile-merge-review:jira-postmortem | merge-jira-postmortem (3g) | sonnet / low — a templated comment + one transition |
Dispatch-and-verify — no shortcuts
The train's main agent orchestrates only: it runs no step's work in its own context. Each per-PR step (3a–3g) runs in its named agent (above) that returns a receipt, and the train verifies it against ground truth (gh / Jira) before advancing. This closes the shortcuts the train is prone to: a shallow review is caught because merge-review-pr's receipt must list a files-read set equal to the PR diff with a file:line cite per lens and per AC; a skipped merge-jira-postmortem is caught because Phase 5 refuses to report a merged PR as Done without a verified postmortem receipt (comment id + done-category) and re-dispatches it. A PR built concurrently (integration-deferred label) has integration + e2e gated by the fresh CI-green run rather than a local re-run. Review and fix converge under a round budget: at most 2 rounds per PR (the full review, then one delta review of the fix), the delta review judges only what the fix changed and is final: an open Critical blocks the PR while remaining Minors merge at the last reviewed-and-green sha and are reported as a follow-up.
Never merge a sha no review has read. 3b reviews the tip as it stood then; 3c then pushes fixes onto it. So 3b records the reviewed sha and 3f asserts the landing tip equals it — a mismatch means the delta is unreviewed (the fixer re-examining its own fix is not an independent gate), so the reviewer is re-dispatched on the delta and the PR re-enters the CI wait. Any PR whose review found something goes through this second review; it is normal flow. That delta review is the last: it judges only what the fix changed, nothing it finds is pushed in this run, an open Critical blocks the PR, and leftover Minors merge and are reported as a follow-up.
A "pre-existing" / "unrelated" / "environment" / "tooling drift" verdict needs base-branch proof. No step may write off a red check by reading its output: run the same command on the base branch, compare exit codes, state the comparison in the receipt. Filenames in the output being untouched by the diff is not evidence — a diff can cause a failure reported against files it never edited. Three triage rules ride with it: isolate the failing item by severity (the error, not the noisier warnings) before diagnosing; treat a SKIPPED job as a symptom and walk the dependency chain to the gate that actually failed; and check reachability before calling an identical repeat failure real — a subtree byte-identical to a base branch where the test is green cannot be the cause, so retry it on an uncontended runner instead.
Review lenses beyond the diff. The reviewer reads every file at the reviewed sha (git show <sha>:<path>), never from a working tree that may be on another branch. It reviews the diff against the ACs, the out-of-scope section, and the documented invariants/conventions — a change that makes a documented invariant false is a defect even when the code is correct, a limitation comment that outlives its limitation is its own defect, and a doc entry is verified accurate rather than merely present. A negative/guard test must be proven to reach the guard it names (not rejected first by an earlier validation layer), and a change labelled "cosmetic" that touches control flow still gets per-branch equivalence proof. A standing convention that conflicts with the ticket's DoD wording becomes a labelled conscious accept in the satisfaction receipt and the postmortem, never a silent deviation.
The per-PR sequence
3a merge-update-pr rebase on main (push only if a merge commit was created)
3b merge-review-pr read every changed file in full, vs the Jira ACs
3c merge-fix-until-satisfied ALWAYS — fix Critical + Minor; satisfaction gate even on a clean review
3d bad-PR escape hatch too broken to fix in one pass → postmortem (blocked), don't merge
3e CI wait fresh, post-rebase green (not "green yesterday")
3f reviewed-sha gate landing tip == the sha 3b reviewed, else re-review the delta → back to 3e
3f gh pr merge --squash --match-head-commit <reviewed sha> verify with `gh pr view --json state,mergedAt` (exit code is not the signal)
3g merge-jira-postmortem comment (opens with the post_merge marker) + transition Done; echoes the collisions it recorded
— branch cleanup end of train, best-effort (a worktree holding a branch is harmless)
One PR at a time — each merge changes main, so the next PR rebases on the new tip and re-runs CI. Cross-PR file collisions are detected up front into a structured conflict_map (per PR: colliding file, other PR, other ticket), passed verbatim into each postmortem dispatch and retro-linked in Jira (relates to) at the end.
Independent review — the second of three layers
merge-review-pr is the independent review by someone other than the author. The implementer already self-reviewed and fixed the obvious in implement-review; this is the authoritative pre-merge gate before code hits main. (The third layer is the global sprint closeout.) Review as a reviewer who didn't write the code — verify against the spec + ADR yourself.
Configuration
Reads the consumer repo's CLAUDE.md / AGENTS.md: cloudId (required), ticket-prefix-regex, done-status-name (+ optional done-transition-id fast path), and lint commands per touched path family.
Where it fits
After agile-execution opens the PRs; before agile-sprint-close. See the full cycle.