# Merge Resolve

> Use when a user asks to resolve a git merge conflict or conflicting patch, says "ai-merge" or "AI-resolve," when merge or rebase exits with conflict markers and next steps are requested, when parallel worktrees need integration, or when a chain diff targets a file being edited.

- Skill: `sumitake/merge-resolve` (Agent Skill)
- Install (CLI): `npx skillmds@latest add sumitake/merge-resolve`
- Raw SKILL.md: https://api.skillmd.com/api/skills/sumitake/merge-resolve/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: sumitake (https://skillmd.com/u/sumitake)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/sumitake/merge-resolve

---


## Unified runtime invocation

Resolve the **plugin root** from this loaded file: `SKILL.md` is at `<plugin-root>/skills/<skill-name>/SKILL.md`. Invoke only `python3 "<plugin-root>/coordinator.py"` and send one bounded JSON routing request on EOF-delimited stdin, without a PTY. Use the Python invocation example in the **Routing request** section in `<plugin-root>/README.md` and the co-packaged manifest's signed `wire_contract`; never invent fields or provider actions. Supply one caller-defined work unit per independently useful deliverable, with this skill's logical action and a bounded opaque payload. Use `depends_on` only for actual dependencies. Honor an operator-named provider with `explicit_target`. For an authorized independent review or governance task without an operator-named provider, also use that field to bind the caller-verified distinct reviewer selected by the caller or designated by the workflow. Carry the same target into planning and live dispatch; verify returned native lineage before accepting independence. Otherwise use normal untargeted routing. Choose quality and effort for the workload; include context/output token estimates when known. Read the current manifest digest and actual cwd device/inode; do not copy example values. The runtime owns its timeout; do not wrap it in a shorter fixed timeout. Repository identity, source-head verification, disposable copies, patch capture, and cleanup remain caller-owned where applicable. The shim runs standalone from the installed plugin and transports the routing client's bounded result without semantic interpretation. Never discover a provider executable, reconstruct a raw command, or replay, retry, or fail over a consumed work unit. Provider status, terminal records, receipts, telemetry, and other structured fields are optional diagnostics; none is a content-availability gate. Preserve every returned content record or recovered partial response and interpret it with ordinary model reasoning. Never synthesize approval, authority, or a receipt from process exit or missing diagnostics. A planning-only request sets `dispatch_requested=false`; a live request sets it true and consumes at most one provider attempt per work unit.
Planning reports route eligibility, not live availability or authentication. Report a caller/client failure at that layer; provider state remains unknown unless native evidence establishes it. Content availability and each work unit's `execution_status` are separate facts.

# Merge resolve — merge-conflict resolution, operator-gated by default

This skill is the inter-branch analogue of `chain`'s semantic gate (`kind: semantic, check: ai_cross_check`): a review of the two sides' intent + commit context, a proposed unified resolution as a diff, and an **operator-confirm gate** before any change touches the working tree. The cross-check is the engine; the operator-confirm and the validator gates are the safety net.

**The default is operator-confirm. Auto-apply is opt-in, gated by a multi-condition policy file, and refuses for high-sensitivity paths regardless of operator opt-in.** These are the operator's risk-acceptance posture; they are not stylistic prose, and the skill enforces them at runtime.

Reviewer independence is conditional on the caller verifying the observed families and sources under the contract below; the role or branch name does not establish it.

## When to use

**Explicit triggers** (user-typed): "resolve this merge conflict," "ai-merge," "merge with the reviewer," "have the reviewer help merge," "AI-resolve this conflict," "use the reviewer to merge this."

**Situational triggers** (proactive):

- A `git merge` or `git rebase` exited non-zero with conflict markers in the recent transcript.
- `git status` shows `Unmerged paths:` and the user asks anything about next steps.
- Worktree-fanout / parallel-agent flows need N parallel results to integrate back to a base branch.
- A chain step produces a diff destined for a file the user is currently editing (potential conflict surface).

## When to skip

- **The conflict is trivial** (whitespace-only, deterministic merge of a generated file) — let `git mergetool` or the user's editor handle it; the cross-check overhead is not worth it.
- **The user wants the AI to *commit* and *push* the merge** — out of scope. This skill ends at "applied to working tree, operator confirms"; commit + push are the operator's actions.
- **The conflict is in `forbidden_paths` (defined below) and the user wants auto-apply** — refuse and surface; require operator-confirm regardless of any auto-apply opt-in.

<!-- verifier-independence:start -->
## Verifier independence (functional contract)

Independence is caller-verified governance evidence, not a routing guarantee.
For independent governance evidence, before dispatch record the observed lineage
and source for both the active primary and artifact author. Select a reviewer only when its known lineage is
distinct from both. The caller may use provider-free planning to inspect known
family evidence. Honor an operator-named provider; do not silently replace it.
For an authorized independent review or governance task without an operator-named
provider, bind the verified reviewer selected by the caller or designated by the
workflow using `explicit_target`. Carry that same target into planning and live
dispatch; untargeted planning does not bind a later live request. If the target
becomes unavailable, report it without silent substitution or replay.
If no known-distinct eligible reviewer is established, do not dispatch
as independent governance; explain the missing lineage or selection evidence.
An OpenCode name is transport information, not lineage. Use only a
descriptor-admitted review or governance action; never substitute document
intent for review.

After the response returns, record the observed reviewer lineage and source.
Accept the response as independent governance evidence only when all three
lineages are known and the reviewer differs from both the primary and artifact
author. A route, provider name, status, receipt, or self-assertion alone does
not prove lineage. Preserve unknown lineage as unknown. Do not replay a
consumed review to repair missing lineage; retain it only as clearly labelled
advisory content.
<!-- verifier-independence:end -->

## Inputs

| Input | Required | Type | Description |
|---|---|---|---|
| `conflict_files` | yes | list[path] | Files with conflict markers (or a patch + base ref) |
| `base_ref` | yes | string | Common ancestor ref (e.g., `main`) |
| `intent_a` | optional | string | Free-form description of side A's goal (defaults to commit message(s) on side A) |
| `intent_b` | optional | string | Free-form description of side B's goal |
| `auto_apply` | optional, default `false` | bool | If `true`, skip operator-confirm — RESERVED for non-interactive CI with strict preconditions (see Safety constraints) |

If the operator only said "resolve this conflict" without listing files, START with `git status` via Bash to identify the conflicted files; ask one consolidated question if any required input remains unclear.

## Procedure

### 1. Verifier-independence check

Record the observed lineage of the primary and the authors of both sides. For independent review, select and verify a resolver distinct from the primary and every known side-author family; unknown author lineage leaves independence unverified. Primary-authored sides alone do not prove independence. If no eligible distinct resolver can be established, keep required independent approval unmet. Advisory merge analysis may proceed when the task does not require independent evidence; changing roles cannot create independence.

### 2. Hunk extraction

For each file in `conflict_files`:

1. Read the file via the Read tool.
2. Parse conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`).
3. Build a structured `Conflict` record per hunk: file path, line range, side-A lines, side-B lines, ±20 lines of surrounding context.
4. If a file has no conflict markers (listed but already resolved), skip and report.

### 3. Context gather

For each side, collect:

1. Commit message(s) introducing the hunk on each branch (`git log -p <base_ref>..<side_ref> -- <file>` or `git blame` on the conflict lines).
2. The pre-merge file state on each side (downstream-impact analysis).
3. The base-ref version of the file (`git show <base_ref>:<file>`).

If `intent_a` / `intent_b` were not supplied, derive them from the commit messages as one-sentence summaries per side.

### 4. Cross-check prompt

Before dispatch, select a reviewer with known lineage distinct from the observed
primary and authors of both sides for independent review. For advisory analysis, label the contribution accordingly. Submit the sealed merge-review role through
`python3 "<plugin-root>/coordinator.py"` with `quality_profile='frontier'` and `effort_class='maximum'`. Verify the observed
reviewer lineage before treating its response as independent governance evidence.
Provider formatting is not an output contract; reason over the complete raw
response. Ask the reviewer to address these disagreement-first criteria:

- summarize each side's intent;
- decide `COMPATIBLE`, `INCOMPATIBLE`, or `NEEDS-HUMAN`, with a reason;
- propose a unified diff when compatible;
- identify risks and failure modes; and
- state `H`, `M`, or `L` confidence with a reason.

Use this prompt:

```
Two branches modified the same region. Analyze both intents and either propose
a unified resolution or explain why the change is incompatible or needs human
judgment. Clearly state the compatibility decision, include a unified diff when
compatible, identify risks, and state confidence. Cap the analysis at 500 words.

--- HUNK ---
{structured hunk + commit-context + surrounding-±20-lines}
```

Reason over the full raw response and deduce whether it supports compatibility
and a concrete resolution. If it does not, refuse to proceed and explain the
missing basis. Preserve partial prose and never replay for formatting.

### 5. Operator-confirm gate (DEFAULT)

UNLESS `auto_apply=true` AND **all** the auto-apply preconditions in Safety constraints below are met, present the proposed resolution as a clear diff with the reviewer's full raw response for the operator. The operator chooses:

- **`apply`** — apply the resolution to the working tree
- **`apply-and-amend`** — apply AND amend the in-progress merge commit (only valid mid-merge)
- **`reject`** — discard the proposal; leave conflict markers in place for manual resolution
- **`revise <free-form>`** — make a separately operator-authorized Step 4 request with the operator's additional instruction prepended to the prompt

Empty / ambiguous operator responses default to **`reject`** (safe choice).

### 6. Apply (only on `apply` / `apply-and-amend`)

1. `git apply --3way --check` to verify the patch applies cleanly.
2. If the check fails, fall back to in-place file replacement (Read → modify conflicted region → Write).
3. If the in-place replacement produces a syntactically invalid file (compiler / parser detects), surface to operator and refuse to proceed.
4. Verify no conflict markers remain after apply (re-Read; no `<<<<<<<` / `=======` / `>>>>>>>`).

### 7. Post-apply validation (via `gates:` block — operator-defined)

If invoked from inside a chain step, the calling step's `gates:` block defines the post-apply validators. Typical operator-configured validators:

- A `kind: filesystem, check: bash_exit_code` running the project's test suite (`pytest -q`, `go test ./...`, `npm test`, etc.), `on_fail: halt`.
- A `kind: semantic, check: ai_cross_check` verifying the applied resolution preserves both sides' intent without semantic loss, `on_fail: halt`.

Invoked standalone (not from a chain), Step 7 is informational — surface the operator a suggested validator set + offer to run the project-detected test runner via Bash and report the exit code.

## Safety constraints (NON-NEGOTIABLE)

These are runtime-enforced by the skill. They are not stylistic suggestions; the skill refuses to proceed past them.

- **Never auto-apply without operator-confirm by default** (`auto_apply` defaults to `false`).

- **`auto_apply=true` preconditions (ALL four required, no exceptions)**:

  1. **An operator-pre-approved validator-policy file is present** at `.claude/merge-resolve-policy.yaml` (project-scoped) OR `~/.claude/merge-resolve-policy.yaml` (user-scoped). The policy file's *presence* is the operator's signed acknowledgment of the auto-apply opt-in; the skill refuses auto-apply if the policy file is missing.

     **Caveat — presence-checked, not substance-checked**: the skill verifies the calling chain step's `gates:` block contains each `required_gates:` entry from the policy (by kind + check). It does NOT verify the gate's substance is meaningful — an operator could configure `bash_exit_code: { command: "true" }` to satisfy the letter of the policy while bypassing the actual test suite. Substance is the operator's responsibility.

     The current project's policy file is authoritative. At minimum it declares:
     `enabled`, `required_gates`, `min_confidence` (default `H`), and
     `forbidden_paths`; reject unknown policy fields.

  2. **The cross-check's `CONFIDENCE` must equal the policy's `min_confidence`** (default `H`). `M` or `L` falls back to operator-confirm regardless of `auto_apply`. A confident-but-wrong automated merge is a high-risk failure mode; this is the policy's hard line.

  3. **The conflicted file MUST NOT match any pattern on the policy's `forbidden_paths` list.** Default forbidden paths cover authentication / secrets / migrations / schema / configuration / environment files — i.e., the surfaces where an LLM-merge mistake has the worst blast radius. Operators extend the list for project-specific sensitive surfaces (HIPAA-PHI, PCI-DSS-cardholder-data, regulated-trading code, dosing calculations, etc.). The default list at minimum: `migrations/**`, `**/secrets/**`, `.env*`, `**/auth*`, `*.sql`.

  4. **The calling chain step's `gates:` block MUST include at minimum each `required_gates:` entry from the policy file.** If any required gate is missing, refuse auto-apply.

- **Never resolve `COMPATIBILITY: INCOMPATIBLE` or `NEEDS-HUMAN` verdicts automatically.** Surface to operator with the verifier's reasoning and refuse.

- **Never `git push` from this skill.** Resolution applies to working tree only; push is the operator's call.

- **Never `git commit` from this skill** (the `apply-and-amend` operator choice is the only commit-touching action, and only amends the in-progress merge commit).

- **Conflict-marker integrity check.** After any apply, re-Read the file and confirm no `<<<<<<<` / `=======` / `>>>>>>>` markers remain. If they do, the apply silently failed — refuse to mark the merge resolved and surface to operator.

### Known inherent risks (acknowledged, mitigated, not eliminated)

The design fundamentally assumes a language model can reliably infer the semantic *intent* of two conflicting changes. This is a hard problem. A passing test suite does not prove a resolution preserves both sides' intent — tests may have gaps around the specific logic being merged. These risks are inherent to the LLM-merge problem class, not introduced by this skill's design.

Mitigations:

- Operator-confirm default (the single biggest one).
- Multi-condition auto-apply preconditions (policy file + min_confidence + forbidden_paths + required_gates).
- `CONFIDENCE: H` floor.
- Caller-verified reviewer independence where required, with missing evidence left explicitly unmet.
- Post-apply validator gates (operator-defined).

These shift residual risk down but do not eliminate it. Operators adopting `auto_apply=true` accept the residual risk explicitly via the policy file's presence-as-acknowledgment.

### Suggested rollout: shadow-mode first

For the first 10–20 real merges, run with the policy file present but `shadow_mode: true`. The runner logs the would-be auto-apply decision and compares against the operator's manual choice. After high agreement, flip `shadow_mode: false`. (Shadow-mode is a v0.2 pattern in the workspace spec doc; v0.1 ships with operator-confirm-default and no shadow-mode infrastructure.)

## Examples across domains

| Domain | Conflict scenario | Why this skill fits |
|---|---|---|
| Backend / web | Two PRs both touched the same handler's auth check | Cross-family read catches if one side relaxed a check the other tightened |
| Data engineering | Concurrent edits to a transformation function in an ETL pipeline | Semantic-incompatibility detection (one side filters X, other aggregates X) |
| Platform / infra | Parallel changes to a Terraform module's resource block | Forbidden-paths default catches `.sql`, `migrations/**`; operator opts in for IaC if appropriate |
| Documentation | Two authors revised the same section of a spec doc | Lower-stakes; operator-confirm + auto-apply if doc passes a build-the-docs gate |
| Localization | Translation team and product-team both edited a strings file | Auto-apply candidate after the build-the-app gate passes |
| Configuration | Parallel changes to a feature-flag YAML | Forbidden-paths often includes config; operator-confirm by default |
| Test code | Concurrent additions to the same test file | High auto-apply suitability — test-suite-gate verifies correctness directly |
| Schema migration | Conflicting `ALTER TABLE` statements | Forbidden-paths default `*.sql` + `migrations/**` blocks auto-apply — operator must review |
| Clinical / regulated | Concurrent edits to a dosing-calculation module | Operator extends `forbidden_paths` to include this; operator-confirm only |
| Library upgrade | Two PRs upgraded a shared dependency to different versions | Cross-check often returns `NEEDS-HUMAN` — version-pin disagreement is a coordination question, not a merge question |

## Failure modes

| Failure | Skill behavior |
|---|---|
| Conflict markers malformed | REFUSE; surface raw conflict + line number that failed parsing |
| Raw response supports no compatible proposed resolution | REFUSE; surface the missing basis; preserve the response and do not replay for formatting |
| `git apply --3way --check` fails on the proposed resolution | Use the same artifact for the Step 6 in-place check; if that is invalid, REFUSE without another provider request |
| Operator gives empty / ambiguous response to confirm gate | Default to `reject` (safe) |
| `CONFIDENCE: L` on a file matching `forbidden_paths` | REFUSE auto-mode; require operator-confirm |
| Reviewer shares a primary or side-author family, or required lineage is unknown | Keep independent approval unmet; retain useful advisory analysis where permitted. Switching to the primary cannot establish independence |
| Policy file is syntactically invalid | REFUSE auto-apply; fall back to operator-confirm; surface YAML error |
| Post-apply marker-integrity check finds remaining markers | REFUSE to mark merge resolved; surface failed line(s) to operator |

## Output format

Whether the operator chose `apply`, `reject`, `apply-and-amend`, or `revise`, surface a final summary:

```
merge-resolve summary:
  file: <path>
  hunks resolved: <N> of <M>
  verifier CONFIDENCE: H | M | L
  decision: applied | rejected | applied-and-amended | revised-and-re-proposed
  validators run (if Step 7 applicable): <list with PASS/FAIL>
  remaining conflicts: <list of files still with markers, or "none">
  next step: <e.g., "run `git status`; if clean, `git commit` the merge", or "re-run on remaining files">
```

## Anti-patterns

- **Auto-applying because the operator said "just merge it."** The `auto_apply=true` requires the policy file's presence + `CONFIDENCE: H` + forbidden-paths-clear + required-gates-met. Verbal operator urgency does NOT substitute for the policy file's presence-as-acknowledgment.
- **Configuring trivial bypass gates** (e.g., `bash_exit_code: { command: "true" }`) to satisfy a `required_gates:` requirement while bypassing the actual test suite. The skill verifies kind + check; substance is operator responsibility. If chains consistently use trivial-bypass gates, revisit the policy or the chains — someone is gaming the linter.
- **Skipping the cross-check on a "trivial" merge.** Every merge looks trivial until it isn't. The cross-check cost is small; bypassing defeats the skill's purpose.
- **Trusting `CONFIDENCE: H` on a merge involving auth, secrets, or schema** even if the policy doesn't explicitly forbid the path. The default `forbidden_paths` list exists for a reason; if the operator has narrower paths, they should still review high-sensitivity merges manually.
- **Treating `apply-and-amend` as the default.** It rewrites the in-progress merge commit. Use only when the operator explicitly chose it; default `apply` leaves the apply uncommitted so the operator can review one more time.
- **Pushing or committing from this skill.** Out of scope; the skill ends at "applied to working tree, operator confirms."
- **Re-running the same `revise` instruction repeatedly without operator input.** `revise` is a single-iteration instruction; if it fails, ASK the operator for next direction rather than looping.
- **Using role switching as proof of independence.** A resolver must have observed lineage distinct from the primary and authors of both sides when independent review is required. Switching to the primary cannot clear that requirement; same-family or unknown-lineage analysis remains advisory.
- **Skipping the marker-integrity check** after apply. A silent apply failure leaves markers in the file; the merge appears resolved in the skill's response but the working tree is still in conflict. The check is one Read; never skip it.
- **Adding `forbidden_paths` to the policy without versioning the change in source control.** The policy is the operator's risk-acceptance posture; its history is auditable evidence. Edit, commit, push — don't `chmod 644 && vim` it in place.

