upstream-sync
microsoft/intelligent-terminal/.github/skills/upstream-sync/SKILL.md
Periodically sync new commits from microsoft/terminal into this manually-forked intelligent-terminal repo by cherry-picking commit-by-commit onto a dated sync branch, auto-skipping revert pairs and empty commits, auto-resolving known take-upstream files, and stopping cleanly on genuine conflicts. The agent (you, reading this file) is the orchestrator — the PowerShell scripts are atomic operations you invoke one at a time. Use when the user asks to "sync upstream", "pull from microsoft/terminal", "run upstream sync", "catch up to upstream", or wires this into a scheduler (weekly/daily). Designed to be safe under repeated unattended runs.
- Commits and pushes
---
name: upstream-sync
description: 'Periodically sync new commits from microsoft/terminal into this manually-forked intelligent-terminal repo by cherry-picking commit-by-commit onto a dated sync branch, auto-skipping revert pairs and empty commits, auto-resolving known take-upstream files, and stopping cleanly on genuine conflicts. The agent (you, reading this file) is the orchestrator — the PowerShell scripts are atomic operations you invoke one at a time. Use when the user asks to "sync upstream", "pull from microsoft/terminal", "run upstream sync", "catch up to upstream", or wires this into a scheduler (weekly/daily). Designed to be safe under repeated unattended runs.'
license: MIT
---
# Upstream Sync (microsoft/terminal → intelligent-terminal)
Cherry-pick commit-by-commit from `https://github.com/microsoft/terminal`
into this fork, preserving per-commit attribution, auto-skipping picks
that cancel each other out, and stopping cleanly the moment a
human-judgment conflict appears.
**You — the agent reading this file — are the orchestrator.** Each step
in the run is a single atomic call into one of the `scripts/*.ps1` files.
There is intentionally no PowerShell driver, because every interesting
decision (build-fix vs. open stuck issue, retry vs. bail, finalize vs.
dry-run) wants LLM judgment the operator can audit in your transcript.
## When to Use This Skill
- User asks to "sync upstream", "pull from microsoft/terminal", "catch up to upstream", or "run upstream sync".
- A scheduler invokes the agent on a weekly/daily cadence.
- The previous run left an `upstream-sync-stuck` labeled issue open and the human has finished resolving the conflict — **close the issue** (that IS the lock-clear signal) and re-run.
## When NOT to Use This Skill
- User wants a **one-shot rebase** of a single feature branch onto upstream — that's a normal `git rebase`, not this skill.
- An `upstream-sync-stuck` labeled issue is open on `microsoft/intelligent-terminal` — do not re-run; resolve the conflict on the stuck branch first, then close the issue.
## Prerequisites
- `git` 2.38+ (for `cherry-pick --keep-redundant-commits`), `gh` CLI authenticated against `microsoft/intelligent-terminal` (needs push to `upstream-sync/*` topic branches + issue/label create), PowerShell 7+ (`pwsh`) on PATH.
- **`origin` MUST point at `microsoft/intelligent-terminal`.** All scripts push to `origin` and pass `-R microsoft/intelligent-terminal` explicitly. Verify with `git remote -v` before running.
- **Full git history on `origin/main`** (no shallow clone). Watermark discovery walks up to 5000 commits scanning for `cherry picked from commit <sha>` trailers. In CI, use `actions/checkout@v4` with `fetch-depth: 0`.
- Windows build host with Visual Studio 2022, Windows SDK, `vswhere`, and `tools\razzle.cmd` / `bz`. Build is a hard gate before finalize.
- **No `state.json` to bootstrap.** Watermark = newest `(cherry picked from commit <sha>)` trailer on `origin/main`. If the fork has never used `cherry-pick -x`, run the one-time [First-time sync](./references/recovery-procedures.md#first-time-sync-seeding-the-watermark).
## State Model (no state file)
Every persistent fact lives in the source that owns it:
| Question | Source of truth |
|---|---|
| Last-synced upstream commit? | Newest `(cherry picked from commit <sha>)` trailer on `origin/main` whose target is reachable from `upstream/main`. Derived by [`02-compute-pending.ps1`](./scripts/02-compute-pending.ps1). |
| What's pending? | `git log --cherry-pick --right-only --no-merges origin/main...upstream/main`, drop SHAs at/before the watermark. Patch-id based, so a picked-then-reverted commit correctly re-appears. |
| Is the scheduler locked? | Any open issue with the `upstream-sync-stuck` label on `microsoft/intelligent-terminal`. Closing it IS the lock-clear signal. |
| Where do build logs go? | `Generated Files/upstream-sync/<YYYY-MM-DD>/` — gitignored by the repo root's `**/Generated Files/`. Never committed. |
### Why cherry-pick (not rebase or merge)
- **Rebase upstream/main** — ❌ fork history contains old "Merge upstream" commits; rebase replays them and explodes conflicts (verified failure on sister repo).
- **Merge upstream/main** — ⚠️ works, but collapses the whole sync into one blob commit, killing per-commit review and `git bisect`.
- **Cherry-pick commit-by-commit** — ✅ preserves authorship + per-commit content, allows mechanical revert-pair skipping, produces a reviewable PR.
## Run a sync
Eight-step orchestration. Full commands, JSON contracts, and
failure-handling for every step are in
[`references/run-a-sync.md`](./references/run-a-sync.md). The flow:
```
1. Preconditions (clean tree, on main FF, no open stuck issue)
2. Create branch upstream-sync/<UTC-yyyy-MM-dd-HHmmss-rand4>
3. Fetch upstream (verify owner/repo identity of the `upstream` remote)
4. Compute pending ← scripts/02-compute-pending.ps1 (→ JSON)
5. Cherry-pick loop ← scripts/03-cherry-pick-one.ps1 per SHA (→ JSON)
picked / skipped-empty → continue
stuck → 5a (push branch, file upstream-sync-stuck issue, EXIT)
6. (No commits picked? exit clean.)
before build: re-pin build/pgo/Terminal.PGO.props if upstream bumped
its Windows Terminal Major.Minor (else PGO build fails)
7. Build ← scripts/04-try-build.ps1 (→ JSON)
build-ok → step 8
build-failed → ONE focused fix commit, re-build; else 7a
build-inconclusive → 7a
7a. Surface failure to operator, EXIT (no issue filed for build failures)
8. Finalize: push, `gh pr create`, optional `gh pr merge --rebase --auto`
```
**Key invariants** (the agent MUST hold these — full rationale in the runbook):
- **Atomic per-commit.** Each pick is one commit on the sync branch carrying the upstream author/date and the `(cherry picked from commit <sha>)` trailer. Never amend across picks.
- **Stuck → exit clean.** On a Tier-3 conflict (script returns `status: "stuck"`), do NOT continue past it — push the branch, file the labeled issue, exit. The human resolves on the stuck branch, merges (no squash), closes the issue.
- **One build-fix commit, max.** Build-blocking fixes land as exactly one extra commit on the sync branch. Anything bigger → exit; the operator pushes a manual fix or runs a follow-up PR.
- **Never squash-merge the sync PR.** Squashing destroys per-commit attribution AND the trailer the next sync uses as its watermark. The PR body banner warns reviewers; the recipe arms `--rebase --auto`.
## Recovery procedures (rare)
Direct-to-main escape hatch, first-time watermark seeding, squash-merge
recovery: [`references/recovery-procedures.md`](./references/recovery-procedures.md).
Each requires explicit operator action.
## After-PR review handling — fix-in-PR vs. follow-up PR
Once the sync PR is open, reviewers (Copilot + humans) will comment.
**Only build-blocking fixes** belong on the sync branch as one focused
extra commit. Everything else — code-quality, logic-bug suggestions,
translation corrections, spelling-allowlist migrations, doc nits, design
feedback — goes into a **follow-up PR** that targets the sync branch
(not `main`). The cherry-pick PR must stay reviewable as "per-commit,
faithful to upstream + minimum must-merge delta".
Full rubric, worktree mechanics, PR-body template:
[`references/follow-up-pr.md`](./references/follow-up-pr.md).
## Gotchas
- **Never squash-merge the sync PR.** Squashing destroys per-commit
attribution AND collapses the trailers the next run uses as its
watermark. The PR body opens with a banner; step 8 arms
`gh pr merge --rebase --auto`.
- **Never strip the `(cherry picked from commit <sha>)` trailer** when
hand-resolving a stuck pick. That trailer IS the watermark.
- **Never rebase `upstream/main` onto this fork.** Use cherry-pick —
rebase replays old "Merge upstream" commits and explodes.
- **Don't amend substantive review fixes into the sync PR.** Only
build-blocking fixes (max one extra commit). Everything else → follow-up PR.
- **`.github/workflows/spelling2.yml` always conflicts** and is always
"take upstream wholesale". The Tier-0 list in
[`references/03-known-conflicts.md`](./references/03-known-conflicts.md)
handles it — extend the list when you find the next file with this pattern.
- **`gh pr create` on Windows can fail with "Head sha can't be blank"**
on freshly-pushed branches. The step-8 recipe wraps it in a 3× retry.
Do not "fix" it to use `--head <owner>:<branch>` (that points `gh` at a fork).
- **Cherry-pick over `git revert`-style commits is intentional, not
skipped.** We only skip revert-pairs where **both** sides are inside
the pending range. A revert of an already-merged commit must land —
otherwise the fork diverges silently.
- **Single-host scheduler.** The stuck-lock is a read-then-check gate,
not an atomic lease. Run from ONE host. For multi-host fan-out, layer
atomic locking on top (GitHub Actions `concurrency: upstream-sync` is
easiest).
- **CRLF/LF on manifest files.** Cherry-picks preserve upstream endings,
but Tier-2 LLM-touched resolutions on `.yml`/`.xml`/`.csproj`/winget
manifests may downgrade to LF. Re-normalize before staging — see
[`references/03-conflict-triage.md`](./references/03-conflict-triage.md#line-endings).
- **PGO pin follows upstream.** `build/pgo/Terminal.PGO.props` hard-pins the
PGO database to upstream's Windows Terminal `Major.Minor` (our `custom.props`
stays `0.1`, so it can't be derived). When a sync bumps the upstream version,
re-pin those two values or the build fails with `Could not find matching PGO
package`. Step 7's pre-build check covers this.
## Troubleshooting
| Issue | Solution |
|---|---|
| `02-compute-pending.ps1` throws "No 'cherry picked from commit' trailer …" | Fork has never used `cherry-pick -x` yet. Run the one-time [First-time sync](./references/recovery-procedures.md#first-time-sync-seeding-the-watermark). |
| Stuck issue prevents new run | Resolve on the stuck branch, open + merge a PR (keep the trailer, don't squash), then **close the stuck issue**. The next scheduler tick proceeds. |
| `03-cherry-pick-one.ps1` returns `"skipped-empty"` | Expected for upstream no-op commits and fork-already-applied patches. The loop skips and continues. |
| Same file conflicts every run | Add it to [`references/03-known-conflicts.md`](./references/03-known-conflicts.md) with the right strategy (`take-upstream` or `take-ours`; `union` is reserved and currently escalates instead of auto-resolving). |
| `gh pr create` returns "Head sha can't be blank" | Step 8 retries 3×. On slow networks, the operator may need a manual second run. |
## References
- [`references/run-a-sync.md`](./references/run-a-sync.md) — full eight-step procedure with commands.
- [`references/03-conflict-triage.md`](./references/03-conflict-triage.md) — Tier 0/1/2/3 conflict-resolution rubric.
- [`references/03-known-conflicts.md`](./references/03-known-conflicts.md) — files with fixed Tier-0 resolutions.
- [`references/follow-up-pr.md`](./references/follow-up-pr.md) — fix-in-PR vs. follow-up PR rubric and worktree workflow.
- [`references/recovery-procedures.md`](./references/recovery-procedures.md) — direct-to-main, first-time seed, squash-merge recovery.
- [`scripts/02-compute-pending.ps1`](./scripts/02-compute-pending.ps1) — derive watermark + pending list (no state file).
- [`scripts/03-cherry-pick-one.ps1`](./scripts/03-cherry-pick-one.ps1) — cherry-pick one SHA with author/date pinning + Tier-0/Tier-1.
- [`scripts/04-try-build.ps1`](./scripts/04-try-build.ps1) — run `bz no_clean`; log to `Generated Files/...`.
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
No one has posted yet. Be the first.

