Docs

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’s package.json version 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 a y bump as breaking and a z bump 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

  1. In each owned repo that changed: bump its package.json version (independent SemVer), commit, git tag vX.Y.Z, push.
  2. Bump tranquil-client’s version — the umbrella release number.
  3. Run node script/release-manifest.js <date> and commit the refreshed release-manifest.json.
  4. Tag the client vX.Y.Z and 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.