Release Versioning
Local development uses
link:symlinks with no version pinning at all — see Multi-Repo Setup. This page is about releases: how the client and its owned packages are versioned, tagged, and pinned so a build can be reproduced.
tranquil-client bundles its owned packages two ways at once: each is a link:../<repo> dependency and is listed in packageDependencies so it loads as a bundled package at runtime. The packages are not published to a registry, so a packaged build ships whatever is checked out in each sibling repo at build time. Without discipline, “what shipped” is unrecoverable — this process fixes that.
Principles
link:carries no version. It is a local-dev convenience. Versioning lives in each repo’spackage.jsonversion field and its git tags, never in the client’s dependency specifiers.- Each owned repo is versioned with independent SemVer. Bump a repo only for what changed in that repo — a theme tweak bumps the theme, not everything.
- Pre-1.0, the minor is the breaking slot. While a package is
0.y.z, treat aybump as breaking and azbump as a fix/feature. This matches the “provisional, may break between previews” posture of the developer preview. - The client is the umbrella. The client’s version is the release number for the whole constellation; the owned packages move independently underneath it.
- A release is pinned by a manifest. Because the packages aren’t published, the client records the exact version + commit SHA of every owned package that composed a release, so the build can be reproduced.
Versions & tags
Every repo — the client and each owned package — is tagged vX.Y.Z at release. Tags are the durable, checkout-able refs the link: setup otherwise lacks.
# in each repo, once its release changes are committed
git tag -a v0.1.0 -m "v0.1.0"
git push --follow-tags The first coordinated release (v0.1.0) normalized every bundled owned package to 0.1.0 as a clean common starting line. After that, they diverge independently.
The release manifest
tranquil-client/release-manifest.json is the reproducibility record. It pins each owned (link:) package to its version and commit SHA for a given client release:
{
"release": "v0.1.0",
"date": "2026-07-29",
"packages": {
"tranquil-browser": { "version": "0.1.0", "sha": "…" },
"tranquil-config": { "version": "0.1.0", "sha": "…" }
}
} It is generated — never hand-edited — by script/release-manifest.js, which derives the package set from the client’s link: dependencies, then reads each sibling’s version and git rev-parse HEAD:
node script/release-manifest.js 2026-07-29 # optional YYYY-MM-DD, defaults to today Order matters. Regenerate the manifest after committing the release changes in every owned repo and before tagging the client, so the recorded SHAs point at the tagged commits — not at pre-release HEADs.
Cutting a release
- In each owned repo that changed: bump its
package.jsonversion (independent SemVer), commit,git tag vX.Y.Z, push. - Bump
tranquil-client’s version — the umbrella release number. - Run
node script/release-manifest.js <date>and commit the refreshedrelease-manifest.json. - Tag the client
vX.Y.Zand create the GitHub Release (notes live on the releases page). Build artifacts are optional and can be attached later.
Tag on the active development branch, never on the branch that tracks upstream.
Reproducing a build
A release is reproducible from its manifest: for each entry, check out the owned repo at the recorded SHA (or its vX.Y.Z tag), then build the client:
# check out each owned repo at its manifest SHA, then, in tranquil-client:
yarn install && yarn dist Because the packaged build follows the link: symlinks, the manifest is the source of truth for what to check out before building.
Related
- Multi-Repo Setup — the sibling-repo layout and
link:wiring for local dev. - ADR-0001 — the fork decision that gives Tranquil its owned, unbundled package model.