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
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ Semver applies from 1.0.0. A breaking change to a documented API needs a major

## [Unreleased]

## 3.0.0 - 2026-08-19

The first release *able* to go through the workflow since 1.2.0: every package now has an OIDC
trusted publisher, and none had one before. 2.0.0 was hand-published without provenance precisely
because there was nothing for the exchange to verify against. `@ultimat3/scraping` — 404 since it
landed after the 2.0.0 run — was bootstrapped by hand at 2.0.0 so the derived publish list can
reach it here.

Whether this release *did* publish with provenance is a fact about the registry, not about this
file: `npm view @ultimat3/core@3.0.0 dist.attestations` answers it.

A major because a five-agent bug sweep landed breaking changes to documented APIs. The
entries below are that sweep; each names the manual edit it costs.

### Added

- **`agent()` — the tool loop, as an action factory.** The third instance of the rule after `llm()`
Expand Down Expand Up @@ -608,6 +622,32 @@ Semver applies from 1.0.0. A breaking change to a documented API needs a major
that trusted that page called five tools the server answers ToolNotFound for. The table is now
the thirteen `devTools(host)` declares, with each one's scope.

### Merged pull requests

The prose above says what changed and why; this is which pull request carried it.

**Added**

- browser automation as a job factory, with zero new dependencies (#140)
- an agent's tool can be a real action, and a hive of agents is an action (#139)
- adopt an existing database, and make a seed replayable (#137)

**Fixed**

- an apostrophe in JSX text turned the errors gate off for a whole file (#158)
- a crafted icon executed at import, and a session cookie went to the wrong host (#152)
- the outbox claim locked nothing, and a drain released nothing (#148)
- the contracts that said "never throws" threw, and a gate that was never enforced (#147)
- an unreadable password hash was an enumeration oracle (#141)
- a terminal error is retried, because the executor never reads the classification (#138)
- the trusted publisher was attached without its environment, and the check could never see it (#136)

**Changed**

- the release status said the opposite of the registry, in ten files (#159)
- agents, and a migration guide an AI agent can execute (#142)


## 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.
Expand Down
72 changes: 45 additions & 27 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,50 @@ This repo is the framework itself: a monorepo of `@ultimat3/*` packages, the `x`

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

**Status:** 2.0.0 — **versioned, tagged, pushed and on npm**, `As of 2026-08`. `v2.0.0` is on
origin and the registry's `latest` is 2.0.0. 29 `@ultimat3/*` packages plus the unscoped
`create-ultimate` — 30 in all — are **versioned** in lockstep: one version, one commit, one tag.
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. 1.1.0
was the first release published by
[`.github/workflows/release.yml`](.github/workflows/release.yml) over OIDC trusted publishing,
provenance attached; 1.0.0 was the manual bootstrap. **2.0.0 was not**: no package has a trusted
publisher attached (`trust-publishers.ts --check` answers 0 of 30), so the OIDC exchange has nothing
to verify against and 2.0.0 was published by hand — `_npmUser: sebyx07`, no `dist.attestations`,
where 1.1.0 and 1.2.0 carry both. Semver applies — a breaking change to a
documented API needs a major, and the eight primitive shapes, the `x` CLI surface and the tier table
are as stable as the `X_*` codes already were.

**Publication is not in lockstep, and one package is behind: `@ultimat3/scraping` has never been
published.** The registry answers 404, not a stale version — so 29 of the 30 are on npm and
`bun add @ultimat3/scraping` fails. It is not opting out (`packages/scraping/package.json` declares
the same `publishConfig` as the rest) and nothing in the repo notices, because every consumer
resolves it through the workspace. The cause is timing: it landed after the 2.0.0 publish run, so
the run never saw it. That is exactly the hole `@ultimat3/flags` used to be — closed at 2.0.0, which
is `flags`' only version on the registry, by the one-time manual bootstrap every package needs
before a trusted publisher can attach. **It costs the next release run.** `scraping` is **27th of
30** in the derived publish order (`bun run scripts/release-workflow.ts --json`), so the run reaches
it and dies there with **26 packages already published irreversibly**. The bootstrap is
[`PUBLISHING.md`](PUBLISHING.md) step 1; the list is derived so the failure is loud rather than a
silent skip.
**Status:** 3.0.0 in the repository, `As of 2026-08`. 29 `@ultimat3/*` packages plus the unscoped
`create-ultimate` — 30 in all — **versioned** in lockstep: one version, one commit, one tag.

**The registry is one release behind the repository between a bump and its workflow run — that is
where this commit sits.** Never read a number here as the installable one; run the command beside it.

| Fact | State, `As of 2026-08-19` | Read it yourself |
|---|---|---|
| Repository version | 3.0.0, every workspace stamped | `bun run scripts/release.ts --check 3.0.0` |
| Publishable workspaces | 30 | `bun run scripts/release-workflow.ts --json` |
| On the registry | **all 30**, no holes | `bun run scripts/release-workflow.ts --json # the derived list; check every name against npm view` |
| npm `latest` | **2.0.0** — the `v3.0.0` tag and the publish run follow this commit | `npm view @ultimat3/core version` |
| OIDC trusted publisher | attached to all 30 | `NPM_CONFIG_OTP=<code> bun run scripts/trust-publishers.ts --check --json` — without a fresh OTP every package reads as missing |
Comment thread
coderabbitai[bot] marked this conversation as resolved.

**`@ultimat3/scraping` is on the registry, and it was the last publication hole.** It was bootstrapped
by hand at 2.0.0 on 2026-08-19 — `npm publish --access public --provenance=false`, the one-time step
every package needs before a trusted publisher can attach — and npm now answers `E403 … cannot
publish over the previously published versions: 2.0.0` on a retry. `@ultimat3/flags` was the same
shape and was closed the same way at 2.0.0. Publication is a step apart from versioning; the publish
list is **derived** from `scripts/list-workspaces.ts`, which is what keeps a new package from being
silently absent from it. Step 1 of [`PUBLISHING.md`](PUBLISHING.md) comes due again for the next
package added after a release run, and nothing else.

**3.0.0 is a major** because a five-agent bug sweep landed breaking changes to documented APIs:
`mfa.required` refused and narrowed to the literal `false`, `enrolTotp(auth, input)`, `appErrorStatus`
removed, `SocketRegistry.sweepIdle()` → `idle()`, `SyncSocket.lastSeenAt` → `lastSeenMonotonicMs`,
two `SQL_OUTBOX_*` constants gaining a parameter, `DESCRIPTION_MIN_LENGTH` deleted, and a metric
redeclared with different bounds now refused. The 3.0.0 section of [`CHANGELOG.md`](CHANGELOG.md)
carries **10** entries marked `BREAKING —` and ships no codemod, so each one is a manual edit its own
entry names. 2.0.0 was the **first** major and carried 33.

**Every package has an OIDC trusted publisher, attached 2026-08-19 — for the first time.**
`developerz-ai` / `ultimate` / `release.yml` / environment `npm-publish`, publish permission, all 30,
verified per package with `npx -y npm@12 trust list <pkg> --json` — `npm trust` shipped in **npm 12**
and Bun's bundled npm answers it as an unknown command, which is why `scripts/trust-publishers.ts`
pins the runner. **That is why 2.0.0 has no provenance**: with no publisher attached the OIDC
exchange had nothing to verify against, so the workflow could not publish and 2.0.0 went out by
hand — `_npmUser: sebyx07`, no `dist.attestations`, where 1.1.0 and 1.2.0 carry both. 1.1.0 was the
first release [`.github/workflows/release.yml`](.github/workflows/release.yml) published over OIDC;
1.0.0 was the manual bootstrap. 3.0.0 is the first release since 1.2.0 that **can** run through the
workflow — whether it did is `npm view @ultimat3/core@3.0.0 dist.attestations`, not a sentence here.

Semver applies — a breaking change to a documented API needs a major, and the eight primitive shapes,
the `x` CLI surface and the tier table are as stable as the `X_*` codes already were.

Realtime capacity is **measured on one node, in two halves that answer different questions**.

Expand Down Expand Up @@ -225,7 +243,7 @@ Everything in the framework is one of these. **If a feature doesn't fit one of t

## CI

Free GitHub Actions runners (`ubuntu-latest`) — never a paid runner. `ci.yml` runs three jobs, each answering a question no other job answers: `verify` (the gate, `x verify` verbatim — lint, typecheck, boundaries and every suite are its steps, never a second job), `reference-app-verify` (the app gate, on its ratchet) and `scaffold-smoke` (`x new` → `bun install` → `x verify` outside the checkout). Target under 5 minutes. Every job starts with `./.github/actions/setup` — bun, the install cache, a frozen install. Releases publish to npm via **OIDC trusted publishing**, with provenance — that is what the workflow does, and it is not what 2.0.0 did: with 0 of 30 trusted publishers attached it cannot run, so 2.0.0 was hand-published without attestations. See [`PUBLISHING.md`](PUBLISHING.md), which names the two steps that are owed.
Free GitHub Actions runners (`ubuntu-latest`) — never a paid runner. `ci.yml` runs three jobs, each answering a question no other job answers: `verify` (the gate, `x verify` verbatim — lint, typecheck, boundaries and every suite are its steps, never a second job), `reference-app-verify` (the app gate, on its ratchet) and `scaffold-smoke` (`x new` → `bun install` → `x verify` outside the checkout). Target under 5 minutes. Every job starts with `./.github/actions/setup` — bun, the install cache, a frozen install. Releases publish to npm via **OIDC trusted publishing**, with provenance — which 2.0.0 did not get, because no trusted publisher existed for the exchange to verify against. All 30 were attached on 2026-08-19, so 3.0.0 is the first release since 1.2.0 that can run through the workflow. See [`PUBLISHING.md`](PUBLISHING.md).

## Note

Expand Down
107 changes: 66 additions & 41 deletions PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@ Releases use **OIDC trusted publishing** from GitHub Actions
mints a short-lived token from the run's OIDC identity and attaches a provenance attestation
automatically.

**`As of 2026-08`: 30 workspaces publish; 29 are on the registry, all at 2.0.0.** `v2.0.0` is
tagged and pushed and npm's `latest` is 2.0.0. **`@ultimat3/scraping` has never been published** —
the registry answers 404, not a stale version. It is not opting out:
`packages/scraping/package.json` declares the same `publishConfig` as the other 29, and every
consumer resolves it through the workspace, so nothing in the repo noticed. The cause is timing, not
the workflow: `scraping` landed after the 2.0.0 publish run, so the run never saw it. Its first
publish is a human step — see
[Human steps outside this file](#human-steps-outside-this-file).

`@ultimat3/flags` was the previous instance, for the opposite reason: the workflow listed its `-w`
flags by hand and omitted it. That list is now **derived** from `scripts/list-workspaces.ts`, so
`flags` and every package added since are in it by construction — which is why the 2.0.0 run
published `flags` for the first time, and why the next run will reach `scraping` and fail on it
loudly.

The counts and the 404 are a snapshot and go stale the moment step 1 below is done; that the list is
derived is a rule and does not.
**`As of 2026-08-19`: 30 workspaces publish and all 30 are on the registry.** `v2.0.0` is tagged
and pushed and npm's `latest` is 2.0.0; the repository is at 3.0.0, which the workflow has not
published yet.

**There is no publication hole today, and there have been two.** `@ultimat3/flags` was the first:
the workflow listed its `-w` flags by hand and omitted it. That list is now **derived** from
`scripts/list-workspaces.ts`, so every package is in it by construction — which is why the 2.0.0 run
published `flags` for the first time. `@ultimat3/scraping` was the second, for the opposite reason:
it landed *after* the 2.0.0 run, so no run had ever seen it. It was bootstrapped by hand on
2026-08-19 (step 1 below).

The pattern is the point: **a package added after a release run is unpublished until someone
bootstraps it**, and the derived list guarantees the *next* run fails loudly on it rather than
skipping it silently. Expect this again for the next new package.

The counts are a snapshot and go stale on the next release; that the list is derived is a rule and
does not. Read the state — `bun run scripts/release-workflow.ts --json` for the order,
`npm view <pkg> version` for what the registry holds — never this paragraph.

## Lockstep versioning — the rule

Expand Down Expand Up @@ -107,25 +108,33 @@ approval-gated environment, which is the half GitHub cannot enforce, and it must

## Human steps outside this file

**`As of 2026-08` steps 1 and 2 are done and steps 3 and 4 are NOT, measured against the registry.**
`bun run scripts/trust-publishers.ts --check` answers `0/30 packages trust
developerz-ai/ultimate/release.yml` — every one reports `X_TRUST_PUBLISHER_MISSING`. This file
claimed all four were done until 2026-08.
**`As of 2026-08-19` all four are done, for all 30 packages** — steps 3 and 4 for the first time.
Until then no package had a trusted publisher at all, and this file claimed otherwise.

**That is why 2.0.0 has no provenance.** With no trusted publisher attached, the OIDC exchange has
nothing to verify against, so the workflow cannot publish and 2.0.0 went out by hand instead: every
**That is why 2.0.0 has no provenance.** With no trusted publisher attached, the OIDC exchange had
nothing to verify against, so the workflow could not publish and 2.0.0 went out by hand: every
`@ultimat3/*` package at 2.0.0 carries `_npmUser: sebyx07` and **no `dist.attestations`**, while
1.1.0 and 1.2.0 carry attestations and `_npmUser: GitHub Actions`. The releases that ran through
the workflow are the older ones. Read the state, never this sentence:
1.1.0 and 1.2.0 carry attestations and `_npmUser: GitHub Actions`. 3.0.0 is the first release since 1.2.0
that *can* run through the workflow — confirm it did with
`npm view @ultimat3/core@3.0.0 dist.attestations`, never from this sentence.

**Two traps met while doing steps 3 and 4, both worth knowing before you redo them:**

| Trap | What happens |
|---|---|
| `npm trust list` itself needs an OTP | so `--check` without one reports **every** package missing. A `0/30` is not evidence of anything until a code is supplied — and the script takes it as `NPM_CONFIG_OTP=<code>`, never a `--otp` flag, which it does not parse |
| One OTP does not cover 30 packages | a code lasts 30s and npm rate-limits verification (`E429 … OTP verification failed`). Attach in batches on fresh codes; an already-attached package answers `E409 … already exists`, which is a success, not a failure |

Read the state, never this sentence:

```sh
bun run scripts/trust-publishers.ts --check --json
npm view @ultimat3/core@<version> dist.attestations
```

Step 2 is once per repository and stays done; **steps 1, 3 and 4 are once per package** and come due
again for every package added after a release run — all three are owed for `@ultimat3/scraping`, and
step 1 is the one that breaks a release.
again for every package added after a release run — all three were owed for `@ultimat3/scraping` and were done on 2026-08-19; step 1 is the
one that breaks a release.

**Three of the four are scriptable, and this file said otherwise until 2.0.0.** Only step 2's
*reviewer* choice is genuinely a human decision:
Expand All @@ -143,27 +152,43 @@ it breaks it deep into the run, after packages have published irreversibly. **St
`As of 2026-08`: it is a per-package step, and every package added after a release run needs its own
bootstrap before the next one.

### 1. Publish `@ultimat3/scraping` by hand — do this first
### 1. Bootstrap a never-published package by hand — do this first

**`As of 2026-08-19` nothing is owed here**: `@ultimat3/scraping` was bootstrapped and all 30 are on
the registry. This is the procedure for the next package that needs it, which is every package added
after a release run.

```sh
npm login # as an @ultimat3 org member
npm publish -w @ultimat3/scraping --access public --provenance=false
npm publish -w <pkg> --access public --provenance=false
```

Then attach its trusted publisher exactly as in
[the section above](#one-time-configure-the-trusted-publisher-per-package).
**npm reads the credential from an `.npmrc`, not from a bare environment variable.** Setting
`npm_config__authToken` or `NODE_AUTH_TOKEN` alone is not enough: the bootstrap of `scraping`
answered `E404 Not Found - PUT` with a full session token belonging to an org **owner**, which reads
as a permissions problem and is not one. Either `npm login`, or point npm at the variable — never a
literal token in a file:

```sh
printf '//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}\n' > "$HOME/.npmrc"
```

npm interpolates `${NODE_AUTH_TOKEN}` at read time, so the secret stays in the environment. Keep any
`.npmrc` you create out of source control and out of the package — `files` already excludes it, and
a token written literally into one is a credential leak waiting for a `git add`.

**A 404 immediately afterwards is propagation, not failure.** The public packument lagged the
publish by minutes. `npm access list packages @ultimat3` showed the record first, and a retry
answering `E403 … cannot publish over the previously published versions` is the confirmation.

**Why first.** `scraping` has never been on the registry — `npm view @ultimat3/scraping` answers
404, verified `As of 2026-08`. It landed after the 2.0.0 publish run, and the workflow's publish
list is derived, so it is included from the next release on. Trusted publishing cannot bootstrap a
package that does not exist yet, so the workflow will fail on it.
**Why first.** Trusted publishing cannot bootstrap a package that does not exist yet, so a release
run reaches the new package and fails on it.

**Cost of skipping: an irreversible partial release.** The workflow publishes tier by tier and
aborts on the first failure. Measured against the derived list `As of 2026-08`
(`bun run scripts/release-workflow.ts --json`), `scraping` is **27th of 30**, tier 5, between `cli`
and `testing`so **26 packages are already on the registry** at the new version when the run dies,
and npm publishes cannot be undone. You would be recovering by hand, with 26 of 30 packages a
version ahead of the other 4.
aborts on the first failure, so every package ahead of the missing one is already on the registry at
the new version when the run dies, and npm publishes cannot be undone. The ordinal is derived, never
typed out`bun run scripts/release-workflow.ts --json` prints the order, and reading it is the
only way to know the cost. When `scraping` was the hole it was 27th of 30, i.e. 26 published before
the abort.

**A bootstrap cannot carry provenance.** `publishConfig.provenance: true` is on every package, and
npm can only attest from CI — a local publish dies with `EUSAGE — Automatic provenance generation
Expand Down
Loading