/melt¶
Skill metadata
- License: MIT
- Source:
skills/melt/SKILL.md
When to invoke: Resolve git merge, rebase, or cherry-pick conflicts via a structural-merge cascade โ mergiraf (AST-aware auto-resolve) โ git rerere (replay remembered fixes) โ kdiff3 (manual fallback). Use when conflicts exist and the user wants them resolved โ phrases like "melt the conflicts", "fix the merge conflicts", "resolve the rebase conflicts", "what's conflicting after the merge", "/melt", "fix the cherry-pick", or any prompt that surfaces <<<<<<< markers, CONFLICT (...) git output, or a half-finished merge state. First checks for squash-merge residue (rebase doomed by a squash-merged PR โ abort and re-cherry-pick), then runs the cascade with helper scripts for batch resolution, ours/theirs picks, and lockfile regeneration. Use even when only one file is conflicting if the user wants the structural pass attempted before manual editing. Do NOT use for general git operations without conflicts. After /cook or /cure if a merge step blocked them; before retrying the gate that surfaced the conflict.
Use this skill to resolve git merge, rebase, or cherry-pick conflicts using the structural cascade: mergiraf โ rerere โ kdiff3. Each tool handles what the previous could not.
Do not use it for general git operations without conflicts (those go to a commit or gh skill) or when no conflict markers are present.
File IO delegation¶
melt orchestrates the resolution chain via bash and the helper scripts. For per-file inspection or manual edits, delegate to the cheez-* skills:
/cheez-searchโ locate conflict markers or related symbols across the tree./cheez-readโ inspect conflicted files, view conflict hunks, list directory contents./cheez-writeโ apply hash-anchored resolutions when bash flows are not enough.
The bash-driven flows below cover the bulk of resolution. Drop into the cheez-* skills only when you need to inspect or rewrite a specific file by hand.
Resolution chain¶
| Stage | Tool | What it does | When it runs |
|---|---|---|---|
| 1 | mergiraf |
Tree-sitter structural merge of base / ours / theirs. Independent additions merge cleanly even when text merge would conflict. Falls back to text merge on parse failure. | Automatically as a git merge driver, or via batch-resolve.py. |
| 2 | git rerere |
Replays a previously recorded human resolution for the same conflict signature. | After mergiraf, especially during long rebases where conflicts recur. |
| 3 | kdiff3 |
Manual 3-way diff for what mergiraf and rerere could not resolve. | Launched via git mergetool. |
Protocol¶
0. Squash-residue check¶
Run this before the conflict summary. If the branch was squash-merged into base, mergiraf cannot help โ the right answer is to either merge base in (non-destructive) or abort and re-cherry-pick the unique commits (destructive).
If the verdict is SQUASH-MERGED, surface both printed remedies to the user verbatim and stop the cascade. Neither remedy is auto-applied โ the user picks one and copy-pastes. Flags:
--baseโ base ref to compare against (default:origin/main).--branchโ branch to check (default: current).--jsonโ structured output for scripting.
Detection cascade (strongest first; later signals run only when needed):
tree-matchโ walks commits on base looking for one whose tree equals the tree at some point on the branch. That commit is a squash-equivalent of branch commits up to that point. Works offline, through fork PRs and renames, and handles branches with commits past the squash (the caselocal-synthmisses). Always runs first.gh-apiโ runs in parallel with tree-match. Enriches a tree-match verdict with PR metadata (number, URL, merge commit) when its SHAs correlate with the squash; supplies the verdict on its own when tree-match found nothing.local-synthโ synthesizes a would-be squash commit from HEAD's tree and asksgit cherrywhether base contains an equivalent. Last-resort fallback that only runs when neither tree-match nor gh-api produced a verdict; cannot enumerate squashed vs unique commits.
Verdict semantics:
SQUASH-MERGED(method=tree-matchortree-match+gh) โ strongest signal; unique-commit list is the slice of branch commits after the matched squash point.SQUASH-MERGED(method=gh-api) โ fallback when tree-match found nothing but the gh PR's SHAs overlap with branch commits.SQUASH-MERGED(method=local-synth) โ detected offline only; cherry-pick list must be reviewed by hand.not-detectedโ proceed to the cascade.not-applicableโ on the base branch.
The detector prints two remedies in order:
- [A] merge (non-destructive) โ
git merge <base>. Preserves all branch history; squashed commits collapse to a no-op merge, so only real conflicts surface. Prefer this when the branch has unique work or the unique-commit list is uncertain. - [B] reset-and-cherry-pick (destructive) โ
git reset --hard <base>+git cherry-pick <unique-shas>. Rewrites the branch and requires force-push. Use when a clean linear history is wanted and the unique-commit list looks complete.
Default to suggesting [A] first; only suggest [B] when the user has stated a preference for a linear-history workflow or the unique-commit count is small and verified.
1. Diagnose¶
Run the summary script next; it replaces ad-hoc grep -n '<<<<<<<' parsers and is shaped for low-token output.
Default output is terse: one metadata line per file plus minimally framed hunks. Flags:
--jsonโ structured output for scripting.--verboseโ markdown view for humans.--context Nโ context lines around each hunk (default 3).
For raw git context:
2. Structural resolution¶
For every file mergiraf supports, attempt structural merge:
# Preview (dry-run is the default)
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz batch-resolve
# Apply clean resolutions and stage them
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz batch-resolve --apply
# Markdown output and mergiraf debug logs
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz batch-resolve --verbose
To inspect what mergiraf would produce for a single file without touching the working copy, use --debug:
The script extracts the three stages, runs mergiraf with RUST_LOG=mergiraf=debug, keeps the tempdir, and prints paths to the merged output, the log, and the conflict-marker count. Inspect with cat/diff against the printed paths. If the merged output is clean, apply it:
3. Remaining conflicts¶
After the structural pass, check rerere first:
If rerere already applied, the conflict is resolved. Otherwise drop into the manual tool:
After manual resolution, finish the interrupted operation:
git add <resolved-files>
git merge --continue # or
git rebase --continue # or
git cherry-pick --continue
4. Pick ours / theirs (mergiraf-unsupported files)¶
For shell, SQL, YAML, JSON, and other formats mergiraf does not parse, use conflict-pick.py:
# Take ours for every hunk
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz conflict-pick hooks/session-start.sh --ours
# Take theirs for every hunk
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz conflict-pick .gitignore --theirs
# Match by regex; matched hunks resolve, others remain
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz conflict-pick config.yaml --grep "timeout" --ours
5. Lockfiles¶
Lockfile content has structure that text or AST merge cannot validate. Take one side and regenerate from the manifest:
# Auto-detect conflicted lockfiles, take theirs, regenerate, stage
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz lockfile-resolve
# Preview
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz lockfile-resolve --dry-run
# Take ours instead
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz lockfile-resolve --strategy ours
Supports Cargo.lock, package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, Pipfile.lock, uv.lock, Gemfile.lock, and go.sum.
6. Debug mergiraf¶
When mergiraf is not resolving something it should, use --debug for a single-file inspection (keeps the tempdir, captures RUST_LOG=mergiraf=debug):
python3 ${CLAUDE_SKILL_DIR}/scripts/melt.pyz batch-resolve --debug <path>
mergiraf languages | grep <extension> # is the type registered?
git check-attr merge -- <path> # should show: merge: mergiraf
Common causes:
- Extension missing from
~/.gitattributesโ regenerate after upgrade. - Parse failure on one of the three versions โ mergiraf falls back silently.
- Very large files (>1MB) skip structural merge.
7. Maintenance¶
mergiraf languages --gitattributes > ~/.gitattributes # after upgrade
git rerere status # what is currently tracked
git rerere diff # pending resolution diffs
git rerere forget <path> # forget a bad resolution
git rerere gc # clean old entries
ls .git/rr-cache/ # browse the resolution database
Scripts¶
| Script | Purpose | When |
|---|---|---|
detect-squash-residue.py |
Detect that the branch was squash-merged and emit both the merge and reset+cherry-pick remedies | Run first โ short-circuits the cascade |
conflict-summary.py |
Structured summary with line numbers and context | After residue check |
batch-resolve.py |
Run mergiraf merge over every conflicted file |
Supported languages |
conflict-pick.py |
Choose ours / theirs per hunk | Shell, SQL, formats mergiraf does not parse |
lockfile-resolve.py |
Take one side and regenerate the lockfile | Cargo.lock, package-lock.json, etc. |
Special cases¶
Whitespace-only formatting changes¶
If one branch ran a formatter while the other modified content, mergiraf can produce more conflicts because AST positions shifted. Resolution: run the formatter on the merged result after resolving conflicts.
Unrecoverable state¶
If conflict state is unrecoverable, abort and start over:
/melt surfaces abort as an option; the user decides.
What this skill does NOT do¶
- Push or open PRs โ hand off to a
ghskill. - Run builds or tests โ re-enter
/cookor run project gates. - Commit resolved files outside
git addstaging โ use acommitskill. - Architectural review of merge results โ use
/age. - Read, edit, or search files directly โ delegate to
/cheez-read,/cheez-write,/cheez-search.
Gotchas¶
mergiraf solveflag confusion: use--stdout/-pfor preview, NOT--output.- Markdown is supported by mergiraf but may need
.gitattributesregistration. - Lockfile structural merge is not the same as a valid lockfile โ always regenerate after taking a side.
- zdiff3 base markers (
|||||||) are handled by every script in this skill. - If you see conflicts in a supported file type, mergiraf-as-driver already ran โ you are looking at the residue.
Handoff¶
After resolution finishes, prompt the next step via the shared handoff gate in ../../shared/handoff-gate.md. Include the detected interrupted operation and upstream invocation in the context packet before asking. Default options:
- Resume โ dispatch the exact continuation command for the current operation (
git merge --continue,git rebase --continue, orgit cherry-pick --continue). If the triggering skill invocation is known, return to that skill with the original context after the git operation succeeds; otherwise stop with the resumed git status. - Re-run gates โ dispatch the upstream skill invocation that originally surfaced the conflict so its quality gates run on the merged state.
- Stop โ dispatch none; leave the working tree staged for the user to inspect.
/melt never resumes before the user selects. After a non-stop selection, run the selected continuation immediately.
Rules¶
- Always run
detect-squash-residue.pyfirst; if positive, surface both remedies and stop the cascade. - Always run
conflict-summary.pybefore deciding the cascade order. - Prefer structural resolution over manual edits when mergiraf supports the file type.
- Never weaken or hand-edit a lockfile in place โ regenerate from the manifest.
- Flag unresolved files explicitly; do not claim a clean tree until
git statusagrees. - Never auto-apply a squash-residue remedy โ even the non-destructive merge path rewrites working state; the user copy-pastes their choice.
- Lead with the merge remedy unless the user has asked for a linear-history workflow; reset+cherry-pick rewrites the branch and requires force-push.