Appearance
Versioning
Matrix packages version using semantic versioning. The package.json file is the source of truth for the publishable version; the matrix.json file must declare a non-empty version but only package.json drives publishes and installs.
Source of truth
mx publish and mx install read the version from package.json, not matrix.json:
ts
// projects/matrix-3/packages/mx-cli/src/commands/publish.ts:107
const version = readVersionFromPackageDir(cwd);readVersionFromPackageDir (in packages/mx-cli/src/utils/package-store.ts) reads package.json:version. The validator still requires matrix.json:version to exist as a non-empty string; keep them in sync to avoid confusing readers.
Semver comparator
The CLI compares versions with a numeric, dot-segment comparator (packages/mx-cli/src/utils/versioning.ts):
ts
compareSemver("0.1.10", "0.1.9"); // 1
compareSemver("1.0.0", "0.99.99"); // 1
maxSemver(["0.1.0", "0.1.10", "0.1.2"]); // "0.1.10"Pre-release suffixes (-rc.1, -beta) are accepted but compared only by the leading numeric segments. If you use pre-release tags, treat the comparator as approximate and rely on dist-tags or explicit version pins.
When to bump
CLAUDE.md Rule 9.9 (additive-only schema evolution) gives the practical rule:
| Change | Bump |
|---|---|
Adding a new optional field to an actor's accepts schema | patch |
Adding a new component to matrix.json:components[] | minor |
| Adding a new actor op | minor |
Adding a webapp block to a previously headless package | minor |
| Renaming or removing a field, op, or component | forbidden without a major version + replacement plan |
| Internal refactor only | patch |
The "additive only" rule is what makes minor bumps safe across runtimes that haven't restarted yet: a new field is invisible to old code, a removed field breaks it. Don't remove.
Bumping process
Practical steps for a routine release:
- Update
package.json:version. Match it inmatrix.json:version. pnpm build— produce the artifact.pnpm test— confirm tests pass.mx publish --dry-run— confirm preflight passes.mx publish— push to the registry.- Commit and push the version bump (CLAUDE.md Rule 8: commit when a coherent unit of work is complete).
Fork versioning
mx fork <packageName> (packages/mx-cli/src/commands/fork.ts) takes an installed package and forks it under a new name. It writes fork.upstream.{name,version} into the forked manifest, so subsequent upgrades can be tracked:
bash
mx fork @open-matrix/chat --name @my-org/my-chatmx outdated (packages/mx-cli/src/commands/outdated.ts) reports forks whose pinned upstream version is older than what the registry holds:
bash
mx outdated
@my-org/my-chat 0.2.5 -> 0.2.9 (outdated)mx update-fork @my-org/my-chat updates the fork metadata to the latest upstream version. It does not auto-merge code; use it after you've integrated upstream changes manually.
Version pinning at install time
bash
mx install @open-matrix/chat # latest
mx install @open-matrix/chat@0.2.9 # exact versionSource: parsePackageSpecifier in packages/mx-cli/src/commands/install.ts:66-91 parses the <name>@<version> syntax. Without a version, the npm registry returns its latest entry; the local registry returns the maximum semver currently published.
Why matrix.json:version exists at all
Historical reason: package introspection used to read manifests directly, before npm metadata was a hard dependency. It is now redundant with package.json:version but the validator still checks for it. Keep them aligned. Removing the matrix.json:version requirement is filed in WORKSTREAMS/loose-ends/ as a small cleanup.
See also
- Publishing → Package metadata
- Publishing → Release channels
- Installing → Install from registry
- Reference → Manifest schema
Source:
projects/matrix-3/packages/mx-cli/src/utils/versioning.tsis the comparator;packages/mx-cli/src/utils/package-store.ts:readVersionFromPackageDiris the version source.