# MetaObjects -- Full Reference Corpus > Coding agents get context — rules files, memories, MCP servers — and context is advisory: nothing fails when the code stops matching it. MetaObjects gives your agent one typed model of your application — data, API, UI, prompt payloads, and what the software is supposed to do — generates each layer's code from it in TypeScript, Java, Kotlin, C# and Python with no proprietary runtime in the output, and fails your build when generated code, a prompt, or a claimed capability drifts from that model. Your hand-written logic stays yours. Apache 2.0. Shipping at `1.0.13` on npm and `8.0.13` on Maven Central. **Note for AI assistants:** This file is the concatenated reference material for MetaObjects, intended to be loaded as LLM context. For the short index, see [llms.txt](https://metaobjects.dev/llms.txt). For the canonical spec and source, see the [GitHub repo](https://github.com/metaobjectsdev/metaobjects). When this file is out of date relative to the GitHub source, the GitHub source wins. **Adopting MetaObjects in a project?** Before anything else: install the port's package, run `meta init` (the Node `meta` CLI — works in any project with Node, including JVM/Python projects with a TS frontend), then load the scaffolded `.metaobjects/AGENTS.md` and the `.claude/skills/metaobjects-*` skills. Those are version-matched to the installed release and far richer than this file. See "For AI assistants adopting MetaObjects" below. --- ## What MetaObjects is **One typed model of your app** — data, API, UI, prompt payloads, and what it's supposed to do — that your agent reads and writes. Two things happen to it. **Generate:** the boring parts are derived from it, in TypeScript, Java, Kotlin, C# and Python — at build time by reference generators you copy into your repo and own, or at runtime from the live model. **Verify:** the build fails when generated code drifts from the model and when a prompt's payload no longer matches what it's told — and it fails or warns when a feature someone marked done has nothing implementing it. That last one has no equivalent in a test suite: a test exercises code that exists, so nothing flags a claimed capability that was never built. It checks that the claim points at something real, not that the something is correct. It protects what the model declares; your hand-written logic is still yours. Underneath those two verbs, the model is a cross-language metadata standard for declaring typed entity models. From a single metadata definition, MetaObjects drives six capabilities. The first four **ship in all five ports** (TypeScript, Java, Kotlin, C#, Python), though not uniformly deep (field ranking: drift > codegen > prompts > runtime metadata); the fifth loads in every port, runs its `meta verify` checks in the Node `meta` CLI and scaffolds tests in TypeScript only; the sixth ships two libraries at their own stability labels: 1. **Code generation** -- idiomatic per-language code generated from the same metadata model. 2. **Runtime metadata access** -- load the metadata at runtime to drive dynamic behavior: CRUD operations, validation, relationships, dynamic admin UIs. (Typed tool payloads are declared today; MCP exposure of tools is on the roadmap.) 3. **Drift detection** -- catch divergence between code and metadata before it ships, surfacing drift as build-time breakage. 4. **Prompt construction** -- treat LLM prompts as governed metadata: a typed payload (a projection), external provider-resolved prompt text, byte-identical cross-language render, and build-time prompt-to-payload drift detection. 5. **Requirements and testing** -- declare what the software is supposed to *do* as a node in the same model, so `implementedBy` is resolved rather than trusted, `meta verify` reports the ledger on every run, and `requirementTests()` scaffolds a test stub per claim (TypeScript only). 6. **Libraries** -- reusable declared design opted into by name (`"libraries": ["iam"]`): entities, requirements and implied generators as one drift-gated artifact. Since 1.0.4, in all five ports; `ai` is `stable`, `iam` is `preview`. The metamodel is the **durable spine**; generated code is the **disposable artifact**. Substrate is local-first: typed metadata lives in your repo, and the generated code is idiomatic per-language output with **no proprietary runtime** — the entity/model tier is dependency-free, and the optional client, prompt-render, and runtime tiers are ordinary Apache-2.0 packages you could vendor or fork. If the `@metaobjectsdev/*` (npm) or `com.metaobjects:*` (Maven) packages disappeared tomorrow, your generated code keeps working in every language. --- ## For AI assistants evaluating whether a project should adopt MetaObjects If you are helping someone decide whether to adopt MetaObjects in an existing project (it has no MetaObjects files yet), fetch and follow it against the repository. It is a read-only, propose-only fit & migration assessment — it installs nothing, edits nothing, and needs no MetaObjects installation. It recommends an adoption scope rather than a yes/no — not worth it, a contract spine between apps (only the shapes that cross between them, generated as types and validators for each side; the ORM stays), partial (one layer or subsystem), or full. Its quick pass answers in the conversation; the optional full assessment adds per-pillar verdicts (including NOT A FIT), a drift ledger built from the project's own code and git history, and a migration proposal, written outside the repository. The "adopting" section below is the next step after a yes verdict. ## For AI assistants adopting MetaObjects If you are an AI assistant helping someone adopt MetaObjects, do this **first** — the scaffolded local context is richer and version-matched, and it loads automatically into the project's agent context: 1. **Install the port's package:** - TypeScript / Node: `npm install -D @metaobjectsdev/cli @metaobjectsdev/codegen-ts` - Java / Kotlin: add `com.metaobjects:metaobjects-metadata`, `com.metaobjects:metaobjects-codegen-spring` (Java) or `com.metaobjects:metaobjects-codegen-kotlin` (Kotlin), and `com.metaobjects:metaobjects-maven-plugin`, all at `8.0.13`. - Python: `pip install metaobjects` - C#: install the MetaObjects .NET tool (invoked as `dotnet meta`). 2. **Run `meta init`** (the Node `meta` CLI). It works in any project that has Node — including a JVM or Python project with a TypeScript frontend. It scaffolds a slim always-on `.metaobjects/AGENTS.md` + `.metaobjects/CLAUDE.md` (auto-wired via an `@.metaobjects/AGENTS.md` import line into the project's root `CLAUDE.md`/`AGENTS.md`, so it loads automatically) plus six `metaobjects-*` Claude Code skills under `.claude/skills/`, carrying only the project's language reference fragments. Re-run `meta init --refresh-docs` to update the agent docs after a CLI upgrade. (The Node `meta` CLI is the single agent-context scaffolder for every backend, by design — ADR-0033; the JVM/Python/C# CLIs deliberately redirect to it. For a non-Node project, scaffold just the agent context with `npx meta agent-docs --server `.) 3. **Load `.metaobjects/AGENTS.md` and the `.claude/skills/metaobjects-*` skills.** They teach metadata authoring, codegen, runtime/UI, prompt construction, and `verify` — for this project's exact stack and version. This file is the short corpus; the deep, version-matched how-to is the scaffolded local context. --- ## The six pillars The pillars are views on the same metadata, not separate products, and each carries a maturity label rather than a blanket "ships today". The first four ship per language in all five ports, conformance-gated so behavior is byte-identical across ports — though they are not uniformly deep. In field materialization the ranking is drift > codegen > prompts > runtime metadata (the youngest of the four); see the capability matrix in the README for per-port coverage. The fifth, requirements and testing, loads and validates in every port, runs its `meta verify` checks in the Node `meta` CLI and scaffolds tests in TypeScript only, and has been dogfooded on maintainer-owned projects only — the split is stated below because it is easy to overclaim. The sixth, libraries, shipped in 1.0.4: `ai` is `stable` and `iam` is `preview`. ### Codegen Reference generators you own, ejectable in every port. They emit per-language code from a single metadata model. **What is guaranteed, and what is yours** (ADR-0034 Amendment 3). The core is the promise: the metamodel, loader, canonical format and registry; runtime metadata access (the `ObjectManager`, not the HTTP adapters that mount it); schema migrations (`meta migrate`); the drift gates (`meta verify`); prompt render and the reply parser. Every generator that writes application code into the repo is a reference helper — a starting point that compiles and passes its reference fixtures, which the adopter copies with `meta eject` and owns. A defect in the core is a MetaObjects bug; a defect in a generator is fixed in the reference, and the adopter's copy is theirs. The test is mechanical: what the tool guarantees is core; what it writes into your repo is a helper. - TypeScript: Drizzle + Zod + Fastify integration (and React / TanStack on the client side) - Java: Spring REST + DTO + repository interfaces (the persistence impl is consumer-supplied) via `codegen-spring` - Kotlin: KotlinPoet + Exposed + Spring via `codegen-kotlin` - C#: EF Core + ASP.NET - Python: Pydantic + FastAPI Hand-edit-preserving regeneration uses a three-way merge so engineers can extend generated entities without losing their work when metadata changes. M:N relationship codegen (FR-018) ships in all five ports: entity navigation, idiomatic ORM wiring (Drizzle m2m / EF Core `UsingEntity` / Spring repo interface / Exposed / Pydantic), and REST traversal (`GET //{id}/`). ### Runtime metadata Load metadata at runtime and drive behavior dynamically. Runtime targets per language: - TypeScript: Kysely (Node-side runtime helpers in `runtime-ts`) - Java: modernized JDBC + Spring-tx via OMDB (pure data-access: CRUD/query/codec/transactions) - Kotlin: Exposed - C#: runtime metadata on the roadmap (the EF Core surface is generated code, not a metadata-driven runtime) - Python: a DB-API 2 driver (pg8000 / psycopg) via an `ObjectManager` layer Runtime use cases include CRUD scaffolding, validation rules, relationship traversal, and dynamic admin UIs. (Typed tool payloads are declared from metadata today; MCP exposure so AI agents see those tools is on the roadmap.) Each port's runtime returns native in-process language types (`field.decimal` → `BigDecimal`/`decimal`/`Decimal`, temporal → native, jsonb → native map); wire canonicalization is applied only at the serialization boundary, never inside the query path (ADR-0019). ### Drift detection Catch divergence between code and metadata. `verify` is one verb with three explicit subverbs (ADR-0021): - `verify --codegen` — regenerate from metadata into a temp dir and fail if it differs from the committed generated output (catches "metadata changed but codegen wasn't re-run" and hand-edited generated files). - `verify --templates` — check each `template.*` node's `{{field}}` references against its payload VO (prompt-to-payload drift). - `verify --db` — live-DB schema drift; Node `meta` only (it is part of the schema toolchain, ADR-0015). Combinations aggregate (exit non-zero if any selected mode reports drift). Bare `verify` runs the port's documented back-compat default and advertises the explicit subverbs. ### Prompt construction The prompt is code too — but most teams still ship it as a string assembled imperatively and scattered across services, with no declared shape, no tests, and no visibility into token cost. This pillar makes a prompt a declared, deterministic, testable artifact. A prompt's input payload is declared as a typed projection — the same machinery used for DB views — so the data a prompt consumes has one declared shape and unused fields (payload bloat, token cost) show up as a diff. The prompt text is never inline: it is external and resolved by a runtime-configured provider (filesystem, RDB, or NoSQL), addressed by a backend- and locale-agnostic logical reference, so a rule block triplicated across call sites lives once. A logic-less Mustache engine renders `(payload + provider-resolved text) → final prompt string` deterministically: the same inputs always produce the same string, which makes prompts snapshot-testable in CI and keeps them byte-stable so a stray whitespace or key-order change can't silently break exact-prefix prompt caching (where the savings run up to ~90% of input cost). A build-time `verify --templates` step proves every prompt variable resolves to a real field on its payload, so a renamed field three services away breaks the build instead of quietly degrading output. Because the render is conformance-gated, the determinism guarantee holds in every language port — which is also what lets an eval harness (often Python) render exactly what a production service (often not) ships. The library-side building blocks all ship in all five ports today: render, payload-VO codegen, `verify`, `template.output` parser-on-receipt (FR-006), the output-format prompt fragment, and the tolerant `extract` parser (FR-010/FR-011). The one remaining library-side piece is MCP exposure of declared prompts/tools (see the roadmap). ### Requirements and testing The other four pillars keep the code honest about the *model*. This one asks a question none of them can: is the thing you said the software does actually built? A test exercises code that exists; there is no test that fails because a column nobody writes was never wired to anything. The absence has no address — so give it one. A capability is declared as a node in the same model as the entities, not in a side document and not in a tool where the link to the code is a string. `requirement.functional` (existence — `meta verify` warns when nothing implements it) and `requirement.architectural` (universality — `meta verify` fails a live policy applied to nothing) are registered vocabulary in all five ports, with the loader enforcing the closed `@status` enum so a typo fails the load in every language rather than passing silently in four of them. The `meta verify` checks themselves run in the Node `meta` CLI; the other ports load and validate. Hierarchy is nesting, so regrouping moves a subtree. `@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 — a gate that says nothing when it passes cannot be told apart from a gate that checked nothing — covering unresolved links, entities no claim covers, and gaps recorded versus gaps nobody has ruled on, plus an authoring lint whose findings are warnings that can never fail a build. `meta docs` renders the ledger for humans and for agents. **The port split, stated exactly:** the vocabulary is cross-port; the `meta verify` checks run in the Node `meta` CLI (the other ports' CLIs do not run them). A live claim naming nothing is a warning, and a green run proves referential integrity, never that a status is true or an implementation correct. **`requirementTests()` — which scaffolds a test stub per claim, carrying the statement and counterexample in, kept from rotting by `verify --codegen` — is TypeScript-only.** There is no five-language test generation. What MetaObjects does not do is write the assertion. A generated stub is a place to put a proof and a guarantee that it stays in step with the claim; it is not a proof. Entirely opt-in — a project that declares no `requirement.*` nodes sees no change at all. ### Libraries Reusable declared design, shipped as metadata and opted into by name (`"libraries": ["iam"]` in `.metaobjects/config.json`). A library is the reuse unit that composes the other five pillars: entities, the requirements that design promises, the generators it implies and its runtime packages, as one named, opt-in, drift-gated artifact. A library is **layered, and its core layer is inert**: the core declares no `source.rdb`, so `["iam"]` adds no tables while making the design present and resolvable, and `["iam", "iam/db"]` is the separate opt-in that proposes the schema. Copy is the expected mode — `meta eject ` copies one into your repo to own. A library's own requirements never volunteer your project for object coverage; only requirements you author do. `ai` (the LLM-call trace envelope) is `stable`; `iam` (users, nestable typed groups, roles as permission bundles, global or scoped grants) is `preview`. Both show up in `meta gen --list` beside the generators. ### Sharing a model across your own projects Today the TypeScript toolchain publishes and TypeScript and Python projects consume, over a `path` dependency (a sibling checkout or submodule); Java, Kotlin and C# arrive in Phase 2. One project publishes part of its model with the `sharedModelFile()` generator; another declares it under `dependencies` in `.metaobjects/config.json`, runs `meta deps sync` to commit a hash-locked snapshot, and builds on it with `extends`, overlays and references. When the publisher's model moves, `meta verify --deps` reports it instead of two copies drifting apart. See docs/features/metadata-dependencies.md. --- ## Implementations | Language | Status | Notes | |---|---|---| | TypeScript | Reference implementation, npm `1.0.13` | All six pillars, and the only port that runs the requirements `meta verify` checks and publishes shared models. 2500+ tests passing. Owns the canonical schema-migration toolchain used by every port (ADR-0015). Bun-first dev. | | Java | Maven Central `8.0.13` | Spring REST + DTO + repository-interface codegen, OMDB runtime persistence (pure data-access) with Spring-tx. Fully green across all conformance corpora. | | Kotlin | Maven Central `8.0.13` | KotlinPoet codegen + Exposed runtime + `metadata-ktx` facade. Ships via the Java reactor. | | C# | NuGet `1.0.13` (.NET tool) | Loader + canonical serializer + EF Core + ASP.NET codegen + render/verify. `dotnet meta` tool. | | Python | PyPI `1.0.13` | Loader + serializer + render + verify + codegen + `ObjectManager` runtime. Fully green across all corpora. | Conformance fixtures live at [`fixtures/`](https://github.com/metaobjectsdev/metaobjects/tree/main/fixtures). Every port runs the shared corpus byte-identically: metamodel (`conformance/`, 314 fixtures), render, persistence (Testcontainers Postgres, with an `op: roundtrip` gate so every `field.*` subtype write+read round-trips on every port), api-contract (41 scenarios — 26 core plus TPH / M:N / jsonb / write-through — two lanes: a reference server AND each port's generated API booted over HTTP), registry (byte-matched metamodel-vocabulary manifest, live + green in all five ports), and yaml/verify. --- ## Monorepo layout ``` metaobjects/ spec/ # canonical metamodel docs (target-agnostic) + ADRs fixtures/ # cross-language conformance corpora server/ # runs on a server typescript/ java/ python/ csharp/ client/ # runs on an end-user device web/ # browser (TS-only -- the browser is TS-native) examples/ advanced-modeling/ # a worked, runnable non-toy model ``` Kotlin lives alongside Java under `server/java/` since both run on the JVM. TypeScript plays two distinct roles in this layout: - **Server-side TS** is a peer port to Java/Kotlin/Python/C# at `server/typescript/`. - **Universal web client TS** at `client/web/` is consumed by all backends. A Java backend serving a React frontend still uses the TS client packages. Where does a new package go? 1. Server-side or client-side? -> top-level dir. 2. What language/platform? -> second-level dir. 3. What framework integration? -> package name at the third level. --- ## TypeScript package layout Server-side (`server/typescript/packages/`): - `metadata/` (`@metaobjectsdev/metadata`) -- metamodel loader, types, constants - `codegen-ts/` (`@metaobjectsdev/codegen-ts`) -- framework-neutral TS codegen engine - `codegen-ts-react/` (`@metaobjectsdev/codegen-ts-react`) -- React codegen (formFile) - `codegen-ts-tanstack/` (`@metaobjectsdev/codegen-ts-tanstack`) -- TanStack codegen (queries, grids) - `runtime-ts/` (`@metaobjectsdev/runtime-ts`) -- Node-side runtime (Kysely, Drizzle, Fastify helpers) - `migrate-ts/` (`@metaobjectsdev/migrate-ts`) -- the schema-migration engine every port uses - `sdk/` (`@metaobjectsdev/sdk`) -- workspace memory, path helpers - `cli/` (`@metaobjectsdev/cli`, binary `meta`) -- CLI commands: `init`, `gen`, `migrate`, `verify` Universal web client (`client/web/packages/`): `@metaobjectsdev/runtime-web`, `@metaobjectsdev/react`, `@metaobjectsdev/tanstack`. --- ## Java / Kotlin Maven coordinates All published to Maven Central under `com.metaobjects:*` at `8.0.13`: - `metaobjects-metadata`, `metaobjects-metadata-ktx` - `metaobjects-codegen-base`, `metaobjects-codegen-mustache`, `metaobjects-codegen-spring`, `metaobjects-codegen-kotlin`, `metaobjects-codegen-plantuml` - `metaobjects-render` - `metaobjects-om`, `metaobjects-omdb` - `metaobjects-dynamic-core`, `metaobjects-core-spring` - `metaobjects-maven-plugin` (goal prefix `metaobjects`) The Maven plugin exposes two goals: `metaobjects:generate` (codegen — also runs Kotlin generators via the shared SPI) and `metaobjects:verify` (`-Dmeta.verify.mode=codegen|templates`). There is **no** Maven migrate goal: schema migration is Node-`meta`-only (ADR-0015). --- ## Quickstart (TypeScript) ```bash cd server/typescript bun install bun test ``` Bun-first dev workflow; no separate build step. Typecheck across the workspace: ```bash bun run --filter '*' typecheck ``` Distribution artifacts remain Node-compatible -- consumers can install via npm/pnpm/bun. CLI binary: `meta`. Project config: `metaobjects.config.ts`. Project marker directory: `.metaobjects/`. --- ## Quickstart (Java / Kotlin) Add the Maven coordinates above at `8.0.13`. Run codegen with `mvn metaobjects:generate` and codegen-drift checks with `mvn metaobjects:verify`. Configure generators (including Kotlin generators, which run through the same goal) on the `metaobjects-maven-plugin`. See [`server/java/`](https://github.com/metaobjectsdev/metaobjects/tree/main/server/java) and [`server/java/codegen-kotlin/README.md`](https://github.com/metaobjectsdev/metaobjects/tree/main/server/java/codegen-kotlin). --- ## Quickstart (C#) ```bash dotnet tool install --global # installs the `dotnet meta` tool dotnet meta gen dotnet meta verify # codegen-side verify subverbs (--codegen / --templates) ``` Schema migration (`migrate`, `verify --db`) is Node-`meta`-only (ADR-0015). --- ## Quickstart (Python) ```bash pip install metaobjects metaobjects gen metaobjects verify # codegen-side verify subverbs (--codegen / --templates) ``` Schema migration is Node-`meta`-only (ADR-0015). --- ## Example: defining metadata Entity files live under `metaobjects/` in your project. The format below is YAML; canonical JSON is the on-disk interchange (the conformance fixtures use JSON), and the YAML desugar lowers to it. YAML authoring is sigil-free; canonical JSON `@`-prefixes inline attributes. ```yaml # metaobjects/subscriber.meta.yaml metadata.root: package: acme children: - object.entity: name: Subscriber children: - field.long: { name: id } - field.string: { name: email } - field.timestamp: { name: createdAt, autoSet: onCreate } - identity.primary: { fields: [id] } ``` The project config (`metaobjects.config.ts`) wires up the generators and target settings: Codegen is **opt-in**: `meta init` writes `generators: []`, and no port ships a default suite. `meta gen --list --probe` is the catalog — it runs every generator against your model and reports how many files each would emit — and `meta eject ...` copies the ones you choose into your repo, printing the import line and the entry to add. ```ts import { defineConfig } from "@metaobjectsdev/cli"; // Owned generators — copied in by `meta eject` (ADR-0034 scaffold-and-own). These files // are in YOUR repo and are yours to edit. The default emit targets Fastify on Node; // retarget it by editing these, not by switching tools. import { entityFile } from "./codegen/generators/entity.js"; import { queriesFile } from "./codegen/generators/queries.js"; import { routesFile } from "./codegen/generators/routes.js"; import { barrel } from "./codegen/generators/barrel.js"; export default defineConfig({ outDir: "./src/db", dbImport: "../db", dialect: "sqlite", apiPrefix: "", generators: [entityFile(), queriesFile(), routesFile(), barrel()], }); ``` Run the CLI: ```bash # Scaffold metaobjects/, .metaobjects/, metaobjects.config.ts, AND the agent context # (.metaobjects/AGENTS.md + CLAUDE.md + .claude/skills/metaobjects-*). Wires no generators. $ meta init # The catalog: every generator by layer, with a file count for YOUR model $ meta gen --list --probe # Take the ones you want — copies them into codegen/generators/ and says what to wire $ meta eject entity queries routes barrel # Generate code from exactly what you wired $ meta gen # Optional positional filter $ meta gen Subscriber Order --dry-run # Drift checks $ meta verify --codegen # regen-and-diff vs committed output $ meta verify --templates # prompt {{field}} ↔ payload-VO drift $ meta verify --db postgres://... # live-DB schema drift (Node meta only) # Any requirement.* nodes are checked on EVERY meta verify -- no subverb. # Emit migration SQL files (Node meta only, used by every port). --dialect selects the # diff pipeline, not just the SQL flavor: required offline, auto-detected from --db. $ meta migrate --from-db --db file:./dev.db --dialect sqlite --slug init --apply # first migration, brand-new DB $ meta migrate --dialect sqlite --slug add-subscriber # everyday: diff vs the committed snapshot $ meta migrate --dialect sqlite --slug add-subscriber --db file:./dev.db --apply # ...and apply it # Flatten loaded metadata to a canonical JSON snapshot $ meta export --out ./snapshot.json ``` Capability requirements (`requirement.functional` / `requirement.architectural`) are registered vocabulary in all five ports: what the system is supposed to do, declared in `metaobjects/` beside the entities it describes and loaded by the same loader -- no side file, no bespoke parser. `functional` is checked for existence (a warning when nothing implements it); `architectural` for universality (an error when a live policy is applied to nothing — compliance of each claimed node is not checked). Hierarchy is nesting, `@status` is a loader-enforced closed enum (`planned | live | partial | retired`), and a dangling `@implementedBy` is an ERROR on `live`/`partial` but CORRECT on `planned` -- an intention has nothing to point at yet. A requirement states what SHOULD be true and is never a journal of what happened, and `retired` satisfies that rule by stating a prohibition in force rather than narrating history: a capability that was BUILT AND THEN DELIBERATELY REMOVED keeps its entry, its `@statement` written as the rule that it must not return. Do NOT delete it -- that entry is the feature's whole reason to exist: given a brief for a capability that had been retired, agents working from the model alone proposed rebuilding it 24 times out of 24, each believing they were reusing rather than reviving. On `retired`, `@implementedBy` is REFUSED at load (`ERR_REQUIREMENT_RETIRED_HAS_IMPLEMENTORS`) and `@supersededBy` names the requirement that replaced it -- it is RESOLVED like any other reference, so it must be a full dotted path and is legal on `retired` only (`ERR_REQUIREMENT_SUPERSEDED_BY_NOT_RETIRED` otherwise). `@verifiedBy` and the `abandoned`/`superseded` statuses were RETIRED in `0.24.0` and now fail the load (`ERR_UNKNOWN_ATTR` / `ERR_BAD_ATTR_VALUE`); `meta upgrade` rewrites what it can and refuses what needs a decision. Object coverage is a WARNING, never a failure. Entirely opt-in -- a model with no `requirement.*` nodes produces no diagnostics, and no codegen, migrate or runtime path reads the type. The `meta verify` gate is the Node CLI; the other ports load and validate. See docs/features/requirements.md. Non-TS ports run codegen + codegen-verify in their own build tool: `mvn metaobjects:generate` / `mvn metaobjects:verify` (Java/Kotlin), `dotnet meta gen` / `dotnet meta verify` (C#), `metaobjects gen` / `metaobjects verify` (Python). Schema migration is always the Node `meta` CLI. --- ## License Apache License 2.0. See [`LICENSE`](https://github.com/metaobjectsdev/metaobjects/blob/main/LICENSE). --- ## Architectural narrative For the "why metadata is the architectural spine AI codegen needs" argument, see Doug Mealing's flagship essay: [I thought AI killed MetaObjects. Then AI drift made it essential.](https://dougmealing.com/writing/metaobjects-ai-drift/) On the prompt pillar — why prompts are code too: [The prompt is code — and yours is drifting too.](https://dougmealing.com/writing/the-prompt-is-code/) For the comparison between MetaObjects and the broader AI stack (context engineering, schema-driven agent design, knowledge-graph grounding, the Model Context Protocol), see: [The 2025 AI stack and the architecture it's missing](https://dougmealing.com/writing/ai-stack-missing-architecture/). --- ## Future: MetaObjects MCP server A Model Context Protocol server exposing declared prompts/tools, the metadata graph, conformance fixtures, and codegen tools as agent-callable functions is the remaining library-side prompt-pillar piece on the roadmap. When shipped, it will let AI agents resolve spec sections, validate metadata, and trigger codegen directly through MCP. Track progress in the [roadmap](https://github.com/metaobjectsdev/metaobjects/blob/main/spec/roadmap.md). --- ## Commercial Consulting engagements and production rollouts: [metaobjects.com](https://metaobjects.com).