Versioning
There are three separate version numbers.
1. The spec
Section titled “1. The spec”The spec covers formats, operations, dice modifiers and engine behavior. The current version is 0.1.0, which is pre-1.0: anything may still change.
From 1.0:
- Minor bump: additions that old packs keep working with, such as a new effect operation, dice modifier, change type or error code.
- Major bump: a change to what something means. This should almost never happen.
The spec is its own package (@opencharacter/spec), so ports get it without touching TypeScript, and so engine releases never look like spec changes. Schema $ids carry the spec’s major.minor (/schemas/0.1/).
2. Each engine
Section titled “2. Each engine”Each engine library (the TypeScript reference engine and community ports) has its own version and declares which spec versions it implements (for example, engine 2.4.1 implements spec 1.3). Each engine runs the spec’s test suite as part of its own tests. The TypeScript engine re-exports the spec’s schemas and types.
3. Each pack
Section titled “3. Each pack”- Every pack update gets a unique version. Published versions never change, because characters pin them.
- Each pack declares the minimum spec version it needs (
specVersioninpack.yaml).loadRulesetrefuses a pack that needs a newer spec than the engine implements (spec-version-unsupported). - Pack versions are semver and follow its convention for 0.x. A breaking bump is a minor bump while the version is 0.x (0.1.4 → 0.2.0) and a major bump from 1.0.0 on (1.4.2 → 2.0.0); any smaller bump is non-breaking. A dependency range such as
^0.1.0accepts only non-breaking bumps (>=0.1.0 <0.2.0). - Pack versions follow the upgrade rule in upgrades.md: a version that changes the saved state’s shape, or the pack’s interface, gets a breaking bump; a shape change also ships an upgrade script.
- There is one package per pack. The reason is versioning, not size: each version must mean only “this pack changed”. Translations for languages other than the default live in a separate
-i18npackage, so translation fixes never bump the mechanics pack.
The release flow
Section titled “The release flow”- Describe the change:
pnpm changeset, picking the packages and bump types. While a package is 0.x, a breaking change is aminorchangeset and anything else apatch; amajorchangeset takes it to 1.0.0. - Version:
pnpm version-packagesrunschangeset version, then copies each pack’s newpackage.jsonversion into itspack.yaml, since that is the version characters pin. - Check:
pnpm releaseruns every check, builds the packs, then runspnpm release:check. For each pack it compares the new release with the last published one, found by git tag (@opencharacter/<id>@<version>):- a version that is already published must build to the same release
(
published-version-changedotherwise); - otherwise
checkReleaseagainst the latest lower version must pass: shape changes need a breaking bump and a covering upgrade script (upgrades.md).
- a version that is already published must build to the same release
(
- Publish:
changeset publishpublishes changed packages and tags them. Built output (dist/: the packs’ releases and text, the bundle, the spec’s standard text) comes from step 3; each published package’sprepackrefuses to pack without it, so packing a package on its own needspnpm build:packsfirst.
Character files
Section titled “Character files”A character file records the specVersion it was written against, and the exact pack versions it uses.