-
Notifications
You must be signed in to change notification settings - Fork 28
Release Process
Status: Active. All packages ship at the same version to the registry. CI handles publishing automatically — merge a version bump to
mainand packages are published. Canary builds are published on every PR.
Astryx releases all packages at the same version number for clear compatibility. The release process:
-
Accumulate changes — PRs land on
mainwith changesets - Identify codemods — Breaking changes get AST-based codemods
-
Version bump —
pnpm version-packagesapplies changesets, create a PR - Merge — CI builds and publishes to the registry automatically
- Post-release — Tag, update agent docs, internal sync, announce
All non-private packages are published together at the same version (a Changesets fixed group):
| Package | Contents |
|---|---|
@xds/core |
Components, hooks, utilities, tokens, CSS |
@xds/cli |
CLI commands: init, swizzle, upgrade, agent-docs, component, docs, template |
@xds/build |
Shared build tooling (tsup/StyleX config) |
@xds/theme-default |
Default theme (Heroicons) |
@xds/theme-neutral |
Neutral theme (Lucide icons) |
@xds/theme-butter · theme-chocolate · theme-daily · theme-gothic · theme-matcha · theme-stone · theme-y2k
|
Additional published themes |
@xds/lab, @xds/vega, @xds/theme-brutalist, and the apps/internal packages are private and never published. @xds/storybook and @xds/sandbox are in the changesets ignore list. (Source of truth: the fixed array in .changeset/config.json.)
Rule: All packages bump to the same version. This is enforced by the fixed group — a single changeset co-bumps every publishable package, so if you're on @xds/core@0.0.15, you use @xds/theme-default@0.0.15.
Every PR that changes published package behavior should include a changeset.
pnpm changeset:newThis Astryx wrapper (around the Changesets CLI):
- Auto-detects which publishable packages your working tree touched and pre-selects them — no hand-enumerating the frontmatter.
- Prompts for a category (
breaking,component,feat,fix,perf,docs,chore) — this drives changelog grouping, not the semver bump. - Captures the contributor(s) — defaults to your
gh/git identity, so credit is recorded at authoring time. -
Forces a
patchbump while we're pre-1.0 (see the rule below).
The changeset file is committed with the PR. The Astryx body convention is a [category] headline followed by a @handle line:
---
'@xds/core': patch
'@xds/cli': patch
---
[component] Added CommandPalette component and `xds upgrade` CLI command (#2717)
@yourhandleYou can pass everything as flags for non-interactive use:
pnpm changeset:new --category fix --summary "…" --pr 2717 --contributor yourhandleThe bare pnpm changeset CLI still works, but then you must follow the body convention by hand. CI (pnpm check:changesets, part of check:repo) rejects any changeset that is missing a category or contributor, declares a minor/major bump while pre-1.0, or names a private/ignored package.
⚠️ Pre-1.0 rule: Always usepatchfor changesets while we're on 0.0.x. The Changesets CLI treatsminoras a semver-minor bump, which jumps 0.0.x → 0.1.0. Signal a breaking change with the[breaking]category, not aminor/majorbump.pnpm changeset:newenforcespatchautomatically;pnpm check:changesetsis the CI backstop. (When we hit 1.0, the patch-only gate lifts automatically — it keys off whether publishable packages are still0.x.)
| Change type | Category | Bump (pre-1.0) | Changeset needed? |
|---|---|---|---|
| New component | component |
patch | Yes |
| New feature/prop | feat |
patch | Yes |
| Bug fix | fix |
patch | Yes |
| Prop rename | breaking |
patch | Yes — also needs a codemod |
| Component removal | breaking |
patch | Yes — also needs a codemod |
| Perf improvement | perf |
patch | Yes |
| Docs only | — | — | No |
| Tests only | — | — | No |
| Internal tooling (storybook, vibe-tests) | — | — | No (these are in ignore list) |
- The first body line is
[category] one-line user-facing summary (#PR). - The second line is the contributor handle(s):
@yourhandle(space-separated for multiple). - If there's a breaking change, use the
[breaking]category and mention the codemod:
---
'@xds/core': patch
---
[breaking] Renamed `items` prop to `options` on Selector for clarity (#2717)
@yourhandle
**Codemod:** `npx xds upgrade --codemod rename-selector-items-to-options`Before releasing, audit all changesets for breaking API changes that need codemods.
| Change | Codemod needed? | Example |
|---|---|---|
| Prop renamed | ✅ Yes |
items → options on Selector |
| Prop removed | ✅ Yes | Remove deprecated prop, add TODO comment |
| Component renamed | ✅ Yes |
HStack → Stack direction="horizontal"
|
| Component removed | ✅ Yes | Replace with new component + direction/variant prop |
| Callback signature changed | ✅ Yes |
onHide: () => void → onOpenChange: (isOpen: boolean) => void
|
| Two props merged into one | ✅ Yes |
onShow/onHide → onOpenChange
|
| New required prop added | If there's a sensible default, no codemod needed | |
| New optional prop | ❌ No | Additive, non-breaking |
| New component | ❌ No | Additive |
| Bug fix | ❌ No | Unless it changes expected behavior |
| Import path changed | ✅ Yes |
@xds/core/Layout → @xds/core/Stack
|
git log v0.0.13..HEAD --oneline -- packages/core/src/ | grep -iE 'rename|remove|refactor|unify|deprecat|breaking'Or check the accumulated changesets:
ls .changeset/*.mdCodemods live in packages/cli/src/codemods/transforms/v{VERSION}/. Each transform is a jscodeshift module. See existing transforms for patterns (prop rename, component rename, import rewrite).
- Create the transform file in
transforms/v{VERSION}/ - Create a test file in
transforms/v{VERSION}/__tests__/ - Add it to
transforms/v{VERSION}/index.mjsmanifest - If it's a new version directory, add it to
codemods/registry.mjs
pnpm test --run packages/cli/src/codemods/Once all PRs are merged and codemods are ready:
pnpm version-packagesThis runs changeset version (bumps versions, generates CHANGELOGs, deletes the consumed changesets) and then scripts/format-changelogs.mjs to format the output.
All publishable packages are a Changesets fixed group, so a single changeset co-bumps all of them to the same version automatically — no need to manually bump packages to match. Only genuinely-affected packages receive a changelog entry; the rest get a clean version-only bump.
pnpm version-packages already runs scripts/format-changelogs.mjs, which rewrites each just-bumped package CHANGELOG into the doc-site format:
| Element | Heading level | Example |
|---|---|---|
| Version |
# 0.0.16 (h1) |
# 0.0.16 |
| Section |
#### Breaking Changes (h4) |
#### Fixes |
| Divider |
--- between versions |
--- |
Category sections render in canonical order (Breaking Changes → New Components → New Features → Fixes → Performance → Documentation → Other Changes). The formatter is idempotent and has a --check mode (node scripts/format-changelogs.mjs --check) for CI drift detection. You normally don't touch CHANGELOGs by hand — just review the generated output.
This aligns with the doc site's Markdown rendering which uses headingLevelStart={1}, giving version numbers prominent h1 sizing.
The #### Contributors section is generated from the @handle lines captured in each changeset at authoring time — so it credits the real humans, not the release bot. No git log / gh pr list reconstruction needed.
If a contributor is missing (e.g. an old-format changeset slipped through), add their
@handleto the relevant changeset body and re-runpnpm version-packages, or edit the generated#### Contributorslist directly.
git checkout -b chore/version-packages-vX.X.X
git add .
git commit -m "chore: version packages for vX.X.X"
git push -u origin chore/version-packages-vX.X.X
gh pr create --title "chore: version packages for vX.X.X" --body "Version bump for release X.X.X"Merge the PR. CI takes it from here.
When the version bump PR merges to main, the Deploy workflow (deploy.yml) runs automatically:
- Tests pass
- All packages are built (
pnpm build) -
pnpm changeset publishpublishes any packages whose version is not yet on the registry - Already-published versions are skipped (npm 409 Conflict → no-op)
No manual npm publish needed. No npm auth tokens on your machine. No corp network requirement. CI handles everything via a registry auth token secret.
-
Tag the release in git:
git tag vX.X.X git push --tags
-
Update agent docs in consumer projects:
npx xds agent-docs
-
Notify consumers — post in the Astryx chat spaces with a summary of changes and the upgrade command.
After CI publishes to the registry, internal consumers need to be updated. This involves updating shared libraries in the internal monorepo and submitting a diff.
Once the internal sync lands:
- When an AI agent runs
xds component <Name>, the CLI readsLATEST_VERSIONvia thexds.versionFileconfig - If the installed version is older, the CLI prints an upgrade nudge
- The user decides when to upgrade — the agent won't upgrade automatically
Post a release announcement to the Astryx Open Source Workplace group and GChat space (spaces/AAQAmz6AQ8Y).
Write every line item from the builder's perspective — how they experience the change in their product or dev workflow.
Rules:
- Lead with the outcome — what's better for the builder now?
- One sentence max per highlight
- Skip internal-only changes
- Breaking changes: reassure, don't alarm — mention the codemod handles it
- Group related fixes
CI publishes a canary version on every PR commit automatically via the canary job in ci.yml. No manual steps needed.
<base-version>-canary.<short-sha>
e.g. 0.0.13-canary.fd7c751
npm install @xds/core@canarySafety guarantee: npm install @xds/core (no tag) always gets the stable @latest release. Canary versions live on a separate dist-tag.
| Scenario | Use canary? |
|---|---|
| Test codemods on internal apps before a stable release | ✅ Yes |
| Validate a breaking change on a feature branch | ✅ Yes |
| Quick fix for a codemod bug post-release | ✅ Yes |
| Routine release with no breaking changes | ❌ No — just publish stable |
- All breaking changes have codemods with tests
- CHANGELOGs follow the standard format
- All packages at the same version number
- Previous release is tagged
- Version bump PR created and reviewed
- Verify:
npm view @xds/core dist-tags - Tag:
git tag vX.X.X && git push --tags - Internal sync diff submitted
- Release announcement posted
main. Always checkout the exact tag, build from that commit, and publish that build.
git checkout vX.X.X
pnpm install && pnpm build
# Configure registry auth, then: pnpm changeset publish
git checkout main# Add a changeset to your PR (auto-detects packages, prompts category + contributor)
pnpm changeset:new
# Check pending changesets
ls .changeset/*.md
# Validate changesets (category, contributor, patch-only) — also runs in CI
pnpm check:changesets
# Version bump (changeset version + CHANGELOG formatting)
pnpm version-packages
# Create version bump PR, merge → CI publishes automatically
# Consumers upgrade
npx xds upgrade --apply- Distribution — Packages, versioning, source and dist bundles
- API Conventions — Naming and prop conventions that inform when codemods are needed