OPS on-demand: This skill should be used when the user asks to "merge PRs", "salvage branches", or…

MITAuto-check: notes

Install Ops Merge

skills CLI
$ npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install Lifecycle-Innovations-Limited/claude-ops ops-merge --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/Lifecycle-Innovations-Limited/claude-ops.git skills-src && mkdir -p .claude/skills && cp -r skills-src/claude-ops/skills/ops-merge .claude/skills/ops-merge && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
ops-merge
GitHub stars
542
Token cost
~8k tokens
SKILL.md length
2,808 words
Files
2 (incl. references)
Skills in repo
67
Repo updated
First seen
Licence
MIT

At a glance

OPS on-demand: This skill should be used when the user asks to "merge PRs", "salvage branches", or…

  • Works in 9 steps: Salvage scan (run BEFORE the PR queue) → Classify the PR queue → Confirm and merge ready PRs → …
  • Asks to merge PRs
  • SKILL.md covers Runtime Context, Agent Teams support, Pre-gathered PR data and Pre-gathered salvage data…, plus 6 more sections
  • Calls git, gh and mise; reaches github.com; needs CLAIM_KEY and GITHUB_TOKEN

What it does

Ops Merge is an agent skill from Lifecycle-Innovations-Limited/claude-ops. OPS on-demand: This skill should be used when the user asks to "merge PRs", "salvage branches", or…

Its SKILL.md is about 8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including reference files (for example `references/cli.md`).

It works with GitHub. The repository describes itself as: Business operating system for Claude Code — 57 skills, 21 agents, smart daemon. Unified inbox (WhatsApp/Email/Slack/Telegram), autonomous PR merge, full-AWS monitoring, revenue… The licence is MIT.

When your agent uses it

  • Asks to merge PRs
  • Salvage branches

Example prompts

  • “merge PRs”
  • “salvage branches”
  • “/ops-merge”

Requirements

  • A credential in GITHUB_TOKEN
  • Pre-approved tools (allowed-tools): Bash, Read, Write, Edit, Grep, Glob, Agent, TaskCreate, TaskUpdate, TaskList, AskUserQuestion, TeamCreate, SendMessage, Monitor, WebSearch

Workflow steps

9 steps, taken from the step headings in SKILL.md.

  1. Salvage scan (run BEFORE the PR queue)
  2. Classify the PR queue
  3. Confirm and merge ready PRs
  4. Dispatch fixers for PRs that need work
  5. Resolve surfaced conflicts
  6. Orchestrator verification & merge
  7. main sync (only if flag is set)
  8. Final report
  9. (Salvage) Safety Rails

What it can do on your machine

Read from SKILL.md and the folder at commit ee9c784. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Bash
    • Read
    • Write
    • Edit
    • Grep
    • Glob
    • Agent
    • TaskCreate
    • TaskUpdate
    • TaskList

    …and 5 more on the same allowed-tools line.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • git
    • gh
    • mise

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • github.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names these keys or tokens, usually read from environment variables:

    • CLAIM_KEY
    • GITHUB_TOKEN

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Ops Merge loads about 8k tokens when it runs, and up to ~8.5k if it reads all its reference files. Until then it costs about 27 tokens; SKILL.md has 2,808 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~27
When it runs · the whole SKILL.md, loaded when a task matches
~8k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~8.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NotePre-approves every shell command (allowed-tools: Bash)SKILL.md
    allowed-tools: Bash, Read, Write, Edit, Grep, Glob, Agent, TaskCreate, TaskUpdate, TaskList, AskUserQuestion, TeamC

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from Lifecycle-Innovations-Limited/claude-ops at commit ee9c784, republished under its MIT licence (© Lifecycle-Innovations-Limited). 2,808 words, ~8,003 tokens.

Download SKILL.mdSave it as .claude/skills/ops-merge/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
ops-merge
description
OPS on-demand: This skill should be used when the user asks to "merge PRs", "salvage branches", or…
allowed-tools
Bash, Read, Write, Edit, Grep, Glob, Agent, TaskCreate, TaskUpdate, TaskList, AskUserQuestion, TeamCreate, SendMessage, Monitor, WebSearch
argument-hint
[--main] [--repo org/repo] [--dry-run] [--no-salvage] [--salvage-only]
effort
medium
maxTurns
50
context
fork

Runtime Context

Before executing, load:

  1. Preferences: cat ${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json — read owner, timezone, project registry
  2. Daemon health: cat ${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json — if action_needed set, surface to user
  3. Secrets: GitHub token: env $GITHUB_TOKEN → Doppler MCP (mcp__doppler__*) → doppler secrets get GITHUB_TOKEN --plain → password manager

OPS ► MERGE

Load ops-rules before acting. Public repo (no personal data). Outbound: one draft → one approval → one send. If AskUserQuestion / Workflow are missing, follow Rule 10 in ops-rules (Hermes: numbered options / two-turn Telegram card; delegate_task).

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

${CLAUDE_PLUGIN_ROOT}/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 <slug> → 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:

FindingClassificationAction
Worktree with dirty_files > 0 or unpushed_commits > 0worktree-incompleteDispatch salvager: finish work in the worktree, commit, push, open PR if missing
Worktree on a branch with has_open_pr: falseworktree-orphan-prDispatch salvager: confirm work is complete (lint/type/test gate), push if needed, open PR
Local branch with integrated: false and has_open_pr: falsebranch-no-prDispatch salvager: review state, push if unpushed, open PR targeting integration branch
Local branch with integrated: true and has_open_pr: falsebranch-already-mergedSurface to user → [Delete local branch] / [Keep] (NEVER auto-delete — Safety Rails)
Main checkout: dirty_files > 0 or staged_files > 0 or stash >0checkout-dirtySurface to user → [Stash & continue] / [Open salvage worktree] / [Skip]. Never auto-discard.
Main checkout: unpushed_commits > 0 on a non-integration branchcheckout-unpushedDispatch 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>
Repo path: <path from salvage scan>
Findings:
  - <classification>: <branch / worktree path> — <state summary>
  - ...

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 <repo path> worktree add .worktrees/salvage-<branch> <branch>

For each finding:
  1. cd into the worktree.
  2. Inspect state: `git status`, `git log <integration>..HEAD --oneline`, `git diff --stat`.
  3. **Stale-copy guard (mandatory, per candidate file before commit):**
     - Set `BASE=$(git merge-base HEAD origin/<integration_branch>)`.
     - List files you plan to salvage from the worktree.
     - For each file `<f>`:
       - If `git diff --quiet "$BASE..origin/<integration_branch>" -- "<f>"` is **false** (integration changed `<f>` since base), treat `<f>` as high risk.
       - For high-risk files, inspect both sides before staging:
         - `git diff "$BASE..origin/<integration_branch>" -- "<f>"`
         - `git diff "$BASE..HEAD" -- "<f>"`
       - Only stage hunks that are genuinely new work from the salvage branch. Do **not** stage a wholesale file replacement that drops integration-side hunks.
       - If you cannot prove the salvage branch is newer for `<f>`, mark the finding `aborted_for_review` (do not commit the file).
  4. 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.
  5. If finishing work: make the smallest correct commit. Quality gate locally
     (per-repo: type-check + lint + relevant tests).
  6. Commit with a clear message. NEVER use --no-verify unless a hook is genuinely
     broken and unrelated to your change.
  7. Push: `git push -u origin <branch>` (or `--force-with-lease` if branch already remote).
  8. Open PR (only if has_open_pr=false in the brief):
       gh pr create --repo <repo> --base <integration_branch> --head <branch> \
         --title "<derived from commit messages>" \
         --body "Salvaged by /ops:merge Phase 0. <commit summary>"
  9. Return structured JSON:
       {
         "repo": "...",
         "branch": "...",
         "status": "pr_opened" | "pushed_only" | "aborted_for_review" | "failed",
         "pr_number": <int or null>,
         "pr_url": "<or null>",
         "end_sha": "<remote head>",
         "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:

ClassificationMeaningAction
readyCI green, approved, no conflictsMerge immediately
needs-rebasemergeable: CONFLICTINGDispatch fixer: rebase on base branch
needs-ci-fixCI failures in statusCheckRollupDispatch fixer: investigate logs, fix, push
needs-review-responsereviewDecision: CHANGES_REQUESTEDDispatch fixer: resolve comments
blockedmergeStateStatus: BLOCKED (branch protection, required reviews)Note why, skip
draftisDraft: trueSkip — 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:

  1. Verify CI is still green: gh pr checks <number> --repo <repo>
  2. If green: gh pr merge <number> --repo <repo> --squash (never --admin — see "Never bypass a branch gate" below)
  3. Report: ✓ Merged <repo>#<number> to <base>
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 #<number> in <repo> (<classification>)
Repo path: <path from registry>
Branch: <headRefName>
Base: <baseRefName>

Pre-work: capture START_SHA = current `git ls-remote origin <headRefName>`.

For needs-rebase:
  1. Worktree: `git worktree add .worktrees/fix-<pr> <headRefName>` inside <repo path>.
  2. `git fetch origin && git rebase origin/<baseRefName>`.
  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 <headRefName>`.

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 <headRefName>` (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 <headRefName>` MUST return END_SHA.
     If mismatch, retry once; if still mismatched, return failure.
  7. Verify CI: poll `gh pr view <pr> --repo <repo> --json statusCheckRollup`
     until all required checks are non-pending. Capture the literal JSON output.
  8. Clean up worktree: `git worktree remove .worktrees/fix-<pr> --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 #<n> 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:

  1. Display the conflict summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► MERGE — Conflict in <repo>#<number>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Branch: <headRefName> → <baseBranchRef>
 Conflicting files:
   - <file1>
   - <file2>

<diff_summary>
──────────────────────────────────────────────────────
  1. Use AskUserQuestion (max 4 options — CLAUDE.md Rule 1):
[Accept incoming (theirs)]  [Keep current branch (ours)]  [Open manual resolution]  [Skip this PR]
  1. Based on response:
    • Accept incoming (theirs): Create worktree, rebase with git checkout --theirs . on each conflicting file, git add ., git rebase --continue, push force-with-lease
    • Keep current branch (ours): Create worktree, rebase with git checkout --ours . on each conflicting file, git add ., git rebase --continue, push force-with-lease
    • Open manual resolution: Print step-by-step instructions for the operator to resolve manually, then check in with git push confirmation before continuing the merge pipeline
    • Skip this PR: Note as unresolved-conflict, include in final report
Phase 5 — Orchestrator verification & merge

NEVER TRUST FIXER REPORTS. ALWAYS VERIFY VIA INDEPENDENT gh CALLS.

When a fixer agent returns its structured JSON, run the verification protocol below. Skip merge if ANY check fails — surface the discrepancy to the user.

Verification protocol (run for every fixer return)

For each fixer's JSON report:

  1. Parse the JSON. If the agent didn't return parseable JSON, treat as failure — do not merge.

  2. Verify push actually landed. Read claimed end_sha from JSON. Run:

    bash
    ACTUAL_REMOTE_SHA=$(git ls-remote https://github.com/<repo>.git <branch> | awk '{print $1}')

    If ACTUAL_REMOTE_SHA != end_sha, the agent fabricated or its push failed silently. Do not merge. Mark as verification_failed: push_sha_mismatch and surface to user.

  3. Verify the push is yours (defense against bot-race overwrites). Compare start_sha claimed vs git log between start and end:

    bash
    git log --pretty=format:"%H %an %s" "$start_sha".."$end_sha" | head -10

    If author isn't us OR the diff is wildly different from what the agent reported, mark as verification_failed: branch_overwritten_by_other_agent and surface.

  4. Verify CI independently. Do NOT trust the agent's ci_status field. Run:

    bash
    gh pr view <pr> --repo <repo> --json statusCheckRollup,mergeable,mergeStateStatus

    Parse statusCheckRollup. All required checks must have conclusion: SUCCESS. mergeable must be MERGEABLE. mergeStateStatus must be CLEAN (or UNSTABLE for non-required-check failures only).

  5. If all checks pass: orchestrator performs the merge. The fixer never had merge authority. Run:

    bash
    gh pr merge <pr> --repo <repo> --squash

    Never add --admin. If the merge is refused, that refusal is the gate doing its job — see "Never bypass a branch gate" below.

  6. Verify the merge actually landed. Immediately after the merge call:

    bash
    gh pr view <pr> --repo <repo> --json state,mergedAt,mergeCommit

    state must be MERGED. mergedAt must be a timestamp within the last 60 seconds. mergeCommit.oid must exist. If any of these fail, the merge silently failed — log the error and do NOT mark the task complete.

  7. Verify the merge SHA exists in the target branch.

    bash
    git fetch origin <base-branch>
    git merge-base --is-ancestor <mergeCommit.oid> origin/<base-branch>

    Exit 0 = merge SHA is in the branch. Exit non-zero = false merge (rare but real — guard against it).

  8. Only after steps 1-7 all pass, report success with the verified merge SHA.

Decision matrix after verification
Verification resultAction
All 7 checks passOrchestrator merges (step 5), verifies merge (steps 6-7), reports ✓ verified-merged
Push SHA mismatchMark fabricated_or_push_failed, surface fixer's claimed vs actual SHAs to user
Branch overwritten by other botMark race_lost, surface diff, ask user if re-dispatch or skip
CI still redMark ci_red, surface failing checks, do NOT merge
Merge call failedCapture stderr, mark merge_failed, surface to user
Merge call succeeded but mergedAt absentMark silent_merge_failure, escalate immediately
Anti-fabrication red flags (always investigate)

If you see any of these in a fixer's report, treat the entire report as suspect and run the verification protocol with extra scrutiny:

  • Reported merge SHA has suspicious structure (sequential hex like a3f91c2d...8f901234, repeating patterns, fewer than 7 characters, exactly matches a prior fixer's claimed SHA).
  • Reported CI run URL doesn't return a valid run via gh run view <id>.
  • Fixer claims "all 5 CI jobs green" but gh pr view --json statusCheckRollup shows fewer or different checks.
  • Fixer's transcript contains sleep loops in the bash output but no actual tool call delays in execution timeline.
  • Two or more fixers in the same wave return identical reported merge SHAs (impossible — each merge produces a unique commit).
Phase 6 — --main sync (only if flag is set)

For each repo that has separate dev and main branches:

  1. Check if dev is ahead of main: git -C <path> log main..dev --oneline | head -5

  2. If ahead, show the commits and use AskUserQuestion:

    [repo]: dev is N commits ahead of main:
      [commit list]
    
      [Create sync PR and merge]  [Create PR only — I'll review]  [Skip this repo]
  3. If confirmed: create sync PR: gh pr create --repo <repo> --base main --head dev --title "chore: sync dev → main"

  4. Wait for CI via the approved monitor, never a hand-rolled loop and never --watch. hooks/gh-watch-guard.sh denies both: ${CLAUDE_PLUGIN_ROOT}/scripts/ops-deploy-monitor.sh <repo> <sync-pr-number>

  5. If CI green: gh pr merge <sync-pr-number> --repo <repo> --merge (merge commit, not squash; never --admin)

  6. Pull main back into dev: git -C <path> fetch origin && git -C <path> checkout dev && git -C <path> merge origin/main --no-edit

Phase 7 — Final report
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► MERGE COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Phase 0 — Salvage
| Repo | Finding | Result |
|------|---------|--------|
| my-api | feat/x worktree | ✓ pushed + PR #2999 opened |
| my-app | feat/y local-only | ✓ pushed + PR #4470 opened |
| mise | old-experiment (merged) | ⚠ surfaced for delete confirmation |

Salvaged: N pieces of work → N new PRs opened
Aborted for review: N
User-input pending: N (dirty checkouts, already-merged branches)

Phase 1–5 — PR merges
| Repo | PR | Result |
|------|----|--------|
| my-api | #2958 | ✓ merged to dev |
| my-api | #2999 | ✓ salvaged + merged to dev |
| my-app | #4456 | ✓ fixed CI + merged |
| mise | #10 | ✗ 3 critical bugs — skipped |

Merged: N PRs across M repos
Skipped: N (blocked/draft)
Failed: N (still need manual attention)

Phase 6 — Main sync
Main sync: N repos synced (dev → main → dev)
──────────────────────────────────────────────────────

Show full SKILL.md (1,161 more words)Show less

Superpowers Integration

During this command's execution, invoke the following superpower skills at the specified checkpoint:

  • Checkpoint: Before the final merge decision for each PR in Phase 2 and Phase 5 (after fixer reports green).
  • Skills: superpowers:verification-before-completion + superpowers:finishing-a-development-branch
  • Why: Verification-before-completion forces evidence (CI green, tests pass) before the merge call; finishing-a-development-branch structures the merge/cleanup choice so nothing ships half-done.

Safety Rails (NEVER violate)

  • NEVER trust a fixer's claim of merge success. Always verify via gh pr view --json state,mergedAt,mergeCommit before marking complete. See Phase 5 verification protocol.

  • NEVER let a fixer call gh pr merge. Merge is orchestrator-only. Fixers push, orchestrator verifies the push, orchestrator merges, orchestrator verifies the merge.

  • NEVER merge, or open a PR against, a repo the owner is not a member of. The registry lists every locally cloned project, so a fork's upstream (facebookresearch/*, someone else's OSS) appears in the queue carrying open PRs from unrelated contributors. Those are read-only. Contributing upstream is a deliberate act the owner asks for, one PR at a time, never a pipeline sweep.

    Check push access immediately before every gh pr create, gh pr merge, and git push — in every phase (0 salvage, 2 merge, 5 verified-merge, 6 main sync):

    bash
    PERM=$(gh api "repos/$REPO" --jq '.permissions.push' 2>/dev/null || echo error)
    [ "$PERM" = "true" ] || { echo "refusing: no confirmed push access to $REPO ($PERM)"; exit 1; }

    Fail closed. Only a literal true proceeds. false, null, a network error, a renamed repo, or an empty response all refuse. The scan filtering the queue is not sufficient on its own: the queue can be stale, hand-edited, or passed in by an operator, and the step after it is a merge. Re-check at the point of action, not once at the start.

    OPS_MERGE_INCLUDE_EXTERNAL=<owner/name> authorises exactly one repo for one run, and only when the owner asked. It is a slug, never a boolean — a global on/off would re-open the whole registry to a pipeline whose next call is gh pr merge.

  • NEVER force-push to main/master

  • NEVER merge with red CI — fix root cause first

  • NEVER bypass review on PRs touching auth, payments, PII, or secrets — these require security-reviewer subagent audit before merge

  • NEVER run git reset --hard on shared branches

  • ALWAYS use worktrees for fixes (multiple agents may be active)

  • NEVER bypass a branch gate. Do not pass --admin to gh pr merge, and do not widen a ruleset, add yourself to a bypass list, or grant yourself admin to get a merge through. A refused merge is the protection working. See "Never bypass a branch gate" below.

  • ALWAYS confirm the base branch before merging. Read baseRefName from gh pr view <n> --json baseRefName in the same step as the merge. A run scoped to one branch must refuse a PR whose base is a different one — a protected branch typically carries a review gate the scoped branch does not.

  • Max 10 PRs per invocation to avoid GitHub API throttling

  • If a PR has > 50 files changed, flag it for manual review instead of auto-merging

Never bypass a branch gate

gh pr merge --admin merges past branch protection and org rulesets. It is banned in this pipeline, in every phase, on every repo. So is any other route to the same outcome: editing a ruleset's conditions, adding an actor to a bypass list, or promoting your own account to get a merge through.

Why it matters here specifically: a merge queue sweeps many repos at once, and repo governance is not uniform. Organisations commonly scope a review gate to a subset of repos via a repository custom property, and protect only some branches. The pipeline cannot see that policy from the PR alone — but the merge API can, and it enforces it. --admin throws that enforcement away silently and succeeds, so the violation is only discoverable afterwards, from the commit.

Rules:

  1. Never pass --admin (or --auto as a workaround for a refused merge).
  2. Read baseRefName in the same step as the merge and refuse any PR whose base is outside the run's declared scope. A default-branch merge and a protected-branch merge are different acts with different approvals.
  3. Treat a refusal as a result, not an obstacle. mergeStateStatus: BLOCKED with green checks usually means a required approval or an unresolved review thread. Resolve the findings, request the human reviewer, report the PR as waiting, and move on.
  4. If a merge is genuinely urgent and gated, that is the owner's decision to make, not the pipeline's. Surface it; never route around it.

A merge that landed via bypass cannot be silently undone. Report it immediately, name the commit, and say which gate it skipped.

Phase 0 (Salvage) Safety Rails
  • NEVER auto-delete a local branch, worktree, or stash — even if classified branch-already-merged. Always surface to the user via AskUserQuestion.
  • NEVER git stash drop or git checkout -- <file> or git clean in any checkout — uncommitted work is the user's, not the agent's, until they confirm.
  • NEVER auto-commit ambiguous changes. If a salvager can't tell whether work is complete, it MUST return aborted_for_review and let the user decide.
  • NEVER commit stale snapshots over integration branch progress. If integration branch and salvage branch both changed a file since merge-base, stage only provably new hunks (or abort for review).
  • NEVER share the main checkout between salvager subagents. Per CLAUDE.md worktree isolation: each agent gets its own .worktrees/salvage-<branch> dir. Sharing the main checkout causes branch-switch collisions.
  • NEVER force-push a branch the salvager didn't originate work on — salvagers may only push with --force-with-lease to branches whose tip they fetched at start of work.
  • NEVER salvage main/master/dev — those are integration branches; loose work on them surfaces to the user, never auto-pushed.
  • NEVER touch files outside the assigned worktree. Salvagers are scoped to one repo + one branch.
  • ALWAYS run the per-repo quality gate (type-check + lint + tests) before pushing salvaged work.
  • ALWAYS open a PR (not direct push to dev/main) — salvaged work flows through the same review/CI/merge gate as any other PR.

Native tool usage

Monitor — live CI watching

When waiting for CI after a fixer pushes (Phase 3-4), call the approved monitor script. A hand-rolled gh api polling loop is denied by hooks/gh-watch-guard.sh before it runs, and gh run watch is banned outright (polls every 2-5s, no tick cap):

bash
${CLAUDE_PLUGIN_ROOT}/scripts/ops-deploy-monitor.sh <owner/repo> <pr-number>

Tick cap, wall-clock deadline, 25s sleep floor and REST rate gate all live in that one script, so the interactive and hook-spawned paths cannot drift apart.

Tasks — progress tracking

Create a TaskCreate for the overall merge pipeline and individual tasks per PR. Update with TaskUpdate as each PR is fixed/merged/skipped. This gives the user a live checklist view.

WebSearch — CI failure context

When a fixer agent encounters an obscure CI failure, use WebSearch to find known issues (e.g., npm registry outages, GitHub Actions incidents, flaky test patterns).


Ledger Integration

CLAIM_KEY: gh:pr:<owner>/<repo>#<number> (e.g. gh:pr:your-org/your-repo#42)

Pre-flight skip-check
bash
CLAIM_KEY="gh:pr:<owner>/<repo>#<number>"
ledger query --claim-key "$CLAIM_KEY" --since=-PT24H

If done exists, the PR was already merged or closed this session — skip. If in_progress exists from another agent, do not attempt a concurrent merge.

Claim + resolve
bash
# Claim when beginning CI fix or merge flow for a PR
ledger write \
  --claim-key "$CLAIM_KEY" \
  --kind "merge" \
  --status "in_progress" \
  --title "Merge: <repo>#<number> — <PR title>" \
  --ttl-sec 3600

# Resolve after merge completes or is skipped
ledger write \
  --claim-key "$CLAIM_KEY" \
  --kind "merge" \
  --status "done" \
  --title "Merge: <repo>#<number> — <PR title>" \
  --context "merged|skipped: <reason>"

Additional resources

CLI detail: references/cli.md.

© Lifecycle-Innovations-Limited, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file (references) in claude-ops/skills/ops-merge of Lifecycle-Innovations-Limited/claude-ops.

  • SKILL.md
  • references/cli.md

Open the folder on GitHubat commit ee9c784

Compare with similar skills

Ops Merge next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Ops Merge compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Ops Merge this skillLifecycle-Innovations-Limited/claude-ops542—~8kAutomated safety check: NotesMIT
PR Babysitteropeninterpreter/openinterpreter69k3 repos~4.2kAutomated safety check: PassApache-2.0
Greplooponyx-dot-app/onyx32k4 repos~3.3kAutomated safety check: PassMIT
GitHub Deep Researchbytedance/deer-flow84k4 repos~1.3kAutomated safety check: PassMIT
Diagnosing Superpowers Sessionsobra/superpowers297k3 repos~1.7kAutomated safety check: PassMIT
Update V8 Versionopeninterpreter/openinterpreter69k2 repos~845Automated safety check: PassApache-2.0

Similar skills

  • PR Babysitter

    openinterpreter/openinterpreter

    Watches an open GitHub pull request until it merges, handling review comments, diagnosing CI failures and retrying flaky checks along the way.

    69k GitHub starsUsed in 3 repos~4.2k tokens
    DevelopmentAuto-check passed
  • Greploop

    onyx-dot-app/onyx

    Iteratively improves a PR (GitHub), MR (GitLab), or shelved changelist (Perforce) until Greptile gives it a 5/5 confidence score with zero unresolved comments.

    32k GitHub starsUsed in 4 repos~3.3k tokens
    DevelopmentAuto-check passed
  • GitHub Deep Research

    bytedance/deer-flow

    Researches a GitHub repository over four rounds using the GitHub API and web search, then writes a structured markdown report with timeline, metrics and Mermaid diagrams.

    84k GitHub starsUsed in 4 repos~1.3k tokens
    Research & ScienceAuto-check passed
  • Investigates a session where Superpowers went wrong, reads the transcripts on disk and produces an evidence-cited report, optionally prepared as a bug report for the maintainers.

    297k GitHub starsUsed in 3 repos~1.7k tokens
    Agent WorkflowsAuto-check passed
  • Update V8 Version

    openinterpreter/openinterpreter

    Bumps the pinned v8 and rusty_v8 versions in Codex, validates the release-candidate path with the v8-canary check, and traces failures to upstream build changes.

    69k GitHub starsUsed in 2 repos~845 tokens
    DevOps & CloudAuto-check passed
  • Last30days

    mvanhorn/last30days-skill

    Research what people actually say about any topic in the last 30 days.

    64k GitHub stars~7.9k tokensUpdated yesterday
    Research & ScienceAuto-check: notes

More from Lifecycle-Innovations-Limited/claude-ops

All 67 skills in this repo
  • Ops Dash

    Lifecycle-Innovations-Limited/claude-ops

    OPS on-demand: This skill should be used when the user asks to "ops dashboard", "pixel HQ", or…

    542 GitHub stars~4.7k tokensUpdated yesterday
    Auto-check: notes
  • Ops Gtm

    Lifecycle-Innovations-Limited/claude-ops

    OPS on-demand: This skill should be used when the user asks to "go to market", "GTM plan", or…

    542 GitHub stars~3.7k tokensUpdated yesterday
    Auto-check: notes
  • Ops Marketing

    Lifecycle-Innovations-Limited/claude-ops

    OPS on-demand: This skill should be used when the user asks to "klaviyo", "ads spend", or…

    542 GitHub stars~3.5k tokensUpdated yesterday
    Auto-check: notes
  • Ops Socials

    Lifecycle-Innovations-Limited/claude-ops

    OPS on-demand: This skill should be used when the user asks to "tweet", "post to linkedin", or…

    542 GitHub stars~3.6k tokensUpdated yesterday
    Auto-check: notes
  • Ops Yolo

    Lifecycle-Innovations-Limited/claude-ops

    OPS on-demand: This skill should be used when the user asks to "yolo mode", "run the business today"…

    542 GitHub stars~4k tokensUpdated yesterday
    Auto-check: notes
  • Ops Monitor

    Lifecycle-Innovations-Limited/claude-ops

    OPS on-demand: This skill should be used when the user asks to "datadog", "APM alerts", or…

    542 GitHub starsUsed in 1 repo~1.5k tokens
    Auto-check: notes

Works with

Questions about Ops Merge

What does Ops Merge do?

OPS on-demand: This skill should be used when the user asks to "merge PRs", "salvage branches", or…. Ops Merge is an agent skill from Lifecycle-Innovations-Limited/claude-ops.

When should I use Ops Merge?

Ops Merge fits situations like: asks to merge PRs; salvage branches.

How do I install Ops Merge in Claude Code?

Run `npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a claude-code`. Or copy the skill folder (claude-ops/skills/ops-merge in Lifecycle-Innovations-Limited/claude-ops) into .claude/skills/ops-merge in your project. Claude Code loads it when a task matches its description.

How do I install Ops Merge in Codex?

Run `npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a codex`. Or copy the skill folder (claude-ops/skills/ops-merge in Lifecycle-Innovations-Limited/claude-ops) into .agents/skills/ops-merge in your project. Codex loads it when a task matches its description.

Can I use Ops Merge in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ops-merge, .gemini/skills/ops-merge, .github/skills/ops-merge and .opencode/skills/ops-merge in your project.

What does Ops Merge need to run?

Going by SKILL.md and its folder, Ops Merge needs the command-line tools its instructions call (git, gh and mise) and credentials named CLAIM_KEY and GITHUB_TOKEN. Our summary lists: A credential in GITHUB_TOKEN. Its frontmatter pre-approves these tools: Bash, Read, Write, Edit, Grep, Glob, Agent, TaskCreate, TaskUpdate, TaskList, AskUserQuestion, TeamCreate, SendMessage, Monitor, WebSearch.

Does Ops Merge access the network?

SKILL.md names 1 domain. In commands or code: github.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Ops Merge safe to install?

Our automated static check of SKILL.md found notes only (pre-approves every shell command (allowed-tools: bash)), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.

What licence does Ops Merge use?

Ops Merge is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Ops Merge use?

About 8k tokens (SKILL.md is roughly 32k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 518 tokens, read only when the agent opens those files.

What are the alternatives to Ops Merge?

Skills that share tags, products or a category with Ops Merge: PR Babysitter (openinterpreter/openinterpreter, 69k stars), Greploop (onyx-dot-app/onyx, 32k stars), GitHub Deep Research (bytedance/deer-flow, 84k stars) and Diagnosing Superpowers Sessions (obra/superpowers, 297k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Ops Merge?

Lifecycle-Innovations-Limited (a GitHub organization) maintains it in Lifecycle-Innovations-Limited/claude-ops, which has 542 GitHub stars. The repository holds 67 skills in this directory. The repository was last updated on October 10, 2026.

Source: Lifecycle-Innovations-Limited/claude-ops on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.