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
55 changes: 21 additions & 34 deletions .claude/skills/releasing/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: releasing
description: Use when cutting or publishing a release of the @metaobjectsdev npm/TypeScript packages — e.g. "do a release", "release 0.x.y", bumping the published npm version, promoting merged work to npm latest, or refreshing version references after a release.
disable-model-invocation: true
---

# Releasing the npm/TypeScript packages
Expand Down Expand Up @@ -40,6 +41,15 @@ Do not bump or publish anything until every check is green. Print each result.
| **Target version is free** | `npm view @metaobjectsdev/cli@<version> version` (a 404 = free); `git tag -l v<version>` | the target version is NOT already published or tagged (npm versions are permanent — a taken version can never be reused) |
| CHANGELOG ready | `sed -n '1,20p' CHANGELOG.md` | an entry exists or you will add one (see Phase 8) |
| **`metamodelVersion` moved if the metamodel did** | `node scripts/check-metamodel-version.mjs` | exit 0. It diffs `expected-registry.json` against the last release tag and fails if the vocabulary changed without the version moving. Read its PROSE warning too — a rule can change with no machine-readable footprint (#210 changed only a `rules` string). Fix with `--set <version>`; detail with `--explain`. |
| **You CAN publish** | `npm whoami` | prints your username (see the note under this table) |

**Check that you CAN publish.** `scripts/release.mjs` runs `npm whoami` in preflight; do the same
by hand if you are publishing manually, and use an **Automation / bypass-2FA** token. A "Publish"
token passes `whoami`, shows `read-write`, passes `--dry-run`, and then `EOTP`s on every write,
at which point `bun publish` falls back to a browser flow that cannot complete non-interactively
(`--otp=` is ignored; a code must be piped on stdin). Verify BEFORE the version bump: the bump is
committed and pushed well before the first publish, so a dead credential strands the cut with
other registries already shipped. See `docs/RELEASING.md` → Prerequisites.

If the code-review check fails (no PR, or unmerged/dirty tree): **stop** — releases
ship reviewed, merged `main`, never a working tree.
Expand Down Expand Up @@ -162,12 +172,9 @@ Add the `CHANGELOG.md` entry (Keep-a-Changelog format) if not already committed.

`npm deprecate <pkg>@<version>-rc.1 "superseded; use <version>"` for each package.

Retire the RC's `next` tag by **repointing, not deleting**: `npm dist-tag rm` 403s for every
token we hold (local and CI both — npm's bypass-2FA package-access rule, not a missing OTP).
The Actions → **npm dist-tag** dispatch that repointed the whole lockstep set from the
publish token **cannot run — GitHub Actions is disabled on this repository (2026-09-16),
and the replacement path is being decided**. Repoint per package from your machine instead:
`npm dist-tag add <pkg>@<version> next` (`add` is not restricted). See `docs/RELEASING.md` §4.
Retire the RC's `next` tag by **repointing, not deleting**: `npm dist-tag rm` is refused
for every token we hold. Repoint per package with `npm dist-tag add <pkg>@<version> next`,
or dispatch the npm dist-tag workflow for the whole set. See `docs/RELEASING.md` §4.

## Phase 10 — Propagate versions (docs + websites)

Expand Down Expand Up @@ -211,24 +218,14 @@ version FAILS by design — skip what's done, never force.
- About to `bun publish` to `latest` without human confirmation → stop.
- About to push the site repo without confirming the live deploy → stop.

## OIDC Trusted Publishing — now DATED, not optional
npm removes **direct publishing from 2FA-bypass tokens around January 2027**
([changelog](https://github.blog/changelog/2026-07-31-restricting-npm-bypass-2fa-granular-access-tokens/));
since 2026-07-31 such tokens already cannot change package access — including
**deleting a dist-tag**. Measured 2026-09-10: the local token and the CI `NPM_TOKEN`
both 403 on `DELETE …/dist-tags/next` and `--otp` changes neither, so this is a grant
boundary and no OTP session was going to clear it. Phase 9 repoints with `dist-tag add`
instead, which is not restricted. The replacement is **OIDC Trusted Publishing** via
`publish-npm.yml` (which exists — inoperative while GitHub Actions is disabled on this
repository, 2026-09-16), the same mechanism `publish-csharp.yml` already
uses for NuGet; the remaining work is a trusted-publisher registration per package
on npmjs.com. Caveat: OIDC can't drive `npm dist-tag` yet, so RC→promote still needs
a token.

Separately, and still genuinely optional: **Changesets** (per-PR intent files → a
reviewable "Version Packages" PR → automated bump + CHANGELOG). Adopting it would
replace Phases 1/3/7's manual steps; the preflight gate, smoke test, and
stop-and-confirm in this skill stay.
## npm credentials and Trusted Publishing
The npm token type, the read-only auth preflight, and the dated plan to move publishing to
OIDC Trusted Publishing are in `docs/RELEASING.md` → Prerequisites. Read them before the
first publish of a cut.

Separately, and optional: **Changesets** (per-PR intent files → a reviewable "Version
Packages" PR → automated bump + CHANGELOG). Adopting it would replace Phases 1/3/7's manual
steps; the preflight gate, smoke test, and stop-and-confirm in this skill stay.

## Verify with the committed script, not ad-hoc shell
`node scripts/release-verify.mjs [--preflight] [<version>] [--smoke]` is the one place
Expand All @@ -238,13 +235,3 @@ instead of improvising checks per release: the 0.24.0 cut was verified by a doze
throwaway scripts, and the improvised auth check was a **write** against a published
package that could not be undone. **Never probe credentials by mutating a published
package.** It is read-only; extend it there when a release needs a check it lacks.

## Phase 0 addendum — check that you CAN publish
`scripts/release.mjs` now runs `npm whoami` in preflight. Do the same by hand if you
are publishing manually, and use an **Automation / bypass-2FA** token: a "Publish"
token passes `whoami`, shows `read-write`, passes `--dry-run`, and then `EOTP`s on
every write, at which point `bun publish` falls back to a browser flow that cannot
complete non-interactively (`--otp=` is ignored; a code must be piped on stdin).
Verify BEFORE the version bump — the bump is committed and pushed well before the
first publish, so a dead credential strands the cut with other registries already
shipped. See `docs/RELEASING.md` → Prerequisites.
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The first four ship per-language today across the five ports (TS / C# / Java / P
2. **Runtime metadata** — load metadata at runtime, drive behavior dynamically (CRUD, validation, relationships, dynamic admin UIs, LLM tool registration). On Kysely (TS), a DB-API 2 driver via ObjectManager (Python), modernized JDBC + Spring-tx via OMDB (Java), Exposed (Kotlin). **C# runtime metadata is on the roadmap** — its EF Core output is generated code, not a metadata-driven runtime; the runtime `MetaObjects` package depends only on YamlDotNet and ships no data access.
3. **Drift detection** — `meta verify` catches divergence between code and metadata (covers entity codegen, prompt templates, output parsers, schema). Quality-of-life on top of codegen + runtime.
4. **Prompt construction** — a prompt is code, not a string scattered across services. Declare a prompt's payload as a typed projection (payload bloat becomes a diff), keep its text external and provider-resolved, and render it deterministically: snapshot-testable, cache-stable (no whitespace change silently breaking exact-prefix prompt-cache hits), and drift-checked at build time so a renamed field can't degrade a prompt. Conformance-gated, so the guarantee holds in every language port. **Render + payload-VO codegen + `verify` + parser-on-receipt for a *responding* `template.prompt` — one carrying `@responseRef` (FR-006) — + the output-format prompt fragment & tolerant `extract` parser (FR-010) ship in all five ports today** (since 0.24.0 the whole inbound tier keys off `@responseRef`; a `template.output` is outbound-only and emits no parser — ADR-0052) — the library-side building blocks of the pillar are complete. The one remaining library-side piece is MCP exposure of declared prompts/tools (see `spec/roadmap.md`); the application-level consolidation (eval harness, end-to-end declared-prompt orchestration) and consumer adoption are exercised in adopter projects, not in this library repo. Designed in `docs/superpowers/specs/2026-05-22-fr-004-cross-language-prompt-construction-design.md`.
5. **Requirements and testing** — declare what the software is supposed to *do* in the same model as the entities, so a capability claim is checkable instead of prose. The other four pillars keep the code honest about the *model*; this one asks whether the thing you said the software does is actually built — an absence no test can fail on, because a test exercises code that exists. `requirement.functional` (existence: `meta verify` WARNS when nothing implements it) and `requirement.architectural` (universality: `meta verify` FAILS a live policy applied to nothing, and does not check that each claimed node complies) are registered vocabulary in all five ports, with the loader enforcing the closed `@status` enum. `@implementedBy` is **resolved, not trusted** — it names a real member of the real model, so a claim whose implementation was renamed or deleted fails the build instead of going quietly stale. `meta verify` reports the ledger on every run (unresolved links, entities no claim covers, gaps recorded versus gaps nobody has ruled on) plus an authoring lint whose findings can never fail a build; `meta docs` renders it for humans and for agents. **The port split, stated exactly: the vocabulary loads and validates in all five ports; the requirement gate runs in every port's `verify` (ADR-0057 — `docs/CONFORMANCE.md` "Split coverage"); every port ships an ejectable `requirement-tests` generator — which scaffolds a test per claim; the seven authoring-lint advisories are TypeScript-only.** A green run proves referential integrity, never that a status is true or an implementation correct (`docs/features/requirements.md`, "What a green run does not prove"). A project that declares no `requirement.*` nodes sees no change at all. Note the standing carve-out: `agent-context/skills/metaobjects-fit-assessment/SKILL.md` deliberately does NOT treat `requirement.*` as an assessment axis — see the ruling in that file before "finishing the job" there.
5. **Requirements and testing** — declare what the software is supposed to *do* in the same model as the entities, so a capability claim is checkable instead of prose. The other four pillars keep the code honest about the *model*; this one asks whether the thing you said the software does is actually built — an absence no test can fail on, because a test exercises code that exists. `requirement.functional` (existence: `meta verify` WARNS when nothing implements it) and `requirement.architectural` (universality: `meta verify` FAILS a live policy applied to nothing, and does not check that each claimed node complies) are registered vocabulary in all five ports, with the loader enforcing the closed `@status` enum. `@implementedBy` is **resolved, not trusted** — it names a real member of the real model, so a claim whose implementation was renamed or deleted fails the build instead of going quietly stale. `meta verify` reports the ledger on every run (unresolved links, entities no claim covers, gaps recorded versus gaps nobody has ruled on) plus an authoring lint whose findings can never fail a build; `meta docs` renders it for humans and for agents. **The port split, stated exactly: the vocabulary loads and validates in all five ports; the requirement gate runs in every port's `verify` (ADR-0057 — `docs/CONFORMANCE.md` "Split coverage"); every port ships an ejectable `requirement-tests` generator — which scaffolds a test per claim; the seven authoring-lint advisories are TypeScript-only.** A green run proves referential integrity, never that a status is true or an implementation correct (`docs/features/requirements.md`, "What a green run does not prove"). A project that declares no `requirement.*` nodes sees no change at all. Note the standing carve-out: `agent-context/skills/metaobjects-fit-assessment/SKILL.md` deliberately does NOT treat `requirement.*` as an assessment axis — the ruling is in `docs/superpowers/specs/2026-07-12-metaobjects-fit-assessment-maintainer-notes.md`; read it before "finishing the job" there.

6. **Libraries** — reusable declared design, shipped as metadata and opted into by name (`"libraries": ["iam"]` in `.metaobjects/config.json`). Not a sixth verb: a library is the **reuse unit that composes the other five** — entities, requirements, the generators its design implies, its runtime packages — as one named, opt-in, drift-gated artifact. What makes it a pillar rather than a folder of YAML is the fifth: without requirements a library is a schema snippet; with them it is design an adopter's build is held to, which is the same test the requirements pillar passes (*does it change what an agent can be checked against?*). **A library is LAYERED and its core layer is INERT** — the core declares no `source.rdb`, and a sourceless object generates nothing and migrates to nothing (#248), so `["iam"]` adds zero tables and zero generated code while making the design present and resolvable; `["iam", "iam/db"]` is the separate opt-in that proposes the schema. **Copy is the expected mode** (`meta eject <library>` — ADR-0034's ruling applied to metadata), and an ejected copy still named in `libraries` is refused at load (`ERR_LIBRARY_PACKAGE_COLLISION`) rather than merging asymmetrically. Object coverage activates on ADOPTER-authored requirements only, so a library cannot volunteer a project for a gate it did not ask for. `iam` (preview) and `ai` (stable) ship today; rows appear in `meta gen --list` beside the generators. See [docs/features/libraries.md](docs/features/libraries.md) and `docs/superpowers/specs/2026-09-13-fr-043-feature-and-nfr-packages-design.md`.

Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,21 @@ until you regenerate.

One rule is relaxed: an authored `validator.length @min: 0` on a `@required` string now
admits the empty string, as the generated schema already did.
- **The shipped agent skills fit the skill-authoring limits.** `metaobjects-audit` (601 lines to
263), `metaobjects-authoring` (804 to 479) and `metaobjects-fit-assessment` (666 to 481) moved
sections into `references/` files, each with a row and an "open it when" condition in the
skill's reference table, which now sits at the top of `metaobjects-audit`,
`metaobjects-prompts` and `metaobjects-runtime-ui` as well. The text moved and none was cut; `meta init`
and `meta init --refresh-docs` write the new files into `.claude/skills/`. Every reference
file over 100 lines opens with a `## Contents` list, and `metaobjects-codegen` links its five
TypeScript topic files and every language file from `SKILL.md`. A test in the SDK holds all
three rules.
- **The hosted fit-assessment prompt is built, not copied.** The capability sheet and the JSON
contract left `SKILL.md`, so `node scripts/build-assess-prompt.mjs --out <file>` writes the
single-file form served at `metaobjects.dev/assess.md`, inlining both. The output is the old
prompt, apart from one dropped phrase ("in this file"). Its maintainer notes moved to
`docs/superpowers/specs/2026-07-12-metaobjects-fit-assessment-maintainer-notes.md`, and the
skill's `scaffold: false` marker is now `metadata: { scaffold: false }` (no code reads it).

### Deprecated

Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ If your agent can't fetch URLs (or you want it to follow the prompt verbatim), s
the file into your workspace instead — `curl -fsSL https://metaobjects.dev/assess.md
-o metaobjects-assess.md` (don't commit it) — and say: *"Read
`metaobjects-assess.md` and run the assessment it contains against this
repository."* The prompt is one Markdown file
([source](agent-context/skills/metaobjects-fit-assessment/SKILL.md)); read it first
if you like — you should never point your agent at a prompt you haven't vetted.
repository."* The file is built from the
[skill](agent-context/skills/metaobjects-fit-assessment/SKILL.md) and its
`references/` by [`scripts/build-assess-prompt.mjs`](scripts/build-assess-prompt.mjs);
read it first if you like — you should never point your agent at a prompt you haven't vetted.

The catch, stated plainly: it runs in **your** agent on **your** tokens. The quick
pass takes roughly 5–30 minutes of agent time, depending on the agent and the
Expand Down
2 changes: 1 addition & 1 deletion agent-context/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The **scaffolded** set is exactly the six skills in the SDK's `SKILL_NAMES`
additionally holds **`metaobjects-fit-assessment`**, a *pre-adoption* tool that is
deliberately **not** in `SKILL_NAMES` and so is never scaffolded (a not-yet-adopted
target has no `.claude/skills/metaobjects-*` to receive it); it carries
`scaffold: false` in its front-matter as the human marker. Its design + retro-test
`scaffold: false` under `metadata:` in its front-matter as the human marker (no code reads it). Its design + retro-test
validation live in `docs/superpowers/specs/2026-07-12-metaobjects-fit-assessment-design.md`.

Design: `docs/superpowers/specs/2026-06-02-downstream-agent-context-design.md`.
Loading
Loading