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.
OPS on-demand: This skill should be used when the user asks to "merge PRs", "salvage branches", or…
$ npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install Lifecycle-Innovations-Limited/claude-ops ops-merge --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ 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-srcUse ~/.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/
Install the "ops-merge" agent skill from https://github.com/Lifecycle-Innovations-Limited/claude-ops/tree/main/claude-ops/skills/ops-merge into .claude/skills/ops-merge/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ops-merge", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/Lifecycle-Innovations-Limited/claude-ops/tree/main/claude-ops/skills/ops-mergeType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install Lifecycle-Innovations-Limited/claude-ops ops-merge --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Lifecycle-Innovations-Limited/claude-ops.git skills-src && mkdir -p .agents/skills && cp -r skills-src/claude-ops/skills/ops-merge .agents/skills/ops-merge && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "ops-merge" agent skill from https://github.com/Lifecycle-Innovations-Limited/claude-ops/tree/main/claude-ops/skills/ops-merge into .agents/skills/ops-merge/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ops-merge", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install Lifecycle-Innovations-Limited/claude-ops ops-merge --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Lifecycle-Innovations-Limited/claude-ops.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/claude-ops/skills/ops-merge .cursor/skills/ops-merge && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "ops-merge" agent skill from https://github.com/Lifecycle-Innovations-Limited/claude-ops/tree/main/claude-ops/skills/ops-merge into .cursor/skills/ops-merge/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ops-merge", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/Lifecycle-Innovations-Limited/claude-ops.git --path claude-ops/skills/ops-merge--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install Lifecycle-Innovations-Limited/claude-ops ops-merge --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Lifecycle-Innovations-Limited/claude-ops.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/claude-ops/skills/ops-merge .gemini/skills/ops-merge && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "ops-merge" agent skill from https://github.com/Lifecycle-Innovations-Limited/claude-ops/tree/main/claude-ops/skills/ops-merge into .gemini/skills/ops-merge/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ops-merge", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install Lifecycle-Innovations-Limited/claude-ops ops-mergeInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/Lifecycle-Innovations-Limited/claude-ops.git skills-src && mkdir -p .github/skills && cp -r skills-src/claude-ops/skills/ops-merge .github/skills/ops-merge && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "ops-merge" agent skill from https://github.com/Lifecycle-Innovations-Limited/claude-ops/tree/main/claude-ops/skills/ops-merge into .github/skills/ops-merge/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ops-merge", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-merge -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install Lifecycle-Innovations-Limited/claude-ops ops-merge --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Lifecycle-Innovations-Limited/claude-ops.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/claude-ops/skills/ops-merge .opencode/skills/ops-merge && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "ops-merge" agent skill from https://github.com/Lifecycle-Innovations-Limited/claude-ops/tree/main/claude-ops/skills/ops-merge into .opencode/skills/ops-merge/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ops-merge", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
ops-mergeOPS 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. 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.
9 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit ee9c784. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
BashReadWriteEditGrepGlobAgentTaskCreateTaskUpdateTaskList…and 5 more on the same allowed-tools line.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitghmiseFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
github.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
CLAIM_KEYGITHUB_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
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.
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.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
allowed-tools: Bash, Read, Write, Edit, Grep, Glob, Agent, TaskCreate, TaskUpdate, TaskList, AskUserQuestion, TeamCAutomated 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.
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.
.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.Before executing, load:
cat ${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json — read owner, timezone, project registrycat ${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json — if action_needed set, surface to user$GITHUB_TOKEN → Doppler MCP (mcp__doppler__*) → doppler secrets get GITHUB_TOKEN --plain → password managerLoad 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).
If CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 is set, use Agent Teams for fixer agents (Phase 3). This enables:
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".
${CLAUDE_PLUGIN_ROOT}/bin/ops-merge-scan 2>/dev/null || echo '{"prs":[],"error":"merge-scan failed"}'${CLAUDE_PLUGIN_ROOT}/bin/ops-merge-salvage-scan 2>/dev/null || echo '{"repos":[],"error":"salvage-scan failed"}'You are the merge orchestrator. Your job is to get every open PR across the owner's repos merged — fixing whatever blocks them first.
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.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>
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).
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.
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:
gh pr checks <number> --repo <repo>gh pr merge <number> --repo <repo> --squash (never --admin — see "Never bypass a branch gate" below)✓ Merged <repo>#<number> to <base>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).
For each PR returned with status: "conflict" from a fixer agent:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
OPS ► MERGE — Conflict in <repo>#<number>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Branch: <headRefName> → <baseBranchRef>
Conflicting files:
- <file1>
- <file2>
<diff_summary>
──────────────────────────────────────────────────────[Accept incoming (theirs)] [Keep current branch (ours)] [Open manual resolution] [Skip this PR]git checkout --theirs . on each conflicting file, git add ., git rebase --continue, push force-with-leasegit checkout --ours . on each conflicting file, git add ., git rebase --continue, push force-with-leasegit push confirmation before continuing the merge pipelineunresolved-conflict, include in final reportNEVER 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.
For each fixer's JSON report:
Parse the JSON. If the agent didn't return parseable JSON, treat as failure — do not merge.
Verify push actually landed. Read claimed end_sha from JSON. Run:
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.
Verify the push is yours (defense against bot-race overwrites). Compare start_sha claimed vs git log between start and end:
git log --pretty=format:"%H %an %s" "$start_sha".."$end_sha" | head -10If 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.
Verify CI independently. Do NOT trust the agent's ci_status field. Run:
gh pr view <pr> --repo <repo> --json statusCheckRollup,mergeable,mergeStateStatusParse statusCheckRollup. All required checks must have conclusion: SUCCESS. mergeable must be MERGEABLE. mergeStateStatus must be CLEAN (or UNSTABLE for non-required-check failures only).
If all checks pass: orchestrator performs the merge. The fixer never had merge authority. Run:
gh pr merge <pr> --repo <repo> --squashNever add --admin. If the merge is refused, that refusal is the gate doing its
job — see "Never bypass a branch gate" below.
Verify the merge actually landed. Immediately after the merge call:
gh pr view <pr> --repo <repo> --json state,mergedAt,mergeCommitstate 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.
Verify the merge SHA exists in the target branch.
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).
Only after steps 1-7 all pass, report success with the verified merge SHA.
| Verification result | Action |
|---|---|
| All 7 checks pass | Orchestrator merges (step 5), verifies merge (steps 6-7), reports ✓ verified-merged |
| Push SHA mismatch | Mark fabricated_or_push_failed, surface fixer's claimed vs actual SHAs to user |
| Branch overwritten by other bot | Mark race_lost, surface diff, ask user if re-dispatch or skip |
| CI still red | Mark ci_red, surface failing checks, do NOT merge |
| Merge call failed | Capture stderr, mark merge_failed, surface to user |
| Merge call succeeded but mergedAt absent | Mark silent_merge_failure, escalate immediately |
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:
a3f91c2d...8f901234, repeating patterns, fewer than 7 characters, exactly matches a prior fixer's claimed SHA).gh run view <id>.gh pr view --json statusCheckRollup shows fewer or different checks.sleep loops in the bash output but no actual tool call delays in execution timeline.--main sync (only if flag is set)For each repo that has separate dev and main branches:
Check if dev is ahead of main: git -C <path> log main..dev --oneline | head -5
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]If confirmed: create sync PR: gh pr create --repo <repo> --base main --head dev --title "chore: sync dev → main"
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>
If CI green: gh pr merge <sync-pr-number> --repo <repo> --merge (merge commit, not squash; never --admin)
Pull main back into dev: git -C <path> fetch origin && git -C <path> checkout dev && git -C <path> merge origin/main --no-edit
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
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)
──────────────────────────────────────────────────────During this command's execution, invoke the following superpower skills at the specified checkpoint:
superpowers:verification-before-completion + superpowers:finishing-a-development-branchNEVER 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):
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
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:
--admin (or --auto as a workaround for a refused merge).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.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.A merge that landed via bypass cannot be silently undone. Report it immediately, name the commit, and say which gate it skipped.
branch-already-merged. Always surface to the user via AskUserQuestion.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.aborted_for_review and let the user decide..worktrees/salvage-<branch> dir. Sharing the main checkout causes branch-switch collisions.--force-with-lease to branches whose tip they fetched at start of work.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):
${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.
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.
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).
CLAIM_KEY: gh:pr:<owner>/<repo>#<number> (e.g. gh:pr:your-org/your-repo#42)
CLAIM_KEY="gh:pr:<owner>/<repo>#<number>"
ledger query --claim-key "$CLAIM_KEY" --since=-PT24HIf 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 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>"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
SKILL.md and 1 other file (references) in claude-ops/skills/ops-merge of Lifecycle-Innovations-Limited/claude-ops.
Open the folder on GitHubat commit ee9c784
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.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Ops Merge this skillLifecycle-Innovations-Limited/claude-ops | 542 | — | ~8k | Automated safety check: Notes | MIT | |
| PR Babysitteropeninterpreter/openinterpreter | 69k | 3 repos | ~4.2k | Automated safety check: Pass | Apache-2.0 | |
| Greplooponyx-dot-app/onyx | 32k | 4 repos | ~3.3k | Automated safety check: Pass | MIT | |
| GitHub Deep Researchbytedance/deer-flow | 84k | 4 repos | ~1.3k | Automated safety check: Pass | MIT | |
| Diagnosing Superpowers Sessionsobra/superpowers | 297k | 3 repos | ~1.7k | Automated safety check: Pass | MIT | |
| Update V8 Versionopeninterpreter/openinterpreter | 69k | 2 repos | ~845 | Automated safety check: Pass | Apache-2.0 |
openinterpreter/openinterpreter
Watches an open GitHub pull request until it merges, handling review comments, diagnosing CI failures and retrying flaky checks along the way.
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.
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.
obra/superpowers
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.
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.
mvanhorn/last30days-skill
Research what people actually say about any topic in the last 30 days.
Lifecycle-Innovations-Limited/claude-ops
OPS on-demand: This skill should be used when the user asks to "ops dashboard", "pixel HQ", or…
Lifecycle-Innovations-Limited/claude-ops
OPS on-demand: This skill should be used when the user asks to "go to market", "GTM plan", or…
Lifecycle-Innovations-Limited/claude-ops
OPS on-demand: This skill should be used when the user asks to "klaviyo", "ads spend", or…
Lifecycle-Innovations-Limited/claude-ops
OPS on-demand: This skill should be used when the user asks to "tweet", "post to linkedin", or…
Lifecycle-Innovations-Limited/claude-ops
OPS on-demand: This skill should be used when the user asks to "yolo mode", "run the business today"…
Lifecycle-Innovations-Limited/claude-ops
OPS on-demand: This skill should be used when the user asks to "datadog", "APM alerts", or…
Works with
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.
Ops Merge fits situations like: asks to merge PRs; salvage branches.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.