microsoft/quicksand-release
Release packages to GitHub via uvr. Use when user says "release", "publish packages", "cut a release", or wants to publish new package versions.
npx skills add https://github.com/microsoft/quicksand --skill release
Prerequisites: uvr (uv tool install uv-release-monorepo) and gh.
For first-time setup, scaffold the workflow with uvr workflow init (see references/cmd-init.md). To install the Claude skills into your project, see references/cmd-skill-init.md.
If the project has existing CI checks (tests, linting, etc.) that aren't yet wired into the release workflow, see references/custom-jobs.md before your first release.
Before dispatching, ensure all runners are up:
uv run quicksand-runners start
This starts the local macOS runner and the cloud runners (x64, arm64, win). The command is idempotent — safe to run if runners are already up.
Troubleshooting:
pkill -f Runner.Listener then retry._diag/ files from a previous run. Clean with rm -rf gha-runners/local/_diag.run.sh invocation creates a persistent process. Check with ps aux | grep Runner.Listener before starting a new one.You must not be on main. If you are, create a release branch and switch to it.
The working tree must be clean. Run git status. If dirty, ask the user whether to stash, commit, or abort.
uvr release
This prints the plan and prompts Dispatch release? [y/N]. Decline (N) to preview without dispatching. See references/cmd-release.md for all flags.
Present the output to the user. For each changed package, show:
Ask the user whether any packages need a minor bump instead of patch. Patch is the default — bump minor for new features, new public API, or breaking changes:
uv version --bump minor --directory packages/<package-name>
For each changed package, verify its public API against its docs:
Update CHANGELOG.md on the release branch before committing. Format:
For each package, review the commits since the baseline. Use the DIFF FROM column from the uvr release --dry-run output — this is the actual tag the planner diffs against, which may differ from the PREVIOUS version (e.g. a -base tag for dev cycles vs a release tag):
git log --oneline <DIFF_FROM_TAG>..HEAD -- packages/<pkg>
Example entry:
## [v0.3.4] - 2026-03-18
### Fixed
- CIFS directory listing filename truncation
Section headers: Added, Changed, Deprecated, Removed, Fixed, Security.
For each changed package, also write release notes to .uvr/release-notes/<pkg>/<version>.md. This directory is gitignored — notes are ephemeral and consumed at release time.
Review the commits since the last release:
git log --oneline <pkg>/v<last-version>..HEAD -- packages/<pkg>
Draft user-facing release notes — don't dump commit messages, write prose that helps users understand what's new, changed, or fixed. Present the draft to the user for approval before writing the file.
mkdir -p .uvr/release-notes/my-lib
cat > .uvr/release-notes/my-lib/1.2.0.md << 'EOF'
Dashboard support and stability improvements.
### Added
- New `Widget` class for building dashboards
### Fixed
- Parser no longer crashes on empty input
EOF
If no --release-notes flag is provided, the release gets a minimal header only.
git add -A
git commit -m "Release v<VERSION>"
git push -u origin "$(git branch --show-current)"
uvr release
Or with custom release notes:
uvr release \
--release-notes my-lib @.uvr/release-notes/my-lib/1.2.0.md
When prompted Dispatch release? [y/N], answer y.
If uvr release says dependency pins were updated, commit those first and re-run:
git add -A
git commit -m "chore: update dep pins"
git push
uvr release
gh run list --workflow=release.yml --limit=1
gh run watch <RUN_ID> --exit-status
If the workflow fails, check which job failed:
gh run view <RUN_ID> --log-failed
If the failure is early (build broke), fix the issue and re-dispatch from scratch:
git add <files>
git commit -m "Fix: <description>"
git push
uvr release
If a later job failed but earlier jobs succeeded, use --skip-to and --reuse-* flags to resume without re-running what already passed. See references/troubleshooting.md#resuming-a-partially-failed-release for the full decision tree.
gh release list --limit 15 # confirm per-package releases exist
If something goes wrong, see references/troubleshooting.md.
ALWAYS merge stable release branches back to main:
git checkout main
git pull --rebase
git fetch origin <release-branch>
git merge --no-ff origin/<release-branch> -m "Merge <release-branch>"
git push
Why git fetch and origin/<release-branch>: the post-release bump job runs in CI and pushes a chore: bump to next dev versions commit (and creates the -base baseline tag) on the remote release branch *after* uvr release returns. Your local copy of the branch does not have that commit. Merging your local tip leaves main stuck at the released version instead of the next dev version, and uvr status will then resolve DIFF FROM to the previous release tag instead of the new baseline. Fetch and merge the remote tip.
NEVER merge pre-release branches back to main. Stay on the branch through the pre-release cycle, then merge after the stable release.
TAKE CARE merging post-release branches back to main — they branch from an old tag, so pyproject.toml versions will conflict. You may need to accept main's versions or cherry-pick just the fix commits. See references/post-releases.md.
If packages were released successfully, clean up release notes:
rm -rf .uvr/release-notes/
User says: "Let's release the new changes"
uvr release, decline the prompt — shows my-lib is dirty (2 commits: added export, fixed parser)uvr bump --package my-lib --minorParser class exported but not documented. Fix docs.Parser class for structured input handling. Fixed crash on empty input." Present to user for approval..uvr/release-notes/my-lib/0.3.0.mduvr release --release-notes my-lib @.uvr/release-notes/my-lib/0.3.0.md and confirm10. Merge release branch back to main, clean up .uvr/release-notes/
Commands:
<<<<<<< current
=======
references/cmd-version.md — read, set, or bump package versions>>>>>>> incoming
references/cmd-init.md — scaffold the release workflowreferences/cmd-validate.md — check release.yml against schemareferences/cmd-release.md — plan and dispatch a release (all flags)references/cmd-runners.md — manage per-package build runnersreferences/cmd-install.md — install from GitHub releasesreferences/cmd-skill-init.md — copy Claude skills into projectGuides:
references/pipeline.md — the three core jobs (build, publish, bump)references/release-plan.md — what the release plan JSON containsreferences/custom-jobs.md — how to add your own jobs to the workflowreferences/dev-releases.md — publishing .devN versions for testingreferences/post-releases.md — correcting an already-released versionreferences/troubleshooting.md — common problems and fixesTake microsoft/quicksand-release from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.