# MetaObjects > 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. **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. **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 — conformance-gated and the same in every port that ships it. Every generator that writes application code into the repo (routes, controllers, ORM wiring, DTOs, forms, grids, hooks) 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. Every port can eject: `meta eject` (TypeScript), `metaobjects eject` (Python), `mvn metaobjects:eject` (Java/Kotlin), `dotnet meta eject` (C#). The metamodel is the durable spine; generated code is the disposable artifact. Substrate is local-first: typed metadata lives in your repo as YAML or JSON you own, and the generated code carries **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 `@metaobjectsdev/*` (npm) or `com.metaobjects:*` (Maven) disappears tomorrow, you keep working code 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, 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 in their project, do this **first** — the scaffolded local context is far richer and version-matched than this index: 1. **Install the port's package** for the project's stack: - **TypeScript / Node**: `npm install -D @metaobjectsdev/cli @metaobjectsdev/codegen-ts` - **Java / Kotlin**: add the Maven dependencies `com.metaobjects:metaobjects-metadata`, `com.metaobjects:metaobjects-codegen-spring` (Java) or `com.metaobjects:metaobjects-codegen-kotlin` (Kotlin), and the `com.metaobjects:metaobjects-maven-plugin`, all at `8.0.13`. - **Python**: `pip install metaobjects` - **C#**: install the MetaObjects .NET tool (`dotnet tool install` the MetaObjects CLI 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 that happens to have a TypeScript frontend. It scaffolds, into the project: - a slim always-on `.metaobjects/AGENTS.md` + `.metaobjects/CLAUDE.md` agent context, **auto-wired into the project's root `CLAUDE.md`/`AGENTS.md`** (an `@.metaobjects/AGENTS.md` import line) so it loads automatically; and - six `metaobjects-*` Claude Code skills under `.claude/skills/`, carrying only the language reference fragments for the project's stack. Re-run `meta init --refresh-docs` to update the scaffolded 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. Run `meta init` regardless of backend language, or `npx meta agent-docs --server ` to scaffold just the agent context.) 3. **After scaffolding, 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 `llms.txt` is the short index; the deep, version-matched how-to is the scaffolded local context. ## Spec and standard - [Specification (canonical, target-agnostic)](https://github.com/metaobjectsdev/metaobjects/tree/main/spec): the normative metadata schema and semantics that every implementation must conform to. - [Conformance fixtures](https://github.com/metaobjectsdev/metaobjects/tree/main/fixtures): cross-port corpora — `conformance/` (metamodel, 314 fixtures), `render-conformance/`, `persistence-conformance/` (against Testcontainers Postgres, including an `op: roundtrip` gate so every `field.*` subtype write+read round-trips on every port), `api-contract-conformance/` (41 scenarios — 26 core REST contract + filter operators, plus TPH / M:N / jsonb / write-through — run in two lanes: a reference server AND each port's generated API booted over HTTP), `registry-conformance/` (byte-matched metamodel-vocabulary manifest, live + green in all five ports), and `yaml-conformance/` / `verify-conformance/`. Every port runs the shared corpus byte-identically. - [Roadmap](https://github.com/metaobjectsdev/metaobjects/issues?q=is%3Aissue+label%3AFR): current + planned work, tracked as GitHub issues labelled `FR` with milestones per release; [spec/roadmap.md](https://github.com/metaobjectsdev/metaobjects/blob/main/spec/roadmap.md) holds the direction and the index of feature specs. ## The six pillars MetaObjects pillars are capabilities of the same metadata spine, not separate products. Each carries a maturity label — what ships, in which ports, at what stability: - **Codegen, Runtime metadata, Drift detection, Prompt construction** — shipped in all five ports (TS / Java / Kotlin / C# / Python), gated by the cross-port conformance corpora, though not uniformly deep: see the [capability matrix](https://github.com/metaobjectsdev/metaobjects#capability-matrix) for per-port coverage, and note the field ranking is drift > codegen > prompts > runtime metadata (the youngest of the four). - **Requirements and testing** — vocabulary loads and validates in all five ports; the `meta verify` checks run in the Node `meta` CLI; `requirementTests()` scaffolding is TypeScript-only; dogfooded on maintainer-owned projects, no outside adopter yet. - **Libraries** — since 1.0.4, in all five ports: `ai` is `stable`, `iam` is `preview` (the same labels `meta gen --list` prints). - **Codegen** — reference generators you own (ejectable in every port) that emit per-language code from a single metadata model. Drizzle + Zod + Fastify (TypeScript), Spring REST + DTO + repository interfaces (the persistence impl is consumer-supplied) (Java via `codegen-spring`), KotlinPoet + Exposed + Spring (Kotlin via `codegen-kotlin`), EF Core + ASP.NET (C#), Pydantic + FastAPI (Python). Hand-edit-preserving regeneration via three-way merge. Includes M:N relationship codegen (FR-018) in all five ports — entity navigation, idiomatic ORM wiring, and REST traversal (`GET //{id}/`). - **Runtime metadata** — load metadata at runtime and drive behavior dynamically: CRUD, validation, relationships, dynamic admin UIs. (Typed tool payloads are declared today; MCP exposure of tools is on the roadmap.) Kysely (TS), a DB-API 2 driver (pg8000 / psycopg) 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). Runtime queries return native in-process types (ADR-0019); wire canonicalization happens only at the serialization boundary. - **Drift detection** — catch divergence between generated code and metadata before it ships. `verify` is one verb with explicit subverbs (ADR-0021): `verify --codegen` (regen-and-diff against committed output), `verify --templates` (prompt `{{field}}` ↔ payload-VO drift), and `verify --db` (live-DB schema drift, Node `meta` only). Surfaces drift as build-time breakage rather than a production incident. - **Prompt construction** — treat LLM prompts as governed metadata instead of strings scattered across services. A typed payload declared as a projection (so payload bloat and token cost are a diff, not a mystery), external provider-resolved prompt text, and a logic-less Mustache engine that renders deterministically: snapshot-testable in CI, byte-stable so an exact-prefix prompt-cache hit doesn't break on a stray whitespace, and drift-checked at build time so a renamed field can't silently degrade a prompt. Conformance-gated, so the guarantee holds in every language port. Render + payload-VO codegen + `verify` + `template.output` parser-on-receipt (FR-006) + the output-format prompt fragment & tolerant `extract` parser (FR-010/FR-011) ship in all five ports today. - **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. `requirement.functional` / `requirement.architectural` are registered vocabulary in all five ports, with the loader enforcing the closed `@status` enum, and `@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 rather than 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 — and lints the authoring; `meta docs` renders it for humans and for agents. A live claim naming nothing is a warning; a green run proves the references resolve, never that an implementation is correct. **`requirementTests()`, which scaffolds a test stub per claim carrying the statement and counterexample in, is TypeScript-only**; the vocabulary loads in every port, and the `meta verify` checks run in the Node `meta` CLI. A project that declares no `requirement.*` nodes sees no change at all. - **Libraries** — reusable declared design you opt into by name (`"libraries": ["iam"]` in `.metaobjects/config.json`): entities, the requirements they promise and the generators they imply, as one drift-gated artifact. A library is layered and its core layer is inert: it declares no source, so it adds no tables until you also opt into its `/db` layer (`["iam", "iam/db"]`). `meta eject ` copies one into your repo to own. `ai` (the LLM-call trace envelope) is `stable`; `iam` (users, nestable groups, roles, grants) is `preview`. **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` and references. When the publisher's model moves, `meta verify --deps` reports it instead of two copies drifting apart. ## Implementations (npm `1.0.13` / Maven Central `8.0.13`) - [TypeScript](https://github.com/metaobjectsdev/metaobjects/tree/main/server/typescript): the reference implementation. Published to npm at `1.0.13` across 14 `@metaobjectsdev/*` packages on the `latest` tag. 2500+ tests passing across the workspace. Bun-first dev workflow. Owns the canonical schema-migration toolchain used by every port (ADR-0015). - [Java](https://github.com/metaobjectsdev/metaobjects/tree/main/server/java): 14 publishable Maven modules under `com.metaobjects:*` at `8.0.13` on Maven Central (15 artifacts with the parent POM). Spring REST + DTO + repository-interface codegen, OMDB runtime persistence (pure data-access) with Spring-tx, full FR-003 + FR-006 + FR-010/011 + FR-018 + FR5 family. Fully green across all conformance corpora. - [Kotlin](https://github.com/metaobjectsdev/metaobjects/tree/main/server/java/codegen-kotlin): a Kotlin codegen pipeline on KotlinPoet plus `metadata-ktx` — a Kotlin facade over the Java MetaObjects core. Ships via the Java reactor (`metaobjects-metadata-ktx`, `metaobjects-codegen-kotlin`). Persistence-conformance runs against Testcontainers Postgres through Exposed. - [C#](https://github.com/metaobjectsdev/metaobjects/tree/main/server/csharp): loader + canonical serializer + EF Core + ASP.NET codegen + render/verify. The `dotnet meta` tool ships `gen` and the codegen-side `verify` subverbs (`--codegen`, `--templates`); schema migration is Node `meta` only (ADR-0015). - [Python](https://github.com/metaobjectsdev/metaobjects/tree/main/server/python): loader + canonical serializer + conformance + render + verify + codegen + an `ObjectManager` runtime layer. The `metaobjects` console-script ships `gen` and codegen-side `verify`. Fully green across all conformance corpora. ## CLI and project setup MetaObjects deliberately does **not** ship one universal binary. Schema operations are language-agnostic and live in **one canonical Node `meta` CLI**; codegen is language-specific and runs in each language's own build tool (ADR-0015). - Node CLI binary name: `meta` - Project config file: `metaobjects.config.ts` (configures `outDir`, `targets`, `dialect`, `dbImport`, `apiPrefix`, `columnNamingStrategy`, and the `generators` array) - Codegen is **opt-in**: no port ships a default generator suite, `meta init` scaffolds `generators: []`, and `meta gen --list` is the catalog (`--probe` reports how many files each generator would emit for your model) - Project marker directory: `.metaobjects/` - Install (TypeScript reference): `npm install -D @metaobjectsdev/cli` (or `bun add @metaobjectsdev/cli`) - Install (Java): `com.metaobjectsmetaobjects-metadata8.0.13` plus per-concern artifacts (`metaobjects-codegen-spring`, `metaobjects-omdb`, `metaobjects-maven-plugin`, etc.) - Install (Kotlin): same Maven coordinates — add `metaobjects-metadata-ktx` and `metaobjects-codegen-kotlin` to a JVM/Kotlin project. - Install (Python): `pip install metaobjects` - Install (C#): the MetaObjects .NET tool, invoked as `dotnet meta`. ### Commands - `meta init` — scaffold `metaobjects/`, `.metaobjects/`, and `metaobjects.config.ts`, **plus** the agent context: a slim `.metaobjects/AGENTS.md` + `CLAUDE.md` (auto-wired into the project's root `CLAUDE.md`/`AGENTS.md`) and six `metaobjects-*` Claude Code skills under `.claude/skills/` scoped to the project's stack. `meta init --refresh-docs` updates only the agent docs. - `meta gen [...]` — TS codegen from entities defined under `metaobjects/`. Supports `--dry-run` and `--watch`. Generators (`entityFile()`, `queriesFile()`, `routesFile()`, `formFile()`, `tanstackQuery()`, `tanstackGrid()`, `barrel()`) are reference templates you own, not framework imports: `meta init` wires none, and `meta eject ...` copies the ones you choose (`entity`, `queries`, `routes`, `names`, `barrel`, `form`, `hooks`, `grid`, `grid-hook`, `routes-hono`) into `codegen/generators/` in your own repo (ADR-0034 scaffold-and-own) and prints the import and entry to add to `metaobjects.config.ts`. The shipped defaults target Fastify/Drizzle/React/TanStack and are retargeted by editing your copy, not by switching tools. Per-port codegen runs in that port's own build tool: `mvn metaobjects:generate` (Java/Kotlin), `dotnet meta gen` (C#), `metaobjects gen` (Python). - `meta verify` — drift check. `verify --codegen` (regen-and-diff vs committed output), `verify --templates` (prompt `{{field}}` ↔ payload-VO drift), `verify --db` (live-DB schema drift, Node `meta` only). Per-port codegen verify: `mvn metaobjects:verify -Dmeta.verify.mode=codegen|templates` (Java/Kotlin), `dotnet meta verify` (C#), `metaobjects verify` (Python). - `meta verify` also checks any `requirement.*` nodes the model declares (capability requirements — what the system is supposed to do, as metadata). `@status` is a loader-enforced closed enum: `planned | live | partial | retired`. A dangling `@implementedBy` is an ERROR on `live`/`partial` and 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 by stating a prohibition in force**: a capability that was built and then deliberately removed keeps its entry, written as the rule that it must not come back (`@supersededBy` names what replaced it, and is RESOLVED, so it must be a full dotted path; `@implementedBy` is REFUSED on `retired`). Do NOT delete a retired capability's requirement — that entry is the whole point of the feature: given a brief for a capability that had been retired, agents working from the model alone proposed rebuilding it 24 times out of 24. `@verifiedBy` and the `abandoned`/`superseded` statuses were retired in `0.24.0` and now fail the load. Entirely opt-in: no `requirement.*` nodes means no diagnostics. Registered vocabulary in all five ports; the verify gate is the Node `meta` CLI. - `meta migrate --dialect --slug ` — diff metadata vs the committed schema snapshot and emit migration SQL files under `.metaobjects/migrations`; add `--db --apply` to run them. `--dialect` selects the diff pipeline, not just the SQL flavor — required offline and on `baseline`, auto-detected from the URL scheme when `--db` is given. On a brand-new database the first command is `meta migrate --from-db --db --dialect --slug init --apply` (diff against the empty database, emit `CREATE TABLE`, apply, record the snapshot) — **not** `meta migrate baseline`, which is for adopting a database that already has its schema. `meta migrate apply-pending --db --dialect ` replays committed migrations with no diff (fresh DB / CI). Supports SQLite (`file:`, `libsql:`), Postgres (`postgres:`, `postgresql:`), and Cloudflare D1 (TS only). `--dry-run` prints SQL to stdout. **Schema migration is owned by the Node `meta` CLI (ADR-0015) and used by every port regardless of backend language** — a JVM/Python/C# project needs no per-language migrate engine, but DOES need Node (or Bun) available to run it: no pre-built binary is published today. There is no Maven, .NET, or Python migrate command. - `meta export [--out ]` — flatten loaded metadata to one canonical JSON artifact. ## Monorepo layout - `spec/` — canonical metamodel docs (target-agnostic), including ADRs under `spec/decisions/` - `fixtures/` — cross-port conformance corpora (metamodel, render, persistence, api-contract, registry, yaml/verify) - `server/typescript/` — TypeScript server-side packages (`@metaobjectsdev/*` published to npm) - `server/java/` — Java + Kotlin Maven reactor (`com.metaobjects:*` published to Maven Central); Kotlin lives alongside Java since both run on the JVM - `server/csharp/` — C# implementation (`MetaObjects`, `MetaObjects.Render`, `MetaObjects.Codegen`) - `server/python/` — Python implementation (`metaobjects`, `ObjectManager`) - `client/web/` — universal web client TypeScript packages consumed by all backends (`@metaobjectsdev/runtime-web`, `@metaobjectsdev/react`, `@metaobjectsdev/tanstack`) - `examples/advanced-modeling/` — a worked, runnable model exercising projections, value objects, TPH and prompt payloads on one spine (the non-toy reference for authoring) ## TypeScript packages (npm) Server-side under `server/typescript/packages/`: - `@metaobjectsdev/metadata` — metamodel loader, types, constants - `@metaobjectsdev/codegen-ts` — framework-neutral TS codegen engine - `@metaobjectsdev/codegen-ts-react` — React codegen (formFile) - `@metaobjectsdev/codegen-ts-tanstack` — TanStack codegen (queries, grids) - `@metaobjectsdev/runtime-ts` — Node-side runtime (Kysely, Drizzle, Fastify helpers) - `@metaobjectsdev/migrate-ts` — migration tooling (the schema engine all ports use) - `@metaobjectsdev/sdk` — workspace memory, path helpers - `@metaobjectsdev/cli` — CLI binary `meta` (`init`, `gen`, `migrate`, `verify`) Universal web-client under `client/web/packages/`: - `@metaobjectsdev/runtime-web` — pure framework-agnostic browser core - `@metaobjectsdev/react` — React runtime (`useEntityForm`, ``) - `@metaobjectsdev/tanstack` — TanStack runtime (``, default cell renderers) ## 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`; goals `metaobjects:generate` and `metaobjects:verify`) Release procedure documented at [docs/RELEASING-java.md](https://github.com/metaobjectsdev/metaobjects/blob/main/docs/RELEASING-java.md). ## Author and context - Created and maintained by [Doug Mealing](https://dougmealing.com). Background and the architectural narrative live there. - The "why metadata is the spine AI was missing" essay: [I thought AI killed MetaObjects. Then AI drift made it essential.](https://dougmealing.com/writing/metaobjects-ai-drift/) - On the fourth pillar — why prompts are code too: [The prompt is code — and yours is drifting too.](https://dougmealing.com/writing/the-prompt-is-code/) - Commercial inquiries and consulting engagements: [metaobjects.com](https://metaobjects.com) ## Optional full corpus - [llms-full.txt](/llms-full.txt) — full Markdown dump of spec + quickstart material concatenated for direct LLM context.