Decision 0019
One version for the project, including its npm packages
accepted · 2026-11-08
Context
ADR 0013 gave the whole project one Semantic Version, with "nothing on npm". The backend kit
(ADR 0016) and the local stack (ADR 0017) change that. Apps install them from npm, in other
repositories, and they must match the Spotcraft the app is deployed to. The kit's auth
schema is migrated by Spotcraft and used by the kit.
Decision
One version for everything, in the root
package.json, following Semantic Versioning 2.0.0. Every workspace package carries it;pnpm check:versionsfails CI otherwise, andnode scripts/check-versions.ts <version>sets them all. The npm packages are published at that version too: kit X.Y.Z and CLI X.Y.Z belong to Spotcraft X.Y.Z, and the kit needs Spotcraft X.Y or later.Two npm packages:
@spotcraft/kit, in the npm orgspotcraft.spotcraft, the CLI, unscoped so thatnpx spotcraft dev startworks as written.
Every other workspace package stays private.
The public API, what a breaking change is measured against, is what an operator or an app relies on:
- the names of the published images and their tags;
- the variables of the Deploy workflow and the
productionenvironment; - the
.envvariables and Compose service names on each server, and the/opt/spotcraftlayout; - the OpenTofu module's variables and outputs;
- the agent's HTTP API, and the format of its
app.jsonfiles; - new: the npm package names; the kit's exports (
.,./schema,./provision); theauthschema's tables and columns;DATABASE_URLand the role and database names it carries; and the CLI's commands and flags.
The dashboard's screens are not part of it.
0.y.z: while the API settles, a breaking change raises the minor version (0.1 → 0.2), and a backwards-compatible change or fix raises the patch. 1.0.0 comes when the API is stable.
Changelog:
CHANGELOG.mdin Keep a Changelog 1.0.0 format, for operators and app developers. Changes collect underUnreleased, and a release renames that section to the version and date. Breaking changes include migration steps.Releasing: bump with the script, date the changelog, merge to
main, tagvX.Y.Z. CI refuses a tag that doesn't matchpackage.jsonand publishes, from the same tested commit:- images
X.Y.ZandX.Y(plusXfrom 1.0 on); - the two npm packages,
latest, ornextfor a pre-release.
Deploy that tag with the Deploy workflow.
- images
npm publishing runs in CI's
npmjob (environmentnpm) with trusted publishing: GitHub OIDC, no stored token, and provenance attached automatically.- Plain
npm publishruns in each package's folder, after the build and after the CLI'sworkspace:dependency is pinned to the exact version. pnpm isn't used for publishing. - A version that is already on npm is skipped, so a re-run doesn't fail.
- The first publish can't use OIDC, because a trusted publisher is linked to an existing
package. It uses a short-lived
NPM_TOKENin thenpmenvironment, with--provenance; the token is deleted once both packages are linked.
- Plain
Consequences
- One number answers "which Spotcraft is this server running?" and "which kit does it need?"
- A change to only the website still produces a new project version when released.
- An npm version can't be replaced: a broken release is fixed by a new patch version, and the broken one deprecated.
- The owner keeps the npm org
spotcraftand the trusted-publisher links on npmjs.com.