Skip to main content

snap

Perform a branch snap (release branch cut) for dotnet repos like dotnet/roslyn. Use when: snapping a branch, cutting a release branch, creating a release branch, merging main into release, updating VS insertion config, updating darc subscriptions for a snap, moving milestones, or asked about snap workflow.

Source facts

Repository
dotnet/roslyn
Last source activity
September 27, 2026 at 08:53
Detected SKILL.md language
English
Stars
20,686
Forks
4,328

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
snap
description
Perform a branch snap (release branch cut) for dotnet repos like dotnet/roslyn. Use when: snapping a branch, cutting a release branch, creating a release branch, merging main into release, updating VS insertion config, updating darc subscriptions for a snap, moving milestones, or asked about snap workflow.
argument-hint
Which repo and branches to snap (e.g., snap main to release/dev18.6)?
# Branch Snap Perform a branch snap (release branch cut) for dotnet repositories. A snap shifts the content of named branches forward by one VS minor version in a cascade. > **IMPORTANT**: This skill makes destructive changes (creates branches, opens PRs, updates subscriptions, moves milestones). Always gather info first, present the full plan, and get explicit user confirmation before executing any modifications. > **NOTE**: This skill works for multiple dotnet repos (e.g., `dotnet/roslyn`). Do not assume `dotnet/roslyn` — always confirm the repo. > **SKILL MAINTENANCE**: If you deviate from this skill during execution (e.g., a step doesn't work as described, a new step is needed, or the process has changed), remind the user to update this skill file so future snaps benefit from the fix. > **SESSION**: A snap spans multiple days (initial snap, then a follow-up after the scheduled VS snap). Recommend the user reuse the same chat session throughout one snap cycle so context (PR numbers, branch names, channel IDs, schedule dates, etc.) is preserved. If starting a new session, review session memory for prior snap state. ## Branch Model Roslyn (and similar repos) use three named branches that cascade during a snap: | Branch | Role | Example before snap | Example after snap | |--------|------|--------------------|--------------------| | `main` | Active development, inserts to VS main | 18.6 | **18.7** (bumped) | | `release/insiders` | Preview/insiders ring, inserts to `rel/insiders` | 18.5 | **18.6** (gets main's content) | | `release/stable` | Stable ring, inserts to `rel/stable` | 18.4 | **18.5** (gets insiders' content) | A "snap for 18.6" means: main is currently at 18.6 and that content moves to insiders. The cascade is: 1. **Merge `release/insiders` → `release/stable`**: stable gets the old insiders content (18.5) 2. **Merge `main` → `release/insiders`**: insiders gets main's content (18.6) up to a specific commit 3. **Bump `main`** version to 18.7 After the snap, the old stable VS version (18.4 in this example) is retired from the named-branch cascade. If that content must continue servicing an SDK band, preserve it first by creating a long-lived branch such as `release/10.0.4xx` directly from the pre-snap `release/stable` commit. The previous SDK servicing branch can then be retired if its flow is no longer needed. Older `release/dev{version}` branches (e.g., `release/dev18.3` and below) remain for servicing only. ## Prerequisites Before starting, verify these CLI tools are available: - `gh` — GitHub CLI, authenticated (`gh auth status`). The user may need to switch accounts via `gh auth switch` to one with push access to their fork. - `darc` — .NET Arcade/BAR CLI for subscription management (`darc authenticate` must have been run) Test with: ``` gh --version darc get-subscriptions --exact --source-repo https://github.com/dotnet/roslyn --target-repo https://github.com/dotnet/dotnet ``` ### Fork-based workflow Snap PRs are typically opened from a user's fork. Ask the user for their fork (e.g., `{username}/roslyn`). Branches are created in the fork via the GitHub API, and PRs are opened cross-fork with `--head {forkOwner}:{branchName}`. Verify the `gh` account has push access to the fork (`gh api repos/{forkOwner}/{repo} --jq '.permissions'`). ## Workflow The snap process has three phases: **Gather**, **Plan**, **Execute**. ### Phase 1: Gather Information Collect all relevant state before proposing any changes: #### 1.1 Determine repo - Ask which repo (default: the current repo via `gh repo set-default --view`). Note that if working in the Roslyn repo (dotnet/roslyn), then the snap will apply to Roslyn and Razor, as they are both in the repo, so multiple version updates will be necessary. #### 1.2 Discover branches and versions automatically Use darc default channels and version files to infer the branch structure. Do **not** ask the user for branches or versions — infer them and present for confirmation. **Step A — List source-repository default channels** to discover active branches and the build channels they publish to: ``` darc get-default-channels --source-repo https://github.com/{owner}/{repo} ``` Identify the three named branches (`main`, `release/insiders`, `release/stable`), current servicing branches, and their VS and SDK source channels. > **Do not use this list alone to populate the email's SDK columns.** A source channel selects builds for subscriptions; it does not identify every SDK destination consuming those builds. One source channel can feed multiple VMR branches and therefore multiple SDK versions. Determine actual SDK destinations from subscriptions in step 1.3. **Step B — Read versions and configs** from all three branches: - Fetch `eng/Versions.props` from each branch to get the current version. - For roslyn: read `<MajorVersion>` and `<MinorVersion>`. `<VsMajorVersion>` is derived as Roslyn `MajorVersion + 13`, and `<VsMinorVersion>` is derived from Roslyn `<MinorVersion>` (e.g., Roslyn 5.6 → VS 18.6). - Razor versions are also in `eng/Versions.props` (same file as Roslyn's version), using `Razor`-prefixed property names. Razor has **two independent versions**: - **Razor VSIX/Addin version**: `<RazorVsixVersionPrefix>` and `<RazorAddinMajorVersion>` are derived from the shared `VsMajorVersion`/`VsMinorVersion` properties. They track the Visual Studio version like the rest of the snap cascade. - **Razor SDK version**: read `<RazorMajorVersion>` and `<RazorMinorVersion>` (e.g., `10.4`). Tracks the **.NET SDK band** Razor ships into, **not** the VS version. The mapping is `.NET <Major>.0.<Band>xx SDK` <-> Razor `<Major>.<Band>` (e.g., `.NET 10.0.4xx SDK` <-> Razor `10.4`, `.NET 11.0.1xx SDK` <-> Razor `11.1`). - Note: `src/Razor/Directory.Build.props` maps these `Razor`-prefixed properties to the standard MSBuild properties (`MajorVersion`, `MinorVersion`, etc.) for Razor projects. During a snap, only edit `eng/Versions.props` — the Razor props file should not need changes. - Fetch `eng/config/PublishData.json` from each branch to get insertion config (`vsBranch`, `insertionCreateDraftPR`, `insertionTitlePrefix`). - The JSON key is `branchInfo` (roslyn). **Step B.1 -- Detect Razor SDK version drift** for each branch (roslyn only): - For each branch, find the SDK default-channels assigned to it from Step A (e.g., `.NET 10.0.4xx SDK`). - Among those, locate the channel whose major matches the branch's current Razor `RazorMajorVersion`. If multiple channels of the same major are temporarily assigned (e.g., both `.NET 10.0.4xx SDK` and `.NET 10.0.5xx SDK`), pick the **lowest** band -- Razor is versioned to the lowest SDK band it ships into, since higher bands roll forward and can consume the same package. - Apply the mapping `.NET <Major>.0.<Band>xx SDK` -> expected Razor `<Major>.<Band>`. - If no matching SDK channel exists for that branch (common on `main` immediately after a previous snap, before the next SDK band channel has been created), record the branch as "no matching SDK channel -- Razor SDK version bump deferred". - If the expected version differs from the branch's current `RazorMajorVersion.RazorMinorVersion`, flag it as a drift to fix (during snap, see Phase 2 step 5; during follow-up, see Phase 3 step 3.9). **Step C — Infer the snap cascade** from the discovered state: - The snap version is whatever `main` currently targets (e.g., 18.6). - After snap: main bumps +1 minor, insiders gets main's current version, stable gets insiders' current version. - Record the pre-snap `release/stable` commit as the candidate source for a new SDK servicing branch. - Do not infer SDK flow changes yet. Determine them from the subscription topology in step 1.3; SDK flows do not necessarily move one-to-one with the VS branch cascade. Present a summary like: ``` Snap for VS 18.6 on dotnet/roslyn: main: 18.6 -> 18.7 release/insiders: 18.5 -> 18.6 (receives current main content) release/stable: 18.4 -> 18.5 (receives current insiders content) Old stable 18.4: preserve in an SDK servicing branch or retire SDK destinations: pending subscription analysis in step 1.3 ``` If Step B.1 detected any Razor SDK version drift on the branches as they exist **today** (e.g., `main` already flows to `.NET 10.0.4xx SDK` but `eng/Versions.props` still says `RazorMajorVersion=10, RazorMinorVersion=0`), call it out explicitly -- it likely means a previous snap missed the bump and should be fixed in the same snap PR. Confirm with the user before proceeding. #### 1.3 Check darc subscriptions, SDK destinations, and Arcade dependencies List existing forward flows, backflows, incoming Arcade dependency subscriptions, and default channels: ``` darc get-subscriptions --exact --source-repo https://github.com/{owner}/{repo} --target-repo https://github.com/dotnet/dotnet darc get-subscriptions --exact --source-repo https://github.com/dotnet/dotnet --target-repo https://github.com/{owner}/{repo} darc get-subscriptions --exact --source-repo https://github.com/dotnet/arcade --target-repo https://github.com/{owner}/{repo} darc get-default-channels --source-repo https://github.com/{owner}/{repo} darc get-default-channels --source-repo https://github.com/dotnet/dotnet ``` Also check flows to SDK and runtime if relevant: ``` darc get-subscriptions --exact --source-repo https://github.com/{owner}/{repo} --target-repo https://github.com/dotnet/sdk darc get-subscriptions --exact --source-repo https://github.com/{owner}/{repo} --target-repo https://github.com/dotnet/runtime ``` Build the current SDK-flow matrix as follows: 1. For each enabled forward subscription from the source repository to `dotnet/dotnet`, record its source channel and VMR target branch. 2. Map the target branch to its SDK name using the VMR default channels (for example, VMR `main` -> `.NET 12.0.1xx SDK`, `release/11.0.1xx` -> `.NET 11.0.1xx SDK`). 3. Associate the subscription's source channel with the source branches that publish to that channel. 4. Preserve every distinct SDK destination. A branch may legitimately feed multiple SDKs; do not collapse the list to one channel or assume the newest SDK replaces the previous one. Then propose the after-snap flow matrix from the actual servicing requirements: - Preserve existing `main` SDK destinations unless the snap explicitly retires one. - Add the snapped content's required SDK destination to `release/insiders`. - If old stable content must continue feeding an SDK band, plan a new `release/<sdk-band>` branch from the pre-snap stable commit and transfer that SDK flow to it. - Identify the previous SDK servicing branch and flow as a retirement candidate. **Inventory Arcade dependency flow separately from VMR codeflow.** Creating a Git branch does not copy its subscriptions, and a publishing channel or VMR subscription does not supply Arcade tooling updates. For every affected branch, including any new or retiring SDK servicing branch: - Record its incoming Arcade subscription's ID, channel, enabled state, update frequency, batchability, excluded assets, and merge policies. Verify it is a dependency subscription (`Source-enabled: False`), not VMR source flow. - For a new servicing branch, use the preserved branch's compatible Arcade subscription as the template. Record the template ID and intended engineering channel in the plan. For example, a branch preserving content that consumes `.NET 10 Eng` should normally keep that channel, not use `.NET 10.0.4xx SDK` or automatically switch to `.NET Eng - Latest`. - If the template is missing, disabled, or no longer appropriate for the preserved content, stop and confirm the intended Arcade flow with the user rather than guessing. - Preserve Arcade subscriptions for branches that remain supported. Retiring an SDK destination alone does not authorize deleting that branch's incoming tooling updates. Present both SDK-flow matrices and the planned Arcade subscriptions for confirmation. Do not make subscription or default-channel changes yet. #### 1.4 Read Visual Studio schedules and draft the pre-snap announcement The normal cadence is: 1. Send the announcement on Friday. 2. Perform the Roslyn snap the following Monday, normally near end of day PT. 3. Visual Studio snaps `main` → `rel/insiders` that Friday at the time listed in the schedule. Infer these dates from the snapped version's VS schedule instead of asking the user to supply all of them: - Start with the scheduled VS `main` → `rel/insiders` snap. - Recommend the preceding Monday as the Roslyn snap date. - Recommend the Friday before that Monday as the announcement date. Present the inferred cadence and ask the user to confirm the Roslyn snap date/time. Treat this as a default, not a fixed rule: holidays, schedule exceptions, or explicit team plans may require different dates. Two VS versions are involved, and their schedules have different purposes: - **Snapped version** (the current `main` version): supplies the upcoming VS `main` → `rel/insiders` snap date and the `release/insiders` QB window. For a snap for 18.11, use the Dev18.11 schedule. - **After-snap main version** (current version + 1 minor): supplies the start of the new `main` feature-development cycle. For a snap for 18.11, use Dev18.12 only for this context; do **not** use its later QB dates in the 18.11 announcement. Use an MCP server to find the schedule: 1. Search the `DevDiv.wiki` repository in organization/project `devdiv/DevDiv` for `Dev{version} Schedule` with `project_search` method `wiki`. 2. Read the returned page path with `code_read` method `content`. 3. For the snapped version, extract: - `Snap main to rel/insiders` date, start time, and notes. - The first `QB Mode` row whose branch is `rel/insiders`, including start, end, and submission deadline. - Its final build, sign-off, and ship dates for context. 4. For the after-snap main version, extract the first feature-development start on `main`. Do not silently substitute one version's schedule for the other. If the schedule is missing, ambiguous, places the VS snap on an unexpected day, or conflicts with the proposed Roslyn snap date, stop and ask the user to confirm the cadence. The Roslyn snap must precede the VS `main` → `rel/insiders` snap; the user-confirmed Roslyn date/time defines the content cutoff. Using the info from steps 1.1–1.3 and the validated schedules, draft the email. The email should follow this format: > **Subject:** Snap for {VS version} on {day of week}, {date} > > Hi all, > > We will **snap for {VS version} on {day of week}, {date} ~ {time} PT.** main will point to {new VS version} after the snap. > > Following is important information about branches and dates. > > | Branch | Current VS | Current SDK | After-snap VS | After-snap SDK | Notes | > |---|---|---|---|---|---| Fill in each row using the VS versions and insertion settings discovered in step 1.2 and the SDK-flow matrices discovered in step 1.3. If a branch feeds multiple SDKs, list all of them in both the current and after-snap columns; do not imply that adding a new SDK destination retires an existing one. Show the intended after-snap state without exposing pending InfraSwat configuration work. > QB mode for `release/insiders` is from {QB start} to {QB end} ({deadline}). > > If there's anything that needs to be checked in for QB mode, please contact the InfraSwat team. **Adapt the table** to the actual branch structure: - Include all active named branches, the new SDK servicing branch (if any), and the servicing branch planned for retirement. - Use `—` for cells with no applicable VS or SDK destination. - Keep notes action-oriented and concise, for example: - `main`: "Insertions will be drafts until VS snaps" - `release/insiders`: "Will receive the current main content" - `release/stable`: "Will receive the current release/insiders content" - new servicing branch: "Will receive the current release/stable content" - retiring servicing branch: "Will be retired after the snap" - Fill current SDK columns from existing forward subscriptions and VMR target channels, not only source-repository default channels. - Fill after-snap SDK columns from the confirmed planned flow matrix. - Derive the QB sentence from the snapped version's first `rel/insiders` QB row. Preserve the schedule's full weekday/date wording and deadline. - Include the snapped version's schedule link when available. Present the draft to the user for review and editing before they send it. #### 1.5 Find recent PRs and milestones - List last merged PRs to source branch: ``` gh pr list --repo {owner}/{repo} --search "is:merged base:{sourceBranch} sort:updated-desc" --json number,title,mergedAt,mergeCommit --limit 5 ``` - List PRs in the `Next` milestone: ``` gh pr list --repo {owner}/{repo} --search "is:merged milestone:Next base:{sourceBranch} sort:updated-desc" --json number,title,mergedAt,mergeCommit ``` - List closed issues in the `Next` milestone: ``` gh issue list --repo {owner}/{repo} --search "is:closed milestone:Next" --json number,title ``` - List all milestones: ``` gh api repos/{owner}/{repo}/milestones --paginate --jq ".[] | {number:.number,title:.title}" ``` #### 1.6 Determine snap point - Use the user-confirmed Roslyn snap date/time from step 1.4 as the cutoff. Do not use the later VS snap time as the cutoff. - If the cutoff is in the future, record that snap-point selection is deferred and repeat this step immediately before execution. - List enough recently merged PRs to cover the cutoff, parse `mergedAt`, and select the latest PR merged to `main` at or before the cutoff. For example: ```powershell $cutoff = [DateTimeOffset]::Parse("{confirmed cutoff with UTC offset}") $prs = gh pr list --repo {owner}/{repo} --search "is:merged base:main sort:updated-desc" --json number,title,mergedAt,mergeCommit --limit 100 | ConvertFrom-Json $candidate = $prs |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub