Install
$ agentstack add skill-lifecycle-innovations-limited-claude-ops-ops-merge ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Runtime Context
Before executing, load:
- Preferences:
cat ${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json— readowner,timezone, project registry - Daemon health:
cat ${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json— ifaction_neededset, surface to user - Secrets: GitHub token: env
$GITHUB_TOKEN→ Doppler MCP (mcp__doppler__*) →doppler secrets get GITHUB_TOKEN --plain→ password manager
OPS ► MERGE
CLI/API Reference
gh CLI (GitHub)
| Command | Usage | Output | | ------------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------ | | gh pr list --repo --json number,title,state,headRefName,statusCheckRollup,reviewDecision,mergeable,isDraft | List PRs with status | JSON array | | gh pr view --repo --json title,body,state,mergeable,reviews | PR details | JSON | | gh pr checks --repo | CI check status | Check list | | gh pr merge --repo --squash --admin | Squash merge PR | Merge result | | gh pr create --repo --title "" --body "" --base dev | Create PR | PR URL | | gh run list --repo --limit 5 --json conclusion,name,headBranch | CI runs | JSON array | | gh run view --repo --log-failed | Failed CI logs | Log output | | gh run watch --repo | Stream CI run | Live output (use with Monitor) | | gh api repos//pulls//comments --jq '.[].body' | PR review comments | Comment text |
Agent Teams support
If CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 is set, use Agent Teams for fixer agents (Phase 3). This enables:
- Steering fixers mid-flight if priorities change (e.g., a critical PR should be merged first)
- Fixers can report blockers and you can redirect them without waiting for completion
- Shared context: if fixer-A discovers a breaking change that affects fixer-B's PR, you can notify B
Team setup (only when flag is enabled, Phase 3):
TeamCreate("merge-fixers")
Agent(team_name="merge-fixers", name="fixer-[repo]", ...)
Use SendMessage(to="fixer-my-api", content="PR #2958 was just merged — rebase your branch") to coordinate.
If the flag is NOT set, fall back to standard parallel subagents with isolation: "worktree".
Pre-gathered PR data
```! ${CLAUDEPLUGINROOT}/bin/ops-merge-scan 2>/dev/null || echo '{"prs":[],"error":"merge-scan failed"}'
## Pre-gathered salvage data (orphan worktrees, branches without PRs, uncommitted/unpushed work)
```!
${CLAUDE_PLUGIN_ROOT}/bin/ops-merge-salvage-scan 2>/dev/null || echo '{"repos":[],"error":"salvage-scan failed"}'
Your task
You are the merge orchestrator. Your job is to get every open PR across the owner's repos merged — fixing whatever blocks them first.
Parse arguments
From $ARGUMENTS:
--main→ after all PRs merge to dev, also sync dev↔main for repos that have both branches--repo→ scope to one repo only (e.g.,--repo your-org/my-api)--dry-run→ report what would happen, don't dispatch agents or merge anything--force→ skip the confirmation prompt before merging--no-salvage→ skip Phase 0 (Salvage). Behaves like the legacy PR-only pipeline.--salvage-only→ run Phase 0 only and stop. Useful for "find and finish all loose local work" without touching the existing PR queue yet.- (empty) → process all repos: salvage local work first, then merge PRs to dev only
Phase 0 — Salvage scan (run BEFORE the PR queue)
Goal: every repo in every org gets a clean slate before the PR merge pipeline runs. Find and finish every piece of local work that isn't already on dev/main and isn't already in an open PR — orphan worktrees, feature branches without PRs, uncommitted/staged/stashed changes, and unpushed commits.
Skip this phase only if --no-salvage is set.
Parse the JSON returned by ops-merge-salvage-scan. For each repo with has_salvage: true, classify each finding into one of:
| Finding | Classification | Action | | ------------------------------------------------------------------ | ----------------------- | -------------------------------------------------------------------------------------------------- | | Worktree with dirty_files > 0 or unpushed_commits > 0 | worktree-incomplete | Dispatch salvager: finish work in the worktree, commit, push, open PR if missing | | Worktree on a branch with has_open_pr: false | worktree-orphan-pr | Dispatch salvager: confirm work is complete (lint/type/test gate), push if needed, open PR | | Local branch with integrated: false and has_open_pr: false | branch-no-pr | Dispatch salvager: review state, push if unpushed, open PR targeting integration branch | | Local branch with integrated: true and has_open_pr: false | branch-already-merged | Surface to user → [Delete local branch] / [Keep] (NEVER auto-delete — Safety Rails) | | Main checkout: dirty_files > 0 or staged_files > 0 or stash >0 | checkout-dirty | Surface to user → [Stash & continue] / [Open salvage worktree] / [Skip]. Never auto-discard. | | Main checkout: unpushed_commits > 0 on a non-integration branch | checkout-unpushed | Dispatch salvager: push the branch, open PR if missing |
Print the salvage queue:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OPS ► MERGE — Phase 0: Salvage Queue
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| Repo | Location | Branch | State | Classification | Action |
|------|----------|--------|-------|----------------|--------|
| my-api | .worktrees/feat-x | feat/x | 3 dirty, 2 unpushed | worktree-incomplete | salvage |
| my-app | (main checkout) | feat/y | 5 unpushed, no PR | checkout-unpushed | salvage |
| mise | refs/heads/old-experiment | old-experiment | integrated, no PR | branch-already-merged | confirm delete |
| ... | ... | ... | ... | ... | ... |
Salvageable: N | Needs user input: N | Clean: M
──────────────────────────────────────────────────────
If --dry-run, print the queue and stop here (skip Phase 1+). If --salvage-only, run the salvage dispatch loop below, then stop (skip Phase 1+).
Confirmation gate: unless --force, use AskUserQuestion (max 4 options — Plugin Rule 1) to confirm before dispatching salvagers:
N pieces of loose local work found across M repos.
[Salvage all N — dispatch agents] [Let me pick which ones] [Skip Phase 0 — go to PR queue] [Abort]
Dispatch salvager subagents (max 5 concurrent, one repo per agent — never share the main checkout per CLAUDE.md worktree isolation rule). Use subagent_type: "general-purpose" for now (or a future salvage-fixer agent if one exists). Each salvager gets this brief:
Task: Finish and PR loose local work in
Repo path:
Findings:
- : —
- ...
Worktree isolation: if the work lives in an existing .worktrees/* dir, work IN that directory.
If the work lives only on a local branch (no worktree), create one:
git -C worktree add .worktrees/salvage-
For each finding:
1. cd into the worktree.
2. Inspect state: `git status`, `git log ..HEAD --oneline`, `git diff --stat`.
3. Read recent commit messages + any TODOs/HEREs in the diff. Decide whether the work is:
(a) complete and just needs commit/push/PR — proceed
(b) incomplete but obvious next step — finish it
(c) ambiguous or risky → ABORT this finding and return it for human review.
4. If finishing work: make the smallest correct commit. Quality gate locally
(per-repo: type-check + lint + relevant tests).
5. Commit with a clear message. NEVER use --no-verify unless a hook is genuinely
broken and unrelated to your change.
6. Push: `git push -u origin ` (or `--force-with-lease` if branch already remote).
7. Open PR (only if has_open_pr=false in the brief):
gh pr create --repo --base --head \
--title "" \
--body "Salvaged by /ops:merge Phase 0. "
8. Return structured JSON:
{
"repo": "...",
"branch": "...",
"status": "pr_opened" | "pushed_only" | "aborted_for_review" | "failed",
"pr_number": ,
"pr_url": "",
"end_sha": "",
"notes": "..."
}
DO NOT call `gh pr merge` — newly opened PRs flow through Phase 1+ like any other PR.
DO NOT delete branches, worktrees, or stashes. Salvage = finish + PR, never destroy.
DO NOT touch files outside the assigned worktree.
After all salvagers return: re-run ops-merge-scan so the freshly opened PRs join the Phase 1 queue. Surface any aborted_for_review findings to the user with a brief explanation and [Open in editor] / [Skip] options.
Branches classified branch-already-merged and checkout-dirty are surfaced one-by-one to the user via AskUserQuestion (never auto-handled — see Safety Rails).
Phase 1 — Classify the PR queue
Parse the pre-gathered JSON. For each PR, it's already classified as one of:
| Classification | Meaning | Action | | ----------------------- | ----------------------------------------------------------------- | ------------------------------------------- | | ready | CI green, approved, no conflicts | Merge immediately | | needs-rebase | mergeable: CONFLICTING | Dispatch fixer: rebase on base branch | | needs-ci-fix | CI failures in statusCheckRollup | Dispatch fixer: investigate logs, fix, push | | needs-review-response | reviewDecision: CHANGES_REQUESTED | Dispatch fixer: resolve comments | | blocked | mergeStateStatus: BLOCKED (branch protection, required reviews) | Note why, skip | | draft | isDraft: true | Skip — not ready for merge |
Print the queue:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OPS ► MERGE — PR Queue
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| Repo | PR | Title | Status | Action |
|------|----|-------|--------|--------|
| my-api | #2958 | fix(migration) | ready | merge |
| my-app | #4456 | feat(apple-04) | needs-ci-fix | dispatch fixer |
| ... | ... | ... | ... | ... |
Ready: N | Fix needed: N | Blocked: N | Draft: N
──────────────────────────────────────────────────────
If --dry-run, stop here. Print the queue and exit.
Phase 2 — Confirm and merge ready PRs
Unless --force was passed, use AskUserQuestion to confirm before merging:
Ready to merge N PRs:
[repo]#[number] — [title] → [base]
[repo]#[number] — [title] → [base]
[Merge all N now] [Let me pick which ones] [Dry run — don't merge]
If user picks "Let me pick", show each PR with [Merge] / [Skip] options via AskUserQuestion.
For each confirmed PR:
- Verify CI is still green:
gh pr checks --repo - If green:
gh pr merge --repo --squash --admin - Report:
✓ Merged # to
Phase 3 — Dispatch fixers for PRs that need work
HARD RULE: Fixers do NOT merge. The orchestrator merges in Phase 5 after independent verification.
Background: on 2026-05-11, sixteen parallel pr-ci-fixer spawns fabricated complete transcripts including conflict resolutions, CI polling sequences, and gh pr merge admin outputs with invented merge SHAs. Zero merges actually executed. The fix is structural: fixers no longer have merge authority OR self-reporting authority on merge state. They push, the orchestrator verifies the push and merges.
For PRs classified as needs-rebase, needs-ci-fix, or needs-review-response:
Dispatch subagents (max 5 concurrent, one repo per agent, subagent_type: pr-ci-fixer).
Each fixer agent gets this brief:
Task: Fix PR # in ()
Repo path:
Branch:
Base:
Pre-work: capture START_SHA = current `git ls-remote origin `.
For needs-rebase:
1. Worktree: `git worktree add .worktrees/fix- ` inside .
2. `git fetch origin && git rebase origin/`.
3. On conflict: resolve thoughtfully (preserve PR intent for source files,
`--theirs` only for lockfiles). If unresolvable, ABORT and return structured failure.
4. Quality gate locally (per repo): type-check + lint + relevant tests.
5. `git push --force-with-lease origin `.
For needs-ci-fix:
1. Worktree as above.
2. Pull failed-check logs, diagnose, apply surgical fix.
3. Quality gate locally.
4. Commit + `git push --force-with-lease origin ` (no `--no-verify`
unless a hook is genuinely broken and unrelated to your change).
After push (every classification):
5. Capture END_SHA = `git rev-parse HEAD`.
6. Confirm remote: `git ls-remote origin ` MUST return END_SHA.
If mismatch, retry once; if still mismatched, return failure.
7. Verify CI: poll `gh pr view --repo --json statusCheckRollup`
until all required checks are non-pending. Capture the literal JSON output.
8. Clean up worktree: `git worktree remove .worktrees/fix- --force`.
9. Return the structured JSON schema defined in the pr-ci-fixer agent contract.
DO NOT call `gh pr merge` under any circumstances. Your job ends at "CI is green
on the pushed SHA." The orchestrator will independently verify and merge.
DO NOT file a tracking issue for a CI failure you could not fix — in ANY repo.
No `gh issue create`, no `github.rest.issues.create`, no cross-repo issue. If you
cannot get CI green, return the structured failure in your JSON result and STOP;
the orchestrator decides what happens next. (Rationale: emergent issue-filing on
unfixable CI produced 17+ duplicate `[TEAM] CI failure on PR #N` issues — one per
failing check, zero dedup, cross-posted into the wrong repo. A fixer's only valid
outputs are a pushed green SHA or a structured failure report — never an issue.)
If a tracking issue is ever genuinely wanted, that is the orchestrator's call and
it MUST first `gh issue list --search "PR # in:title" --state open` to dedup.
Use model: "haiku" for fixer agents (matches agent definition default).
Phase 4 — Resolve surfaced conflicts
For each PR returned with status: "conflict" from a fixer agent:
- Display the conflict summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OPS ► MERGE — Conflict in #
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Branch: →
Conflicting files:
-
-
──────────────────────────────────────────────────────
- Use AskUserQuestion (max 4 options — CLAUDE.md Rule 1):
[A
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [Lifecycle-Innovations-Limited](https://github.com/Lifecycle-Innovations-Limited)
- **Source:** [Lifecycle-Innovations-Limited/claude-ops](https://github.com/Lifecycle-Innovations-Limited/claude-ops)
- **License:** MIT
- **Homepage:** https://github.com/Lifecycle-Innovations-Limited/claude-ops/wiki
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.