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.

tranquil-client carries ~810 inherited vX.Y.Z tags from Atom’s history, so git tag -a vX.Y.Z fails with “tag already exists” for most version numbers — v0.2.0 pointed at a 2013 Atom commit, and v0.2.1, v0.3.0 and v1.0.0 are all taken too. v0.1.0 and v0.1.1 only worked because Atom never used those exact numbers.

None of the inherited tags are on our remote, so replacing the local one is unambiguous:

git tag -d vX.Y.Z          # drop the inherited Atom tag, local only
git tag -a vX.Y.Z -m "…"
git push origin refs/tags/vX.Y.Z

Two things follow. git push --follow-tags silently skips the tag when this happens — it pushes the branch and reports success, so verify with git ls-remote --tags origin that vX.Y.Z^{} resolves to the commit you meant. And a later git fetch --tags from upstream restores the inherited tag, so expect to do this again. The owned package repos have no such history and tag normally.


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.