Repository navigation
Stability
From v31: at most one major every 90 days, the previous major gets security fixes for 6 months after its successor, and a removal is deprecated for at least one minor first. Each rule is refused by a script, not remembered by a person — the table at the bottom names the code.
Next major window: opens on 2027-02-08, 90 days after 31.0.0 (2026-11-10). The bump that ships a major rewrites this line (scripts/release.ts).
A breaking change to any of these needs a major, and a major waits for its window.
| Surface | Where it is defined |
|---|---|
the eight primitive shapes: entity, policy, action, mutator, query, job, route, task
|
The eight primitives, PRIMITIVE_KINDS in packages/core/src/registrar.ts
|
the x CLI: every command, every flag, and the --json envelope each prints |
CLI reference |
every shipped X_* code: its name and its meaning. A code is never renamed or reused |
Error codes |
| the package tier table |
scripts/lib/tiers.ts, Project layout
|
app.config.ts field names: renaming or removing one |
Configuration |
every export a package's src/index.ts names and its README documents |
each package's README.md
|
| the Bun floor |
engines in every package.json; it moves only in a scheduled major, or by the security exception |
| Not covered | Why |
|---|---|
an export no README documents, and any deep import (@ultimat3/x/src/...) |
not a public surface; it can change in a minor |
.x/ — the build cache, generated manifests, snapshots |
regenerated by the CLI; never hand-edited, never read by an app |
the exact wording of a cause: or fix: line |
the code is the contract; the text improves in any release |
| a gate verdict getting stricter | a new x verify rule that reds an app waits on next like any break |
| performance figures and budgets | measurements, each dated in its committed JSON under scripts/bench/results/, never promises. bench.yml is meant to re-measure the first-hour and HTTP figures weekly and on each release, as a pull request; As of 2026-11-10 its one run measured and could not open that pull request, so the committed figures are older. Budgets: Routes and render modes
|
Never "stable forever": a covered surface can change, in a scheduled major, with its entry in Upgrading.
| Bump | Means | Examples |
|---|---|---|
| major | a covered surface changed incompatibly | a removed config field, a renamed CLI flag, a changed primitive field, a narrowed tier |
| minor | additive: old code still compiles and still passes x verify
|
a new optional field, a new command, a new driver behind an existing interface, a new @deprecated alias |
| patch | no surface change | a bug fix, a perf change, a corrected fix: line |
| Release | When | Branch | npm dist-tag |
|---|---|---|---|
| major | at most once per 90 days from v31, counted from the heading date of the previous major's docs/changelog/<major>.0.0.md
|
next, merged into main when the window opens |
latest |
| minor | weekly, when something shipped | main |
latest |
| patch to the current major | as needed | main |
latest |
| patch to the previous major | security fixes only, until 6 months after its successor shipped | release/<major>.x |
maint-<major> |
| prerelease of the next major — planned, nothing ships one yet |
release-tag.yml cuts only X.Y.Z release commits, so no workflow publishes from next
|
next |
next (scripts/dist-tag.ts already names it) |
v31 is the stable line, dated 2026-11-10 by the heading of docs/changelog/31.0.0.md. It was the exception that starts the clock: it carried every break queued before the promise bound anyone (74, Upgrading), and scripts/release.ts does not refuse it (WINDOW_OPENS_AT_MAJOR in scripts/lib/major-window.ts). From it on, a BREAKING — entry waits on next and a removal ships its deprecation minor first.
Ruling 2026-11-09: the clock moved from v30 to v31. v30 shipped 2026-11-07 while only our own apps ran Ultimate in production, so the window protected no one yet; v31 carries the breaks of plan 101-final-hardening-before-v31, and the window protects adopters from there.
| Major | Status | Security fixes until |
|---|---|---|
the current major (npm view @ultimat3/core version) |
every fix | its successor ships, then 6 months more |
| the previous major | security fixes, as patches on release/<major>.x
|
6 months after the current major's ## X.0.0 date |
| anything older | none |
Upgrading, one major per x upgrade run |
Convention, not enforced: release/<major>.x is cut by hand at each major and kept at that major's newest minor; no script cuts it. Its name is enforced: ci.yml and release-tag.yml match exactly release/[0-9]+.x, and scripts/release.ts --bump refuses any other release/* branch (X_RELEASE_BRANCH_NAME). A bump PR's own branch is chore/release-X.Y.Z, never release/X.Y.Z (#1054). Once it exists, a patch is latest while its major is current and maint-<major> once its successor ships. scripts/dist-tag.ts decides the tag from the registry's latest, and npm publish never runs without it.
A removal or a rename ships its alias, marked @deprecated, on main for at least one minor before a major takes it away. The rule compares each package's src/index.ts export names against the previous release tag: a name that is gone must have carried @deprecated there. Runtime deprecation logging is not part of this — it was deleted once, for good reason (Upgrading).
| Branch | Holds |
|---|---|
main |
minors and patches only while the window is closed; a BREAKING — changelog entry there is refused |
next |
every breaking change waiting for the window. Convention, not enforced: it merges main weekly, by hand, so it never falls behind a fix; ci.yml gates every push to it |
release/<major>.x |
the previous major's security patches |
A change with both kinds of edit splits into two pull requests: the non-breaking half to main, the break to next.
A security fix that cannot be made non-breaking may ship a major inside the window. It is the only exception — "critical bug" is not one, or it would be used every week.
bun run scripts/release.ts --bump major --security GHSA-xxxx-xxxx-xxxx --dry-run --jsonThe advisory id (a GHSA-… or CVE-…) is recorded under the heading of the release's docs/changelog/<version>.md (under [Unreleased] in CHANGELOG.md before the bump) as > **Security exception:** \`, and the bump commit's body carries Security-Exception: `. The same recorded line lets a removal skip its deprecation minor.
The maintainer bot judges whether a release is due and which kind (.dz/briefs/release-due.md), inside this window: it cannot cut a major the window refuses, because scripts/release.ts refuses it before any file moves, release.ts --check refuses it again before a tag is cut, and the gate refuses a dated section that broke it.
| Rule | Refused by | Code |
|---|---|---|
| one major per 90 days |
scripts/release.ts --bump, --check, and the gate's boundaries step |
X_RELEASE_MAJOR_WINDOW |
no break on main while the window is closed |
bun run changelog-check and the gate, on the pull request's base branch |
X_BREAKING_ON_MAIN |
| a removal was deprecated first |
bun run scripts/deprecation-window.ts and the gate |
X_RELEASE_UNDEPRECATED_REMOVAL |
| every release from 30.0.0 opens with Highlights, the Release body |
bun run changelog-check and the gate, over docs/changelog/
|
X_CHANGELOG_HIGHLIGHTS_MISSING |
a bump branch is chore/release-X.Y.Z; release/* is only release/<major>.x
|
scripts/release.ts --bump; ci.yml and release-tag.yml filter on release/[0-9]+.x (scripts/release-tag-workflow-shape.test.ts) |
X_RELEASE_BRANCH_NAME |
a maintenance publish never moves latest
|
scripts/dist-tag.ts in release.yml; scripts/registry-audit.ts audits latest and each maint-* tag |
X_REGISTRY_LATEST_DRIFT |
Ultimate — v31.9.0 As of 2026-10. The full-stack framework where the primary developer is an AI agent: bunx create-ultimate myapp → Getting started · live demo. MIT licensed. What npm serves is npm view @ultimat3/core version, never this line, and this footer is the only page that stamps a version.
Repository · Issues · Changelog · llms.txt
Edits to these pages are synced from wiki/ in the repository — change the file there, not the wiki, or the next sync overwrites it.
Start
- Getting started
- Installation
- Shapes
- Bare VM
- Project layout
- Migrating an existing app
- Compared to other stacks
Tutorials
- 1 · First app
- 2 · First feature
- 3 · Auth and admin
- 4 · Jobs and realtime
- 5 · Deploy free
- 6 · Growing up
Primitives
- The eight primitives
- Building your own base
- Actions
- Entities and migrations
- Policies and authz
- Queries and live queries
- Client data
- Jobs and workflows
- Scheduled tasks
- Routes and render modes
Capabilities
- Realtime
- Caching and invalidation
- Batching and preloading
- N+1 detection
- PWA and offline
- Client navigation
- MCP and AI
- Agents
- Admin dashboard
- Scraping
- Auth
- Notify
- Storage and uploads
- Feature flags
- SEO
- Static assets
Cross-cutting
- I18n
- Theming
- UI components
- Interface rules
- Timezones and dates
- Money
- Outbound HTTP
- Resource management
- Migrations and backfills
- Testing
- CI: the gate across parallel jobs
Reference