Skip to main content

AI-powered code merge agent with browser UI — plan, review, and resolve conflicts across long fork histories

Project description

中文 | English

🔀 Code Merge System

Ship upstream upgrades to long-lived forks — without the 500-file conflict nightmare.

A multi-agent pipeline that turns months of upstream drift into an auditable, resumable, and safe merge — preserving every fork customization along the way.

Python 3.11+ Tests Coverage License Anthropic

Code Merge System Dashboard


The Problem

Teams that maintain a long-lived fork face a brutal reality when syncing with upstream:

  • Hundreds to thousands of file conflicts — impossible to handle manually, one by one
  • Line-level diffs hide semantic intent — LLMs and humans both make the wrong call
  • Fork-only customizations get silently overwritten — APIs, routes, CI jobs, sentinels disappear without a trace
  • One wrong merge creates runtime vulnerabilities or missing features — and they're hard to roll back

git merge gives you a list of conflicts. Code Merge System gives you a decision pipeline.


Quick Start

pip install code-merge-system

export ANTHROPIC_API_KEY=sk-ant-...
export OPENAI_API_KEY=sk-...

cd /path/to/your-fork-repo
merge                            # opens the browser; the first-run wizard walks you through setup

First run opens a browser UI and walks you through a one-time setup wizard — pick your target branch, keys, and (optionally) dry-run (plan only, no file writes). Your choices are saved to .merge/config.yaml — no wizard on subsequent runs. To preview the plan without touching files, enable dry-run in the wizard or set dry_run: true in .merge/config.yaml.

No API keys? Drive a local coding-agent CLI you're already logged into (Claude Code / Codex / Grok Build / Gemini CLI) instead — see Run Without API Keys — ACP Backend.


See It In Action

Plan Review — 124 files analyzed, 87.9% auto-merge confidence, risk distribution across A–E change categories.

Plan Review

Conflict Resolution — Side-by-side intent analysis of fork vs. upstream changes, with LLM-recommended merge strategy (SEMANTIC_MERGE 85% confidence).

Conflict Resolution

Judge Verdict — Independent review agent audits every merged file; CRITICAL/HIGH/MEDIUM/LOW issue breakdown with repair rounds.

Judge Verdict

Run Report — Full cost accounting ($0.04 for 124 files), per-agent token breakdown, learned memory entries for future runs.

Run Report


How It Works

Eight phases driven by a state machine. Seven specialized agents. Every write is snapshotted. Any Ctrl+C is safe.

┌─────────────────────────────────────────────────────────────┐
│  CLI / Web UI                                               │
│         │                                                   │
│   Orchestrator ── 8-phase state machine                    │
│         │                                                   │
│  ┌──────┴───────┐                                          │
│  │              │                                           │
│ Agents        Tools              Memory                     │
│ (7 roles)   (50+ deterministic   (L0/L1/L2                  │
│              + AST parsers)       cross-run store)          │
│  │                                                          │
│ LLM layer (Anthropic + OpenAI, credential pool, routing)   │
└─────────────────────────────────────────────────────────────┘
Phase What happens
INITIALIZE 3-way classification, risk scoring, fork-profile routing
PLANNING Planner generates merge plan with per-file strategy
PLAN_REVIEW PlannerJudge audits the plan; up to 2 revision rounds
AWAITING_HUMAN You review the plan report; fill in any HUMAN_REQUIRED decisions
AUTO_MERGING Executor applies auto-safe files with snapshot-before-write
CONFLICT_ANALYSIS ConflictAnalyst does semantic analysis on risky conflicts
JUDGE_REVIEW Judge + 50+ deterministic scanners audit all merged output
COMPLETED Full report generated; you decide when to git commit
Agent Role Default Model
Planner Generates merge plan Claude Opus
PlannerJudge Reviews plan (read-only) GPT-4o
ConflictAnalyst Semantic analysis of high-risk conflicts Claude Sonnet
Executor Sole write authority — applies merges GPT-4o
Judge Reviews merged output + runs deterministic checks Claude Opus
HumanInterface Generates decision templates Claude Haiku
SmokeTest Post-merge smoke testing

Why two LLM providers? Planner/Judge use Anthropic; Executor/PlannerJudge use OpenAI. Different providers for reviewer vs. writer eliminates collusion bias.


Features

Six Lost-Pattern Detectors

Shadow conflicts, interface reverse impacts, top-level call drops, config line preservation, scar auto-learning, and business sentinel scanning — the failure modes that git merge misses entirely.

Snapshot-Before-Write

Every file write creates a snapshot of the original. Any failure triggers automatic rollback. You never end up with a half-merged file.

Full-Run Checkpointing

State is persisted after every phase. merge resume --run-id <id> picks up exactly where you left off — useful for large merges that take hours.

Explicit Human Decisions

No TIMEOUT_DEFAULT. No silent fallbacks. Files that need human judgment generate a decisions.yaml template; skipped decisions stay as AWAITING_HUMAN until explicitly resolved.

Multi-Language AST Chunking

Python, TypeScript, JavaScript, Go, Rust, Java, and C all use tree-sitter for semantic-level diff — not just line-level.

Cross-Run Memory

Decisions, disputes, and metrics are summarized into a SQLite store. Future runs on the same repo load relevant history to inform planning.

Baseline-Diff Gate

CI validation only flags newly introduced failures — not pre-existing ones. Merging into a repo with a known broken test won't block you.

Browser Web UI

Real-time pipeline progress, conflict resolution UI, plan review, judge verdict — all in a local browser app. Use --ci for non-interactive JSON output in CI.


Compared to Alternatives

Code Merge System git merge / git rebase GitHub/GitLab UI LLM chat (ChatGPT etc.)
Handles 500+ file conflicts ❌ Manual, one-by-one ❌ Context limit
Preserves fork-only features ✅ Auto-detected via scar/sentinel ❌ Easy to overwrite ❌ No repo context
Auditable decision trail ✅ Per-file, with rationale Partial (PR comments)
Resumable after interrupt ✅ Checkpoint after every phase
Deterministic safety checks ✅ 50+ scanners post-merge
Cost ~$0.04 for 124 files Free Free Per-token, no automation

Can You Trust the Output?

A merge tool is only worth as much as the evidence that its output is correct. This project ships a formal evaluation framework and an auditable self-learning loop — and reports their results honestly, including where the numbers are not yet impressive.

Evaluation against human golden merges

We do not ask the LLM judge to grade its own verdict. The framework under docs/evaluation/ measures system output against expert human golden merges as ground truth, scoring five trust dimensions at once — a system that blindly takes upstream and scores 100% "coverage" while losing half the fork's work must still fail:

Dimension Question it answers Key metrics
Correctness Did it merge what should merge, correctly? miss-merge rate, wrong-merge rate, conflict-resolution accuracy
Safety Did it silently drop private changes? M1–M6 semantic-loss recall, security-sensitive escalation rate, snapshot rollback rate
Process Trust Does it escalate uncertainty instead of guessing? over-escalation rate, plan-dispute hit rate, Judge↔ground-truth agreement
Explainability Can every decision be replayed? rationale completeness, discarded_content retention, trace replayability
Operational Stable across re-runs and models? Cost bounded? decision consistency, $/run, wall-time P95

Three dataset tiers feed it: Tier-1 micro-bench (30–60 PRs, runs in CI), Tier-2 real long-span replays (human merge diff = oracle), Tier-3 adversarial injections (does it actually catch M1–M6?). The harness lives in scripts/eval/ (prepare.py → run.py → diff_against_golden.py → summarize.py → gate.py).

Hard gates that veto a release (acceptance.md): wrong-merge rate = 0%, security-sensitive escalation = 100%, private-content retention = 100%, snapshot rollback = 100%, duplicate top-level symbols = 0, hallucinated cross-module references = 0; miss-merge ≤ 2% (Tier-1), each M1–M6 recall ≥ 95%. Soft gates track overall accuracy (≥ 92% Tier-1), determinism (≥ 90% across 3 runs), cross-model consistency (≥ 85%), and cost/latency drift caps.

Honesty over marketing: the version-baseline table in acceptance.md is still seeded with a template row — no release has cleared the full gate yet, so we make no "evaluated & trusted" claim. The framework exists precisely so that claim, when made, is backed by lockable dataset SHAs and per-file golden diffs rather than a "99% merge success" headline.

Self-learning — measured, not assumed

The system improves across runs without weight fine-tuning and without embeddings — a deliberate choice backed by a 24-source survey (see docs/plan/self-learning-system.md): non-parametric, auditable SQLite memory + execution-grounded reflection beats opaque RL on cost and deletability.

Phase What it does Status
P0 Effectiveness metric Ablation harness: memory=on vs memory=off decision lift Landedmerge eval-memory
P1 Grounded feedback loop Persistent auditable suppression of harmful entries · confidence write-back from judge+compile+ci signals · verified-repair recipe library Landed, feedback loops opt-in until ablation proves net gain
P2 Memory-quality hardening High-information entries enforced · key invariants pinned against summarization drift Landed
P3 Offline prompt optimization merge optimize-prompts ranks gate-prompt variants against a golden set, emits a human-review report — never auto-applies Landed, opt-in

The governing rule is measure before you activate: a feedback loop only flips to on-by-default after merge eval-memory shows lift > 0 and causally-attributed harm = 0 on a fixed dataset. First baseline (forgejo, 124 files): lift measured at 0.0000 — so the loops stay opt-in. That run was dominated by deterministic mechanisms (take-target + veto), leaving memory no room to act; it does not prove memory worthless, and an LLM-judgment-dense dataset is needed to measure real lift. We report the zero rather than hide it — that is the trust signal.


Prerequisites

Python 3.11+ mypy strict / Pydantic v2 / async throughout
ANTHROPIC_API_KEY Planner, ConflictAnalyst, Judge, HumanInterface
OPENAI_API_KEY PlannerJudge, Executor (dual-provider anti-collusion)
GITHUB_TOKEN (optional) GitHub integration — pull PR comments, push merge results
Node.js (optional) Web UI development only; the installed wheel bundles web/dist/

Both API keys can be replaced by a local coding-agent CLI subscription — see Run Without API Keys — ACP Backend. In that mode no API key is needed at all, and Node.js becomes a runtime requirement (the backend CLIs launch via npx).

Target repo must:

  • Be a git repo with a clean working tree (git status shows no uncommitted changes)
  • Have upstream accessible locally — either as a branch or via git fetch <remote>
# If you haven't added upstream yet:
git remote add upstream https://github.com/<owner>/<repo>.git
git fetch upstream

Run Without API Keys — ACP Backend

Instead of per-token API keys, the system can drive a local coding-agent CLI you are already logged into over ACP (Agent Client Protocol — JSON-RPC 2.0 over stdio). All 7 agents then bill against that CLI's subscription, and neither ANTHROPIC_API_KEY nor OPENAI_API_KEY is needed.

The two modes are mutually exclusive and global — every agent uses API keys, or every agent uses ACP. There is no fallback across the boundary (cross-provider circuit-breaker fallback still works inside API-key mode); config validation rejects a mixed agents: block.

Everything above the LLMClient seam is unchanged: retries, circuit breaker, budget gate, cost tracking, context compression, the four response-parser quality gates, and apply_with_snapshot rollback all keep working.

1. Install the extra, then log into a backend CLI

pip install 'code-merge-system[acp]'
Backend Launch line (wizard preset)
Claude Code npx -y @zed-industries/claude-code-acp
Codex CLI npx -y @zed-industries/codex-acp
Grok Build npx -y @xai-official/grok agent stdio
Gemini CLI npx -y @google/gemini-cli --acp
Custom any command that speaks ACP over stdio

Log into the CLI itself first (claude / codex / grok / gemini). ACP reuses that login state — this system never reads, stores, or forwards a credential.

2. Pick ACP in the setup wizard

cd /path/to/your-fork-repo
merge

In the first-run wizard, open ACP (local CLI subscription), choose a backend (or Custom and paste a launch line), optionally set the real context window, and save. All 7 agents are written as provider: acp:

agents:
  executor:
    provider: acp
    model: acp:claude_code        # routing / display label only — does NOT select the CLI's model
    api_key_env: ""               # always empty under ACP
    request_timeout_seconds: 600
    acp:
      command: npx
      args: ["-y", "@zed-industries/claude-code-acp"]
      pool_size: 2                # total concurrent sessions for this backend
      startup_timeout_seconds: 60
      context_window: 200000      # token budgeting; never derived from `model`
    # no `fallback`: ACP and API-key providers never fall back to each other

Processes are spawned lazily (first LLM call, not construction), stay resident, and are pooled per (command, args) so seven agents on the same backend share one pool rather than starting 7×pool_size node processes.

3. Validate

merge validate --config .merge/config.yaml

Under ACP this checks the launch command resolves on PATH instead of checking API-key env vars.

4. CI / non-interactive

With no API keys in the environment, merge --ci bootstraps a full-ACP config when MERGE_ACP_BACKEND is set:

export MERGE_ACP_BACKEND=auto      # or claude_code | codex | grok | gemini
merge --ci

auto picks the first preset whose command is on PATH. custom is deliberately not a legal value here — the CI path has no channel to supply a launch line. Unset means the usual API-key skeleton.

Safety boundary

A coding agent that can edit files on its own would punch straight through the Executor must snapshot before writing constraint. So the ACP transport locks the client side down: ClientCapabilities() stays all-false, request_permission always refuses, every fs/terminal method raises, and the session's cwd is an empty scratch directory — not the repository. A no-tools preamble is prepended to each prompt so the backend does not waste a turn probing for tools it cannot use.

Known limits

  • No cross-provider review independence. All agents land on one backend, so the "Planner on Anthropic, PlannerJudge on OpenAI" anti-collusion split is given up. This is an accepted trade-off, not an oversight.
  • usage is optional in the protocol. Grok Build returns none, so token metering, cache hit-rate, and the budget gate read 0 on that backend (a one-time warning is emitted). Claude Code / Codex report usage normally.
  • Prompt adherence varies by backend, and a backend that requests tool permission can get its whole turn cancelled. Real-run evidence, per-agent success rates, and the resulting fixes are written up in docs/fixes/2026-07-29-acp-grok-e2e-findings.md.
  • Design rationale and protocol details: docs/plan/acp-llm-backend.md.

Full Workflow

1. Plan (dry-run)

Enable dry-run in the setup wizard (or set dry_run: true in .merge/config.yaml), then:

cd /path/to/your-fork-repo
merge

The browser UI opens and runs through INITIALIZE → PLANNING → PLAN_REVIEW → AWAITING_HUMAN then stops. Check the output reports:

.merge/plans/MERGE_PLAN_<run_id>.md   # file-by-file merge strategy
.merge/runs/<run_id>/plan_review.md   # PlannerJudge audit record

2. Merge

Disable dry-run in .merge/config.yaml (dry_run: false), then run for real:

merge

Any Ctrl+C is safe — resume with merge resume --run-id <id>.

3. Handle Human Decisions

When the system pauses at AWAITING_HUMAN, fill in .merge/runs/<id>/decisions.yaml:

- file_path: "backend/services/auth/auth.service.ts"
  decision: take_current          # take_target / take_current / semantic_merge / escalate_human
  rationale: "Fork uses SSO  must preserve"

Then resume:

merge resume --run-id <id> --decisions .merge/runs/<id>/decisions.yaml

4. Review and commit

.merge/runs/<run_id>/merge_report.md    # final report
.merge/runs/<run_id>/checkpoint.json    # full state
.merge/runs/<run_id>/logs/run_<id>.log  # complete execution log

The system stops at the working tree. It never auto-commits or auto-pushes — you review, then decide.

Intermediate commits vs target-repo hooks

Merges land layer by layer. A half-merged tree will often fail the target repo’s full typecheck / lint hooks (Cannot find module, missing exports) — that is expected, not a bug. Compile verification is owned by this system’s build_check gates after the merge flow, not by the target’s pre-commit hooks.

If intermediate commits are blocked by hooks, skip them on the target repo side (examples only — pick what matches your hook manager; git-native --no-verify / core.hooksPath is the universal fallback):

git -c core.hooksPath=/dev/null commit -m "..."
# or
git commit --no-verify -m "..."
# or e.g. HUSKY=0 / LEFTHOOK=0 / PRE_COMMIT_ALLOW_NO_CONFIG=1

Details: docs/modules/core.md §7.4.


All Commands

Target branch, dry-run, and thresholds all live in .merge/config.yaml (created by the wizard) — the merge command itself takes no positional branch argument.

⚠ Trust model — .merge/config.yaml is executable code. The gate, smoke-test, and build-check commands in it are run verbatim in a shell. Treat the file with the same care as a shell script: review it before running merge after switching branches or pulling changes that may have rewritten it. Each run fingerprints those commands and raises a visible alarm (and a log entry, including under --ci) when the command surface changed since the previous run — it warns, it does not block.

# Daily use
merge                                         # default: browser Web UI (first run walks the wizard)
merge --web-port 5173 --ws-port 8765          # override the Web UI / bridge ports
rm .merge/config.yaml && merge                # re-run the setup wizard

# Resume / decisions
merge resume --run-id <id>
merge resume --run-id <id> --decisions decisions.yaml
merge resume --run-id <id> --web              # view history in browser

# Validate
merge validate --config .merge/config.yaml    # check config + all API keys

# Fork profile (only needed when fork deleted ≥30 files)
merge forks-profile init -o .merge/forks-profile.yaml
merge forks-profile diff
merge forks-profile validate

# CI
merge --ci                                    # non-interactive, JSON summary to stdout
merge --ci --auto-decisions <yaml>
MERGE_ACP_BACKEND=auto merge --ci             # zero-key bootstrap onto a local ACP CLI

Troubleshooting

Symptom Fix
API Key not set Run merge validate --config .merge/config.yaml; check shell env → .merge/.env~/.config/code-merge-system/.env
working tree dirty git stash or git commit, then re-run
upstream ref not found Run git fetch upstream; use upstream/main not main
Plan review stuck in multiple rounds Normal — Planner and PlannerJudge are negotiating; after max_plan_revision_rounds=2 it transitions to AWAITING_HUMAN. Check plan_review.md.
Run interrupted mid-way merge resume --run-id <id> (find run_id under .merge/runs/)
Want to start over rm -rf .merge/runs/<id>/, then re-run
ACP: ... requires 'agent-client-protocol' pip install 'code-merge-system[acp]'
ACP: launch command not found The backend CLI is not on PATH — install it (or npx), then re-run merge validate
ACP: stopReason='cancelled' The backend asked for a tool permission and was refused. Retries/bisect usually recover; see the findings doc
ACP: token counts and cost all zero The backend does not report usage (e.g. Grok Build) — metering and the budget gate are inert there

Development

git clone <repo-url> && cd code-merge-system
python3.11 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

pytest tests/unit/ -q               # unit tests (no LLM calls)
pytest tests/integration/ -v        # integration tests (real API, local only)
mypy src                            # type check (strict)
ruff check src/ && ruff format src/ # lint + format

# Web UI (only needed for frontend changes)
cd web && npm install
cd web && npm run dev               # Vite dev server at localhost:5173
cd web && npm run build             # tsc + build → web/dist/
cd web && npm test                  # vitest

Architecture constraints enforced by unit tests — do not violate:

  • No TIMEOUT_DEFAULT on DecisionSource — human decisions must be explicit
  • Judge / PlannerJudge receive ReadOnlyStateView — no state writes from reviewer agents
  • Executor uses apply_with_snapshot() — no direct file writes
  • plan_revision_rounds >= maxAWAITING_HUMAN, not FAILED
  • HumanInterface never fills in default decisions

Contributing

Contributions are welcome — whether it's a bug report, a feature idea, or a pull request.

Good places to start:

  • 🐛 Report a bug — include your Python version, the command you ran, and the relevant log from .merge/runs/<id>/logs/
  • 💡 Request a feature — describe your fork/upstream scenario and what the system currently gets wrong
  • 🔧 Browse open issues — look for good first issue labels if you want a guided starting point

Before submitting a PR:

  1. Run pytest tests/unit/ — all tests must pass
  2. Run mypy src — no new type errors
  3. Run ruff check src/ — no lint errors
  4. Keep new files under 800 lines; organize by feature layer (models → tools → llm → agents → core → cli)
  5. New agents require a contract yaml under src/agents/contracts/ — see src/agents/contracts/_schema.md

Key docs for contributors:


Documentation

Full index: docs/README.md

Onboarding Guide Start here if you're new to the project
Architecture Layers, data flow, persistence, extension points
Flow & State Machine 13 states, 8 phases
Six Lost Patterns + P0/P1/P2 Hardening How we catch what git merge misses
Evaluation Framework Golden-merge ground truth, 5 trust dimensions, 3 dataset tiers, acceptance gates
Self-Learning System Non-parametric memory + grounded feedback loop, phased rollout
Migration-Aware Merge Handling bulk-copy scenarios
Risk Levels How files are classified A–E
Web UI User Journey Browser-side walkthrough

License

MIT


Built for teams that maintain long-lived forks and need more than git merge.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

code_merge_system-0.2.0.tar.gz (14.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

code_merge_system-0.2.0-py3-none-any.whl (1.1 MB view details)

Uploaded Python 3

File details

Details for the file code_merge_system-0.2.0.tar.gz.

File metadata

  • Download URL: code_merge_system-0.2.0.tar.gz
  • Upload date:
  • Size: 14.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for code_merge_system-0.2.0.tar.gz
Algorithm Hash digest
SHA256 cf3a7dc87b455e496d585a397dc5997d90923d06cb16c6d0210e02e3badd87e7
MD5 265b0b5e204dacb3ca2a8e5edf88387a
BLAKE2b-256 e0fb0b7b684b3b374404d1a956317ddabf71098b0b56470302f551aca0d118df

See more details on using hashes here.

Provenance

The following attestation bundles were made for code_merge_system-0.2.0.tar.gz:

Publisher: release.yml on GOSICK-Angel/code-merge-system

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file code_merge_system-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for code_merge_system-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 067eda355c5c8a6fa9343bcabbc3ae05b8855a888003fc417c9a17891e8b5ad0
MD5 f33119508e5e7abfa0c95ea61b2b94af
BLAKE2b-256 c1564bd598b63ec24a20805e28195dd796aa97707349b183a0ab0087b155e688

See more details on using hashes here.

Provenance

The following attestation bundles were made for code_merge_system-0.2.0-py3-none-any.whl:

Publisher: release.yml on GOSICK-Angel/code-merge-system

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page