Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ Semver applies from 1.0.0. A breaking change to a documented API needs a major

## [Unreleased]

## 2.0.0 - 2026-08-17

**The first major.** 33 entries below are marked `BREAKING —`, and each one changes a surface semver covers: a primitive field, an export, a CLI flag, an `app.config.ts` key, or a tier edge. Semver applies from 1.0.0, so none of them could ship as a minor. Read [Upgrading](https://github.com/developerz-ai/ultimate/wiki/Upgrading), then the `BREAKING —` entries in order — **no codemod ships with this release**, so each one is a manual edit, and the entry names it.

All 29 workspaces move together — 28 `@ultimat3/*` plus the unscoped `create-ultimate`, one version, one commit, one tag. Publication is not in lockstep: **`@ultimat3/flags` is still not on the registry**, and its first publish is a manual bootstrap by an npm org member ([PUBLISHING.md](PUBLISHING.md), step 1) because a trusted publisher cannot attach to a package that does not exist. The workflow's publish list is derived from `scripts/list-workspaces.ts`, so no package can be silently absent from a release again.

### Fixed

- **An unregistered currency arriving over HTTP answered 500 and paged the on-call.**
Expand Down Expand Up @@ -2606,10 +2612,10 @@ Not fixed, and each one hit by actually running the command. Full list in [Known

### Known gaps

- `x build --target binary` compiles but crashes at import: `FRAMEWORK_VERSION` reads `package.json` at module scope and a single-file executable has none.
- `docker-compose.prod.yml` declares a host port and `replicas: 3` together — two processes cannot bind one port. This is the rung-1 ceiling. **Closed in [Unreleased]**: `web` and `sync` are `replicas: 1` in all four files, and the ceiling is declared with the two ways up named.
- The shared cache tier's Lua invalidation `DEL`s keys it never declared in `KEYS`, so it fails on Dragonfly and on Redis Cluster. **Closed in [Unreleased]**.
- `resolveEnvironment` now exists in both `core` and `seo` with different return types. **Closed in [Unreleased]**, as a breaking change: `@ultimat3/seo` exports neither it nor `SeoEnvironment`.
- `x build --target binary` compiles but crashes at import: `FRAMEWORK_VERSION` reads `package.json` at module scope and a single-file executable has none. **Closed in 2.0.0**: the read is lazy, `x build` and `docker/Dockerfile` both pass `--define ULTIMATE_FRAMEWORK_VERSION`, and the image build ends in `/out/app --version`.
- `docker-compose.prod.yml` declares a host port and `replicas: 3` together — two processes cannot bind one port. This is the rung-1 ceiling. **Closed in 2.0.0**: `web` and `sync` are `replicas: 1` in all four files, and the ceiling is declared with the two ways up named.
- The shared cache tier's Lua invalidation `DEL`s keys it never declared in `KEYS`, so it fails on Dragonfly and on Redis Cluster. **Closed in 2.0.0**.
- `resolveEnvironment` now exists in both `core` and `seo` with different return types. **Closed in 2.0.0**, as a breaking change: `@ultimat3/seo` exports neither it nor `SeoEnvironment`.

## [1.0.0] - 2026-08-10

Expand Down
13 changes: 8 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ This repo is the framework itself: a monorepo of `@ultimat3/*` packages, the `x`

CLI binary: `x`. npm scope: `@ultimat3`. Import paths: `@ultimat3/<pkg>`.

**Status:** 1.2.0, `As of 2026-08`. 28 `@ultimat3/*` packages plus the unscoped `create-ultimate` —
29 in all — **versioned** in lockstep: one version, one commit, one tag. Publication is not in
**Status:** 2.0.0, `As of 2026-08`. 28 `@ultimat3/*` packages plus the unscoped `create-ultimate` —
29 in all — **versioned** in lockstep: one version, one commit, one tag. That is the rule; for 2.0.0
the version and the commit are done and the tag and the publish are not — nothing at 2.0.0 is on
npm, where the latest is still 1.2.0. 2.0.0 is the **first major**: the 2.0.0 section of [`CHANGELOG.md`](CHANGELOG.md) carries 33 entries marked
`BREAKING —` and ships no codemod, so each one is a manual edit its own entry names. Publication is not in
Comment thread
coderabbitai[bot] marked this conversation as resolved.
lockstep and the repo said it was until 2026-08: **`@ultimat3/flags` has never been published** —
the registry answers 404, not a stale version — so 28 of the 29 are on npm. It is not opting out
(`packages/flags/package.json` declares the same `publishConfig` as the rest) and nothing in the
Expand Down Expand Up @@ -54,13 +57,13 @@ Open: roadmap milestone 11's two-platform deploy proof — 1.1.0 gave a scaffold
deployable artifact (`packages/cli/src/serve.ts`; `x new` writes `apps/web/server.ts`,
`prerender.ts`, a Dockerfile and `docker-compose.prod.yml`; `ROLE=migrate` runs release-phase
migrations), but the demo app on Compose **and** K8s from one image with an invisible rolling
restart is still not demonstrated — and until this branch the chart could not have demonstrated it,
restart is still not demonstrated — and until 2.0.0 the chart could not have demonstrated it,
because `sync`'s readiness probe polled a port the process never opened. Of the four known gaps
named in [`CHANGELOG.md`](CHANGELOG.md), **all four are now closed**, `As of 2026-08`:
named in [`CHANGELOG.md`](CHANGELOG.md), **all four are closed in 2.0.0**, `As of 2026-08`:

| Gap | State |
|---|---|
| `x build --target binary` compiled and crashed at import | **fixed, and now proven** — the version read is lazy and `x build` passes `--define ULTIMATE_FRAMEWORK_VERSION`. `docker/Dockerfile` passes it too as of this branch; it had not, so the target was fixed everywhere except in the artifact the framework ships. The image build now ends in `/out/app --version`, so a binary that cannot answer fails the build rather than the first command an operator runs |
| `x build --target binary` compiled and crashed at import | **fixed, and now proven** — the version read is lazy and `x build` passes `--define ULTIMATE_FRAMEWORK_VERSION`. `docker/Dockerfile` passes it too as of 2.0.0; it had not, so the target was fixed everywhere except in the artifact the framework ships. The image build now ends in `/out/app --version`, so a binary that cannot answer fails the build rather than the first command an operator runs |
| the shared cache tier's Lua invalidation `DEL`s keys it never declares in `KEYS` | **fixed** — the script returns the member list and the tier deletes value keys client-side, one key per `DEL`, so it is slot-local on Redis Cluster and Dragonfly |
| `docker-compose.prod.yml` pairs a published host port with `replicas` above 1 | **fixed** — a published host port has exactly one binder (reproduced: the second replica dies with `Bind for 0.0.0.0:3000 failed: port is already allocated`), so `web` and `sync` declare `replicas: 1` in all four files — framework, both tracked apps, and `x new`'s scaffold. Scaling either is the reverse proxy you add or the chart's per-role HPA, both named in the file header: Compose is the ladder's single-node rung and the box is the availability story |
| `resolveEnvironment` exists in both `core` and `seo` with different return types | **fixed** — seo's is deleted; core's is the one reader of `ULTIMATE_ENV`, and `'preview'` is now core's `'staging'`. The half that was not obvious: `ULTIMATE_ENV` is **not in the env schema**, so nothing validates it at boot and a `robots.txt` render can be its first reader — hence `tryResolveEnvironment()` in core, which answers `undefined` rather than throwing, instead of a second resolver in seo |
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
[![CI](https://github.com/developerz-ai/ultimate/actions/workflows/ci.yml/badge.svg)](https://github.com/developerz-ai/ultimate/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Bun](https://img.shields.io/badge/bun-%E2%89%A5%201.3-black.svg?logo=bun)](https://bun.sh)
[![Version](https://img.shields.io/badge/version-1.2.0-blue.svg)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-2.0.0-blue.svg)](CHANGELOG.md)

</div>

> **Status: 1.2.0**, `As of 2026-08`. 28 `@ultimat3/*` packages plus the unscoped `create-ultimate` — 29 in all — versioned in lockstep: one version, one commit, one tag. **`@ultimat3/flags` has never reached npm** and the rest sit at 1.2.0, so the registry is not yet in lockstep with the repo ([#84](https://github.com/developerz-ai/ultimate/issues/84)); it needs the one-time manual bootstrap every package gets before a trusted publisher can attach. 1.1.0 was the **first release published by the workflow**, over OIDC trusted publishing with provenance attached; 1.0.0 was the manual bootstrap. Semver applies — a breaking change to a documented API needs a major. That is what the version number means: a stable API under semver, not a promise about your infrastructure.
> **Status: 2.0.0 in the repository, not on npm**, `As of 2026-08`. 28 `@ultimat3/*` packages plus the unscoped `create-ultimate` — 29 in all — are **versioned** in lockstep: one version, one commit, one tag. Versioned and committed is done; the tag and the publish are not. **The first major**: [CHANGELOG.md](CHANGELOG.md)'s 2.0.0 section carries 33 entries marked `BREAKING —`, and no codemod ships with them, so each is a manual edit its entry names ([Upgrading](https://github.com/developerz-ai/ultimate/wiki/Upgrading)). **Nothing at 2.0.0 is installable yet** — npm's latest is **1.2.0**, which is what `bunx create-ultimate myapp` gives you today. The blocker is `@ultimat3/flags`, which has never reached npm at any version ([#84](https://github.com/developerz-ai/ultimate/issues/84)) and needs the one-time manual bootstrap every package gets before a trusted publisher can attach: it is tier 1 and in the derived publish list, so a release run without it aborts with `core` and `schema` already published irreversibly. [PUBLISHING.md](PUBLISHING.md) names the four human steps and records that none is done. 1.1.0 was the **first release published by the workflow**, over OIDC trusted publishing with provenance attached; 1.0.0 was the manual bootstrap. Semver applies — a breaking change to a documented API needs a major. That is what the version number means: a stable API under semver, not a promise about your infrastructure.

## Built by agents, for agents, maintained by agents

Expand Down Expand Up @@ -51,13 +51,13 @@ are the difference between an agent that ships and one that thrashes.

Reproduce it: `bun run scripts/bench/restart-bench.ts --clients 10000 --probe-interval-ms 200` — the committed report and the run's own transcript are in [`scripts/bench/results/`](scripts/bench/results/).

**Not claimed at 1.1.0:**
**Not claimed at 2.0.0:**

| Open | Where it stands |
|---|---|
| **Two-platform deploy proof** | 1.1.0 gave a scaffolded app a real deployable artifact — `x new` writes `apps/web/server.ts`, `prerender.ts`, a Dockerfile and `docker-compose.prod.yml`, and `ROLE=migrate` runs release-phase migrations. The **proof** is still open: the demo app on Compose **and** K8s from one image, with an invisible rolling restart, is [milestone 11](docs/idea/14-roadmap.md) and has not been demonstrated |
| **Known gaps shipped in 1.1.0** | all four are fixed on `main`, unreleased — but a fix and a proof are different things, and one of the four still lacks the proof. `x build --target binary` no longer crashes at import — the version read is lazy and `x build` passes `--define ULTIMATE_FRAMEWORK_VERSION`, and [`docker/Dockerfile`](docker/Dockerfile) passes it too and ends in `/out/app --version`, so a binary that cannot answer fails the image build rather than the first command an operator runs. The target is still unproven end to end: booting is not serving, and no scaffolded app has been compiled and served from a bare VM · `docker-compose.prod.yml` no longer pairs a published host port with `replicas` above 1: `web` and `sync` declare `replicas: 1` in all four files and each header names the two ways up, which makes the one-box ceiling declared rather than broken, not lifted · the shared cache tier's Lua invalidation no longer `DEL`s keys it never declares in `KEYS` · `resolveEnvironment` exists only in `core`, and `@ultimat3/seo` exports neither it nor `SeoEnvironment` — a **breaking** change, unreleased. Detail in [CHANGELOG.md](CHANGELOG.md), per-row workarounds for the published packages in [Known gaps](https://github.com/developerz-ai/ultimate/wiki/Known-Gaps) |
| **Deferred to v2** | realtime tier 3 local-first (`persist: true`), the plugin API, multi-region replication, the Redis/NATS **job** drivers — each behind the interface that ships today. The job drivers throw `X_NOT_IMPLEMENTED` with a runnable `fix:` rather than pretending to work |
| **Known gaps shipped in 1.1.0** | all four are fixed in 2.0.0 — but a fix and a proof are different things, and one of the four still lacks the proof. `x build --target binary` no longer crashes at import — the version read is lazy and `x build` passes `--define ULTIMATE_FRAMEWORK_VERSION`, and [`docker/Dockerfile`](docker/Dockerfile) passes it too and ends in `/out/app --version`, so a binary that cannot answer fails the image build rather than the first command an operator runs. The target is still unproven end to end: booting is not serving, and no scaffolded app has been compiled and served from a bare VM · `docker-compose.prod.yml` no longer pairs a published host port with `replicas` above 1: `web` and `sync` declare `replicas: 1` in all four files and each header names the two ways up, which makes the one-box ceiling declared rather than broken, not lifted · the shared cache tier's Lua invalidation no longer `DEL`s keys it never declares in `KEYS` · `resolveEnvironment` exists only in `core`, and `@ultimat3/seo` exports neither it nor `SeoEnvironment` — a **breaking** change, which is part of why 2.0.0 is a major. Detail in [CHANGELOG.md](CHANGELOG.md), per-row workarounds for the 1.x packages in [Known gaps](https://github.com/developerz-ai/ultimate/wiki/Known-Gaps) |
| **Deferred past 2.0.0** | realtime tier 3 local-first (`persist: true`), the plugin API, multi-region replication, the Redis/NATS **job** drivers — none of them ships in 2.0.0, each behind the interface that ships today. The job drivers throw `X_NOT_IMPLEMENTED` with a runnable `fix:` rather than pretending to work |

**Never claimed:** no adoption numbers, no production deployments, no testimonials. None exist yet, and this file will say so until they do.

Expand Down Expand Up @@ -223,13 +223,13 @@ Render mode is a route-level property, not a global one. A landing page is stati

## Realtime — a ladder, not a cliff

Three tiers, the same mutator shape at every rung. Tier 2 → tier 3 is a config flag, not a rewrite. Tiers 1–2 ship today; tier 3 lands in v2, behind the interfaces that are already here.
Three tiers, the same mutator shape at every rung. Tier 2 → tier 3 is a config flag, not a rewrite. Tiers 1–2 ship today; tier 3 is not in 2.0.0 and lands in a later major, behind the interfaces that are already here.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

| Tier | What | Covers |
|---|---|---|
| 1 · **Channels** | `ctx.publish(topic, msg)` over Bun's native WS pub/sub | presence, cursors, notifications |
| 2 · **Live queries** | declare server-side with a policy, receive a Solid signal | **90% of "realtime app"** |
| 3 · **Local-first** *(v2)* | optimistic mutators, OPFS SQLite, offline queue, rebase | offline writes that reconcile |
| 3 · **Local-first** *(not in 2.0.0)* | optimistic mutators, OPFS SQLite, offline queue, rebase | offline writes that reconcile |

→ [Realtime design and its honest limits](docs/idea/03-realtime.md)

Expand Down Expand Up @@ -258,9 +258,9 @@ The same app code on one PaaS dyno and on a replicated cluster. Climbing is a dr
| DB | **Postgres**, no ORM | `entity()` is the one table declaration; `postgresDriver()` emits hand-written parameterised SQL, so an agent reads the statement and self-corrects |
| Validation | **Standard Schema**, builtin provider default | dependency-free and shipped; ArkType/Zod/Valibot swap in behind `configureSchemaProvider()` with a ~40-line adapter you write |
| Auth | **Better Auth**, wrapped | MIT, self-hosted, with our policy layer on top |
| Frontend | **SolidJS 2** + our own router | fine-grained reactivity; we vendor the router rather than track an alpha |
| Frontend | **SolidJS, pinned `1.9.14`** + our own router | fine-grained reactivity on the stable line; Solid 2 is still `2.0.0-beta.N`, and we vendor the router rather than track an alpha |
| Styling | **SCSS modules + design tokens** | no Tailwind (diff noise), no CSS-in-JS (runtime cost) |
| Jobs | Postgres queue default; Redis/NATS drivers in v2 | zero-infra start, a real scale path behind one interface |
| Jobs | Postgres queue default; Redis/NATS drivers not in 2.0.0 | zero-infra start, a real scale path behind one interface |
| Observability | **OpenTelemetry, always on** | one trace across HTTP → job → live query |

**Excluded on purpose:** GraphQL · multi-runtime · multi-ORM · a second CSS solution · React Server Components · a plugin API in 1.x · vendor edge/KV primitives.
Expand Down
10 changes: 5 additions & 5 deletions docker/helm/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ type: application
# (values.yaml `image.tag: ""`), so 0.0.1 named a tag that has never existed for any release — a
# fresh `helm install` with the shipped values pulled `ultimate-app:0.0.1` and got ImagePullBackOff.
#
# Nothing rewrites these on release yet: `scripts/release.ts` walks workspace package.json files and
# a chart is not a workspace. Until it does, this is a hand-kept number, which is the same defect
# class as the publish list in .github/workflows/release.yml — reported, not left silent.
version: 1.2.0
appVersion: "1.2.0"
# `scripts/release.ts` rewrites both on every release through `setChartVersions` — a chart is not a
# workspace, so the manifest loop cannot reach it and the script writes it by path instead. Never
# hand-edit them: the chart moving on its own is how `appVersion` named an image tag nobody pushed.
version: 2.0.0
appVersion: "2.0.0"
kubeVersion: ">=1.27.0-0"
keywords: [bun, postgres, solidjs, ultimate]
home: https://ultimate.dev
Expand Down
Loading