--- name: ce-upstream-merge description: "Incorporate upstream git changes into a local fork without losing local intent. Analyzes divergence, surfaces file-level and hidden conflicts, walks you through a per-finding decision (Accept remote / Keep local / Merge both / Keep deleted), then executes resolutions in a structured multi-step pass with checkpoints. Triggers on 'merge upstream', 'incorporate upstream changes', 'sync fork', or when local and remote branches have diverged significantly." --- # Upstream Merge Incorporate upstream changes into a local fork without losing local intent. The flow mirrors `ce-code-review`'s shape: analyze, walk through per-finding with the user, then execute with checkpoints. ## Prerequisites Before starting: 1. **Identify the guiding principle** — ask the user which local intent must survive. Every decision reads against this principle. 2. **Confirm remote** — `git remote -v` should show the intended upstream. 3. **Fetch latest** — `git fetch origin`. ## Phase 1: Analyze divergence Gather the full picture: ```bash git merge-base HEAD origin/main git rev-list --count HEAD ^origin/main git rev-list --count origin/main ^HEAD git diff --name-only $(git merge-base HEAD origin/main) HEAD > /tmp/local-changes.txt git diff --name-only $(git merge-base HEAD origin/main) origin/main > /tmp/remote-changes.txt comm -23 <(sort /tmp/remote-changes.txt) <(sort /tmp/local-changes.txt) > /tmp/remote-only.txt comm -13 <(sort /tmp/remote-changes.txt) <(sort /tmp/local-changes.txt) > /tmp/local-only.txt comm -12 <(sort /tmp/remote-changes.txt) <(sort /tmp/local-changes.txt) > /tmp/both-changed.txt ``` File-level buckets: | Bucket | Meaning | Default action | |--------|---------|----------------| | **Remote-only** | Changed upstream, local untouched | Accept automatically | | **Local-only** | Changed locally, upstream untouched | Keep as-is | | **Both-changed** | Modified on both sides | Decision required | **Also surface hidden conflicts.** File-level bucketing misses three common patterns that still matter: - **Upstream rename of a file local deleted** (remote-only deletion + remote-only creation under a new path, but local intent was to drop it). Check by diffing the set of deleted paths against any new creations at parallel paths. - **Upstream deletion of a file local depends on** (remote-only deletion, but local skills/commands reference the deleted thing). Grep the local tree for names of upstream-deleted skills, agents, and commands. - **Structural refactors** (massive renames, namespace changes, convention shifts) where every file "looks fine" individually but the project no longer fits together. Scan the remote-only diff for patterns that affect many files consistently. Present the summary to the user with real counts, real examples, and flagged hidden conflicts. ## Phase 2: Build the decision set Create one platform task (`TaskCreate` in Claude Code; `update_plan` in Codex) per decision that actually needs user input: - Each both-changed file that survives on both sides (content conflict). - Each local-kept / remote-deleted file (keep local with rename, or follow upstream's removal). - Each hidden conflict surfaced in Phase 1. Do **not** create tasks for: - Trivially-resolved both-changed cases (e.g., both-deleted — keep deleted). - Pure remote-only files where local has no dependency on them (auto-accept). - Pure local-only files untouched upstream (auto-keep). **Task subject format:** `: ` (e.g., `ce-brainstorm/SKILL.md: content merge`). **Task description:** include file paths, both intents, a recommendation, and acceptance criteria. Keep it under ~40 lines so the walk-through stays readable. Use parallel agents to draft descriptions when there are many decisions (batch 4-6 at a time). No file writes to `todos/` or anywhere else — the platform's task tracker is the source of truth. Announce when the decision set is built: `Decision set: N items. Ready to walk through.` ## Phase 3: Walk-through (one decision per finding) Present each task one at a time using the platform's blocking question tool. In Claude Code, `AskUserQuestion` (call `ToolSearch` with `select:AskUserQuestion` first if not loaded); in Codex, `request_user_input`; in Gemini, `ask_user`; in Pi, `ask_user` via the `pi-ask-user` extension. Fall back to numbered options in chat only when no blocking tool is available. For each finding, show: - The file (or group of files if related). - The conflict shape (content / rename / modify-delete / hidden). - Both intents in one sentence each. - The recommendation and the reasoning tied to the guiding principle. - The diff summary when it's short enough to be useful. Then ask: **Stem:** `How should the merge resolve this?` **Options (match the decision vocabulary):** 1. `Accept remote` — take upstream's version as-is. 2. `Keep local` — preserve local as-is; discard upstream's change. 3. `Merge both` — combine; specify the merge shape (e.g., upstream structure + local content hunks). 4. `Keep deleted` — file stays gone regardless of upstream's continued version. **Group related findings** — e.g., all files in a renamed skill dir, or all files in a cohesive upstream refactor. Group decisions reduce fatigue and catch inconsistency. **Track progress:** show `X/N decided` before each question. Update the corresponding task's status to `completed` as decisions land. ## Phase 4: Execute in checkpoints Never apply all decisions silently in one commit. Break into checkpoints so the user can inspect and course-correct mid-flight. ### Setup ```bash git branch backup-local- main # safety net git checkout -b merge-upstream- origin/main ``` All subsequent work lands on the new branch. The backup branch is the escape hatch. ### Checkpoint sequence 1. **(b) Carry in local-only files** — `git checkout backup-local- -- ` for each local-only addition. Exclude files that need special handling (e.g., a locally-modified agent that upstream renamed — port that in step c.5). Commit. 2. **(c) Rename / restructure to upstream convention** — move local custom agents to flat `ce-.agent.md`, rename local custom skill dirs to `ce-/`, delete upstream's renamed versions of locally-deleted items, update frontmatter `name:` fields. Commit. 3. **(d) Content merges** — apply each `Merge both` decision. Commit per-file or per-skill for clean review. 4. **(e) Ports across rename boundaries** — e.g., when upstream renamed a skill and local had modifications under the old path, port the modifications into the new path. Commit. 5. **(f) Deletions + retools** — apply `Keep deleted` and `Accept remote` deletion decisions. If a local skill's purpose survives but its mechanism was deprecated, retool it into the new pattern (don't just delete). Commit. 6. **(g) Reference sweep** — grep for old namespace references, old agent names, old slash commands; replace with new equivalents. Commit. 7. **(h) Metadata refresh** — recompute agent/skill counts in `README.md`, plugin.json descriptions, marketplace catalogs. Never hand-bump release-owned versions. Commit. At each checkpoint, ask the user before proceeding: `Checkpoint N/7 complete. Proceed to , hold for inspection, or revise?` ### Validate before merging ```bash bun run release:validate bun test grep -r "compound-engineering:" plugins/ | grep -v "docs/\|specs/\|\.md:" | head ``` Expected: tests pass (or match baseline pre-merge state), release validator passes, no stray old-namespace agent refs remain in skill/agent/command content. ### Merge to main Ask before merging: `All checkpoints applied and verified. Merge to main now?`. On yes: ```bash git checkout main git merge merge-upstream- ``` ## Decision heuristics | Signal | Default recommendation | |--------|------------------------| | Remote adds new content, no local equivalent | Accept remote | | Remote updates content local deleted intentionally | Keep deleted | | Remote structural improvements + local content changes | Merge both: remote structure + local content | | Both changed same content differently | Merge both: pick the side that serves the guiding principle; port the minimum set of hunks from the other | | Remote renames what local deleted | Keep deleted (drop the renamed upstream version too) | | File is metadata (counts, versions, descriptions) | Defer to the metadata-refresh checkpoint — recalculate from actual files | | Upstream removed a skill local depends on (hidden conflict) | Fix local references AND accept the removal, OR retool local to not need the removed thing | ## Important rules - **No file-based state.** The decision set lives in the platform's task tracker, not in a `todos/` directory. Prior versions of this skill wrote `todos/NNN-*.md`; that pattern is retired. - **Never auto-resolve content conflicts.** Every `Merge both` / `Keep local` / `Accept remote` call is the user's, not the agent's. - **Checkpoint, don't mega-commit.** Seven small commits read better than one 400-file mega-commit. - **Stage explicitly.** Prefer `git add ` over `git add -A` so private files and stale scratch never sneak in. - **Group related findings during walk-through.** A 7-file rename is one decision, not seven. - **Metadata is derived, not merged.** Component counts, descriptions, and version strings are computed after all other work lands. - **Preserve the guiding principle.** Every recommendation should reference it; every decision should be defensible against it.