Last refreshed 2026-07-16.
This file is the single source of truth for the roadmap. GitHub Milestones + Issues + the Project board mirror it. Keeping them in sync:
docs/ROADMAP-PROCESS.md.
Every feature request, its status, target release, and tracking issue. Shipped FRs are detailed under Shipped; planned FRs under Planned + the Release plan. ✅ shipped · 🔵 active · 📋 planned.
| FR | Title | Status | Release | Issue |
|---|---|---|---|---|
| FR-002 | Client/web package split | ✅ | — | — |
| FR-003 | Java RDB persistence & projections | ✅ | — | — |
| FR-004 | Cross-language prompt construction | ✅ (MCP remains) | — | #18 |
| FR-005 | Actionable loader errors (FR5 a–e) | ✅ | — | — |
| FR-006 | template.output parser-on-receipt |
✅ | — | — |
| FR-007 | Codegen conformance corpus | ✅ | — | — |
| FR-008 | Universal REST API contract | ✅ | — | — |
| FR-009 | Filter operators per port | ✅ | — | — |
| FR-010 | Output-format prompt + tolerant extract | ✅ | — | — |
| FR-011 | Extract hardening (enum coercion + nesting) | ✅ | — | — |
| FR-012 | Nested-object prompt expansion | ✅ | — | — |
| FR-013 | Field read-only | ✅ | — | — |
| FR-014 | TPH discriminator | ✅ | — | — |
| FR-015 | Source parameter-ref | ✅ | — | — |
| FR-016 | source.rdb name/kind aliases |
✅ | — | — |
| FR-017 | TPH polymorphic codegen | ✅ | — | — |
| FR-018 | Many-to-many relationships | ✅ | — | — |
| — | AI LLM-call trace persistence | 🔵 active | — | — |
| FR-019 | Shared / externally-provided enums | 📋 | 1.1 | #5 |
| FR-020 | @inheritance joined strategy |
📋 | 1.x | #6 |
| FR-021 | api metadata + contract projections | 📋 | 1.3 | #7 |
| FR-022 | Contract emitters (JSON Schema/OpenAPI/protobuf) | 📋 | 1.3 | #8 |
| FR-023 | Metadata packages (cross-project sharing) | 📋 | 1.x | #9 |
| FR-024 | Entity surfaces (projection/value + declared API) | 🟢 taxonomy + B3/B4a/B4b/B5/B6 validation parity + projection codegen shipped 5 ports (1.0); declared-API surface (api.operational/operation/binding.rest) deferred to 1.1 (foundation for FR-034) |
1.0 · 1.1 | #10 |
| FR-025 | Cross-port package-binding codegen config | 📋 | 1.1 | #11 |
| FR-026 | Forms completeness (edit forms + view parity) | 📋 | 1.0 | #12 |
| FR-027 | DataGrid downloads (CSV/XLSX/PDF/TXT) | 📋 | 1.2 | #13 |
| FR-028 | Strict serializer parity + meta export CLI parity |
📋 | 1.1 | #14 |
| FR-029 | Metadata API + runtime-driven UI | 📋 | 1.4 | #15 |
| FR-030 | Runtime serializers (SPI/XML/binary/round-trip) | 📋 | 1.1 | #16 |
| FR-031 | MetaData read-path caching + perf | ✅ shipped | 1.0 | #17 |
| FR-032 | Canonical FQN refs (YAML-only relative paths) | ✅ shipped (5 ports) | 1.0 | #21 |
| FR-033 | Provider definitions as declarative data + metamodel docs for LLMs | 📋 designed | 1.x | #23 |
| FR-034 | Ecosystem tier — connected systems (system/container/surface/environment) |
📋 designed (draft, deferred post-1.0) | 1.1 | — |
| FR-035 | Present-key PATCH tristate (mutation surface) | 🟢 shipped 5 ports (absent→untouched / present-null→clears / null-on-@required→400); coordinated breaking release held for FR-036 |
1.0 | — |
| FR-036 | Constraint-validation enforcement + semantic pins | 🟢 shipped 5 ports in the coordinated 0.16.0/7.8.0 breaking release (required-string = non-empty·accept-whitespace · @Pattern = full-match · strictest-wins length; HTTP-tier enforcement all 5 ports; TPH tristate) |
1.0 | — |
(FR-001 was the original metamodel foundation — pre-dates the FR-numbered tracking.)
(FR-032 was developed under the working number "FR-026" — see commit history; renumbered to avoid the FR-026=Forms collision. Design: docs/superpowers/specs/2026-06-13-fr-032-canonical-fqn-refs-design.md, ADR-0032.)
- H1 — Polyglot monorepo migration (2026-05-14)
TS code consolidated under
server/typescript/; package names normalized to@metaobjectsdev/*; CLI binary renamed tometa; config filemetaobjects.config.ts; tool-state dir.metaobjects/. - H2 — Shared conformance fixtures (2026-05-15)
Fixtures extracted into
fixtures/conformance/; per-port conformance runners; canonical serializer (fused-key form); format documented inspec/conformance-tests.md. - H7 — npm publish: first public release (2026-05-23)
All publish-candidate
@metaobjectsdev/*packages published to npm at0.5.0then0.6.0(latest). The JS/TS workspace root was hoisted to the repo root soworkspace:*resolves uniformly across the server + client package trees at publish time. - H8 — First TS consumer on published packages (2026-05-23)
A real TS consumer migrated off
link:filesystem deps onto the published packages and builds clean end-to-end — validating the published dist,.d.tstypes, and runtime imports through a real pnpm install.
- TypeScript —
@metaobjectsdev/metadata+codegen-ts(Vite-style plugins) +runtime-ts+migrate-ts+ the universal web client packages (runtime-web,react,tanstack). The reference port for everything cross-language. - C# full-stack target —
MetaObjects(loader + canonical serializer + conformance) +MetaObjects.Render(Mustache + payload-VO codegen +verify) +MetaObjects.Codegen(EF Core entities +AppDbContext/owned-types viaOwnsOne+ CRUD minimal-API routes + Postgres DDL with full-CREATE + incremental introspect/diff/migrate viameta migrate --from-db). - Java port —
metadata+omdb+om+dynamic+core-spring+metadata-ktx(Kotlin facade) +codegen-spring(Spring REST controllers + DTOs + repos + filter allowlists) +codegen-mustache+codegen-plantuml+codegen-base+render+maven-plugin(withmeta:gen/meta:editor; schema migrations are owned by the TS toolchain — the Java diff-and-converge engine and itsmeta:migrate/ live-DB-driftmeta:verifygoals were removed). - Kotlin —
codegen-kotlin(KotlinPoet on JVM): entity + Exposed table + Spring controller + Spring config + payload + relations + filter allowlist + validator + stored-proc + output-parser generators;integration-tests-kotlinruns the persistence-conformance corpus through Exposed against Testcontainers Postgres. - Python port —
metaobjects(metadata loader + canonical serializer + conformance) +migrate+ObjectManagerruntime + render (Mustache) + output-parser codegen.
- Metamodel conformance —
fixtures/conformance/(~90 fixtures + CAPABILITIES manifest). TS / C# / Java / Python all green. - Render conformance —
fixtures/render-conformance/. TS / C# / Java / Kotlin / Python byte-identical. - Persistence conformance —
fixtures/persistence-conformance/. TS / C# / Kotlin / Python all 12/12 against Testcontainers Postgres / Derby (per port). Java runs the query scenarios only (it no longer owns schema migrations); its runtime auto-create path bootstraps the schema, and the aggregate-projection view scenario is deferred (the view-body builder was part of the removed migration engine). - API-contract conformance —
fixtures/api-contract-conformance/. TS / C# / Java / Kotlin / Python all 20/20. - Extract conformance —
fixtures/extract-conformance/(22 dirty-input cases, incl.default-scalar-int+array-of-enum). TS / C# / Java / Python all green; Kotlin reuses the shared JVM engine. - Output-prompt conformance —
fixtures/output-prompt-conformance/(12 cases × 3@promptStylestyles). Pins the FR-010 output-format prompt fragment byte-identically across all 5 ports (zero-drift, no ledger) + a render→extract round-trip skew guard. Fragments expand nested objects + arrays-of-objects + scalar arrays (FR-012). TS pilot; C# / Java / Python reproduce the bytes natively; Kotlin drives the shared JVM engine. Backlog item R13. (Also added threefixtures/conformance/error-enum-*negative fixtures pinning FR-011 enum-coercion attr-validation —@coerceDefault/@defaultmembership +@normalizemode — across the 4 loader ports.) - Object-model conformance —
fixtures/object-model-conformance/(7 scenarios). Pins the cross-port runtime object model:newInstancefactory (map-backedValueObjectdefault, or a self-registered code-generated type), instance→MetaObject back-reference (MetaObjectAware), nested-object + array-of-objects field IO, overflow, and the codegen'd-or-not invariant. All 5 ports 7/7 (Java reference + reconcile; Kotlin over the JVM model; TS/Python/C# native, reflection-free). ADR-0017. (Phase A; metadata-driven extract + generalized@defaultbuild on it next.) - YAML / verify corpora — green across the ports that ship those layers.
- Source v2 paradigm —
source.rdb+@kind: table|view|materializedView|storedProc|tableFunction; multi-source via@role. ADR-0007. - FR-003 — Java RDB persistence & projections (Plans 1/2/3/4a + Plan 4): port of
dynamic/om/omdbonto current core; build-time FQN-keyed binding registry + typed jsonb value-objects + Spring-tx connection;source.*+origin.*metamodel registered in Java; OMDB engine-debt remediation (atomic mapping cache, JDBC codec registry per ADR-0002,inTransactiontemplate). The diff-and-converge schema-migration engine that originally shipped under FR-003 (SchemaMigrationEngine+ introspector + emitter + themeta:migrategoal) was removed when schema migrations consolidated onto the TS toolchain (@metaobjectsdev/cli migrate); the Java port retains runtime persistence + a dev/test runtime auto-create path only. - FR5 family — actionable loader errors (a/b/c/d/e + WARN envelope-shape). ADR-0009.
- FR5a: source-on-node + envelope-shaped errors (
format∈json|yaml|merged|resolved|database|code) - FR5b: YAML source positions on yaml-input envelopes
- FR5c: multi-file merge attribution (
MergedSource+contributors[]+ERR_MERGE_CONFLICT+WARN_DUPLICATE_DECLARATION) - FR5d: reference-resolution errors (
format: "resolved"+referrer+target) - FR5e: database-source envelope schema reserved + per-port shape tests + design questions resolved. Real DB-source loader is a future FR.
- WARN envelope-shape assertion finalized across all 4 ports.
- FR5a: source-on-node + envelope-shaped errors (
- FR-006 —
template.outputparser-on-receipt codegen. ADR-0010. Shipped in all 5 ports (TS / C# / Java / Python / Kotlin);meta verifyextended to cover output drift. - FR-010 — output-format prompt fragment + tolerant
extractparser. Shipped in all 5 ports. Onetemplate.outputdrives three artifacts: a comment-free output-format prompt fragment (3 styles × json/xml via@promptStyle), a tolerantextractLenient()(8-stage, never-throws, returns an all-nullable mirror of the payload) that complements FR-006's strict parser, and the@example/@instruction/@enumAlias/@enumDocfield-teaching attrs. Pinned by the sharedfixtures/extract-conformance/corpus; tolerance is at classification + canonical value (not byte-identity). (Originally namedrecover; cross-port-renamed toextractpre-GA — #87.) Designed indocs/superpowers/specs/2026-05-29-fr-010-output-format-prompt-and-tolerant-parsing-design.md. - FR-011 — extract hardening (enum coercion + nested-object extraction). Shipped in all 5 ports (TS pilot → C# / Java / Kotlin / Python). Hardens FR-010's
extractLenient()in place: an enum coercion pipeline (exact →@normalizenone|collapse|strip→@enumAlias→@coerceDefault→ MALFORMED),@defaultfills an absent enum (emitting the now-liveDEFAULTEDstate, which satisfies@required), and uniform nested/embedded-object recovery via dotted child paths (meta.score,items[i].label) across JSON + XML (the renamedextractengine). Normalization is ASCII-only (manual case-fold, byte-identical cross-port);@normalize/@coerceDefault/@defaultare member-validated onfield.enumat load time, with an object-level@normalizedefault. Fuzzy matching deferred (reserved pipeline slot). Corpus expanded 10 → 20 cases. Designed indocs/superpowers/specs/2026-05-30-fr-011-recover-hardening-design.md. - FR-012 — nested-object prompt expansion. Shipped in all 5 ports (TS pilot → Java / C# / Python; Kotlin inherits the shared JVM engine). The FR-010 output-format prompt renderer now recurses into nested
OBJECTfields, arrays-of-objects, and scalar arrays (instead of a flat{name}placeholder) across all 3 styles (guide/inline/exampleOnly) × json/xml, with an identity-based cycle guard +MAX_NEST_DEPTH. Closes the FR-010 request/response asymmetry (extractalready handled nesting). Output-prompt-conformance corpus 10 → 12 cases (addedjson-deep-nest+json-array-of-objects;json-nested/xml-nestednow round-trip). Designed indocs/superpowers/specs/2026-05-30-fr-012-nested-object-prompt-expansion-design.md. - Cross-port runtime object model (Phase A).
MetaObject.newInstance()factory → a map-backedValueObjectdefault or a self-registered code-generated type, with an instance→MetaObject back-reference (MetaObjectAware), a self-registering FQN→constructorObjectClassRegistry, and a field get/set-by-name SPI — all reflection-free (the ValueObject path resolves no native class; typed binding is generated self-registration, neverClass.forName/Type.GetType/reflect-metadata/importlib). Brought Java's runtime object model to TS/Python/C# (Kotlin reuses the JVM model). Pinned byobject-model-conformance(7 scenarios, all 5 ports). ADR-0017. - Metadata-driven extract (Phase B). Runtime
extract(MetaObject, text) → ExtractionResult<Object>assembles a typed object graph (nested objects + arrays-of-objects) via the Phase A model — never-throws, opt-inorThrow(), cycle/depth guard. Adds array-of-enum per-element coercion and generalizes@defaultto all field types (engine fill → DEFAULTED + per-type load validation in all 4 loader ports; Java legacysetDefaultValues/getDefaultValueunified). Each port's codegenextractLenient()delegates to the runtime (codegen-wrapping-runtime), closing the nested-object/array codegen gap ("Plan 2.1") while keeping a self-contained scalar/enum bakedextractLenient()for back-compat. All 5 ports; extract-conformance byte-green. (Originally namedrecover; cross-port-renamed toextractpre-GA —extractis the industry-standard term and avoids colliding with the retry-loop sense of "recovery" — #87.) Designed indocs/superpowers/specs/2026-05-30-recover-codegen-nested-design.md. - Prompt-construction pillar — per-port building blocks complete. Render (Mustache) + payload-VO codegen +
verify(FR-004), the output parser (FR-006), and the output-format prompt + extract (FR-010) all ship in all 5 ports. The library-side primitives of the fourth pillar are delivered; what remains is MCP exposure (see Planned). - Java flavored object + extractor codegen (shipped 2026-05-31, Java only). Direct (code-as-code, no templates) generation of objects that carry their
MetaObjectand extract a typed graph (nested + arrays-of-objects), in two selectable flavors via aflavorgenerator option:pojoAware(extends PojoObject) andvalueObject(extends ValueObject, perf-tuned cached per-field value-holder accessors), plus a self-registeringObjectClassBindingProviderand a<Name>Extractorwrapping the Phase-B runtime extract. Reuses the legacy direct object-codegen framework byte-unchanged (extends via hooks; downstream-extensibleprotectedseams +createWriterfactory). Compile-and-run gated per flavor + Extractor + a downstream-customization proof. Other ports frozen until Java is correct; designed indocs/superpowers/specs/2026-05-31-java-flavored-object-codegen-design.md. - Cross-port
<Name>Extractorcodegen (shipped 2026-05-31, TS / Python / C# / Kotlin — capability parity with Java). A generated<Name>Extractorpertemplate.outputadds a strictextracttier over the existing lenient tier:extractreturns the port's idiomatic strict typed payload (TS inferred type, Python Pydantic model, C#record, Kotlindata class) and throws on lost-required;extractLenient(never-throws, all-nullable mirror) is re-exposed. It reuses each port's existing nested-capable runtime-delegating lenient extract and a generated recursive mirror→strict mapper (nested objects + arrays-of-objects, one-shot construct), with no registry / binding / factory (codegen knows the type graph statically) and no new flavored object-class generation (constructs each port's existing idiomatic types). Compile-and-run gated per port (incl. non-string scalar arrays). Surfaced + fixed a latent cross-port scalar-array extract bug (JVMDataConverterarray conversions were dead/throwing; the JVM/C# lenient extract emitted scalar arrays as non-arrays). Idiom divergence (intentional): TS/Python honor@requiredoptionality in the strict payload; C#/Kotlin payloads are all-required(no optional-absent modeling) — extract works into each port's existing payload shape. The cross-portrecover → extractrename (#87) then swept all 5 ports together. Designed indocs/superpowers/specs/2026-05-31-cross-port-extractor-codegen-design.md. - Typed enums in payload VOs (shipped 2026-05-31, all 5 ports). The strict
extract<Name>payload types afield.enum(and enum arrays) with a value-constrained, idiomatic type instead of the prior inconsistentunknown/str/object/String: TS string-literal union, PythonLiteral[...], C# nestedenum, Kotlinenum class, Java generatedenum. The extract mapper coerces the engine-validated mirror string to the typed value — identity for TS (castas <Union>, gated bytsc --strict) / Python (Literal, Pydantic runtime-validated);Enum.Parse/valueOffor C#/Java/Kotlin (the call IS the bridge; gated by Roslyn/javac/kotlin-compile-testing). Reuses each port's established entity enum-type emitter + the shared<Super>/<Owner><Field>naming + dedup (two fields extending one abstractfield.enum→ one generated type, proven per port). The lenient mirror stays raw string (Java has no separate mirror — its single typed payload record is shared by parse/extract/extractLenient with null-safevalueOf, a documented idiomatic divergence; never-throws preserved because the engine yields a valid member or null). Engine +fixtures/extract-conformance/unchanged (codegen-typing only). Surfaced + fixed the enum-array "check-enum-before-isArray" lenient-mirror collapse bug in TS/Python/C#. Follow-up: super-resolution naming diverges only for 2+ level abstract-enum chains (immediate-super TS/C#/Python vs root-super JVM — pre-existing in the entity emitters, latent). Designed indocs/superpowers/specs/2026-05-31-typed-enums-payload-design.md. template.outputrender-helper codegen (phase 1 shipped 2026-06-01, TS + Java; C#/Python/Kotlin = phase 2).template.outputgains@kind(documentdefault |email); a new per-port generator emits a typed render helper wrapping the existing sharedrender()engine —render<Name>(payload, provider): stringfor a document (renders@textRefin@format),render<Name>(payload, provider): EmailDocument {subject, htmlBody, textBody?}for an email (renders@subjectRef/@htmlBodyRef/@textBodyRef). The build-time mustache↔VO drift gate is the headline: the generator resolves each referenced in-repo.mustacheand runs the existingverify()at codegen, FAILING the build when a{{field}}isn't on the payload VO (runtime check stays too). Replaces hand-writtenrender({ref, payload, format, provider, verify})boilerplate (the email-rendering hack). Reusesrender()/verify()/the filesystem provider/the payload field-tree walk +EmailDocument— engine + render-conformance UNCHANGED (codegen + small metamodel only). Sharedfixtures/template-output-render-conformance/(document + email + drift) pins identical TS/Java output. (The recollectedtemplate.documentmetatype never existed — this istemplate.output+ codegen.) Designed indocs/superpowers/specs/2026-06-01-template-output-render-helper-design.md.- Cross-port
templateGenerator()(shipped 2026-05-28). TS reference + Python / C# / Java factories; 3/3 conformance fixtures byte-equivalent. Java ships lightweight types undercom.metaobjects.render.templategen(its legacyGeneratorinterface was incompatible). Seedesign-docs/2026-05-28-cross-port-template-generator.md. - SP-1b — JVM declarative Mustache template generator (shipped 2026-06-28, Java + Kotlin). Wires the cross-port template generator into the JVM as a Maven-wirable
TemplateScopeGenerator(com.metaobjects.generator.template, incodegen-base) over the byte-equivalent render engine — closing the prior "Maven-plugin integration is a follow-up" gap. Implements the three named scope walks (perEntity/perPackage/perModel), the neutral structural data dict, and the output-pattern grammar ({name}/{Name}/{package}), all gated byte-identical for both Java and Kotlin against the sharedfixtures/template-codegen-conformance/corpus (the same corpus the TS port passes). Kotlin gains a template generator for the first time (reuses the shared JVM engine — no KotlinPoet). Part of the SP-1 codegen authoring-parity program; designed indocs/superpowers/specs/2026-06-28-mustache-codegen-parity-design.md. - SP-1d — C# declarative Mustache template generator (shipped 2026-06-28). The last of the four SP-1 ports — all changes under
server/csharp/. Brings the declarative template generator (scopeperEntity/perPackage/perModel+outputPattern, no walk code) to C# inMetaObjects.Codegen.TemplateCodegen(OutputPattern.Expand, theTemplateDataneutral data dict,ScopeWalk.ForScope,TemplateSpec.Parse/ToGenerators), and exposes it via a--template-spec <json>(+--template-root <dir>) JSON surface ondotnet meta gen— turning the previously no-optemplateGenerator()registry primitive into a real consumer-usable generator. Atargetfield is rejected (C# has no output-target concept, same decision as Python), and a bad template ref / wrong--template-rootyields a clean error not a stack trace. Gated byte-identical against the SAMEfixtures/template-codegen-conformance/corpus the TS + JVM + Python ports pass — all four ports now produce identical output. Part of the SP-1 codegen authoring-parity program; designed indocs/superpowers/specs/2026-06-28-mustache-codegen-parity-design.md. - OMDB Spring Boot 3 starter (shipped 2026-05-30). Autoconfiguration wires a
DataSource→ObjectManagerDBwith Spring-tx; closes the OMDB-modernization open question (jOOQ migration ruled out as a non-goal). - FR-008/FR-009 — Cross-port REST API contract + 10 filter operators. Shipped in all 5 ports.
- FR-018 — Many-to-many relationships. Shipped in all 5 ports. Slim vocabulary (
@through/@sourceRefField/@symmetric, with@joinEntity/@joinFieldsremoved; FK fields derived from the junction'sidentity.referenceSSOT) + a generic runtime M:N resolver (TS / Java / Kotlin / Python / C#) + codegen (entity navigation + idiomatic ORM wiring [Drizzle m2m / EF CoreUsingEntity/ Spring repo+JPA / Exposed / Pydantic+route as the SQLAlchemy-secondary equivalent]) + REST traversal (GET /<source-plural>/{id}/<relation>) + Tier-2 docs. Gated by the shared api-contract m2m corpus in both lanes (reference-server + generated-artifact-over-HTTP) + persistence-conformance, across hetero / directed-self-join / symmetric modes. Remaining: a typed TanStack M:N client hook (client-ergonomics follow-up). Designed indocs/superpowers/specs/2026-06-02-fr-018-many-to-many-relationship-design.md. - SP-G — registry-conformance gate. Shipped in all 5 ports (TS / C# / Java / Kotlin / Python, live + green). A structural enforcer of the "metamodel subtype vocabularies must be identical across languages" contract: each port emits its registry as a canonical, fully-sorted, byte-stable JSON manifest matched to the single committed
fixtures/registry-conformance/expected-registry.json. Reconciled the Java/Kotlin registries at source (the JVM runners compose from the defined metamodel provider set so codegen/om SPI doesn't pollute the measured vocabulary). Plus an untested-vocabulary coverage report (coverage-report.json) surfacing every registered(type, subType)/attr no fixture exercises. Seefixtures/registry-conformance/README.md. - SP-H — field-subtype end-to-end hardening + write-path conformance. Shipped in all 5 ports. Every concrete
field.*subtype now write+read round-trips through each port's runtime/ORM, gated cross-port: the persistence corpus gained anop: roundtripscenario type (INSERT via the port's write codec, NOT raw SQL → read-back → assert wire-normalized value) whoseAllTypesentity carries one field of every persistable subtype against Testcontainers PG — the structural complement to SP-G (which gated vocabulary). Cutfield.byte/field.short/field.classas non-functional registration-only stubs; reconciled uuid/currency filter-op bands cross-port + a loader guard for@filterable-without-op-band; Java write-codecs (timestamp/currency/enum/native-uuid/time) + Springfield.timearm; TS decimal string-exact dataType; Kotlin runs the shared metamodel corpus + a mapper-elsenegative test; barefield.objectrejected at load (ADR-0013). The write-gate surfaced + drove latent breakage "all corpora green" had masked (TS enum-CHECK, Java timestamp/native-uuid/time/jsonb writes, Kotlin LocalTime-write, C# read-back-caching, the filter-op divergences). Designed indocs/superpowers/specs/2026-06-03-sp-h-field-subtype-hardening-design.md. - Per-target output directories (TS codegen). Each generator routes to a named output target (
{ outDir, importBase?, outputLayout?, dbImport? }). - 0.6.x → 0.7.0 consumer-friction batch. Stock
promptRender()generator;db-parameter generated repo helpers (ADR-0008); Cloudflare Workers deploy recipe; CHANGELOG.md backfill + camelCase ↔ snake_case docs. (Currently published as0.7.0-rc.2; GA promotion is the next release move.)
- 0.7.0 GA promotion — currently
0.7.0-rc.2. Diff vs rc.2 is essentially one additive type (warningEnvelopes?onLoadOutcomein@metaobjectsdev/conformance). Procedure:docs/RELEASING.md(bun publish, regen lockfile, external install smoke in npm + pnpm). - AI LLM-call trace persistence — cross-port rollout. A metaobjects-native typed-trace store: each LLM call is persisted in the adopter's own DB with request/response as typed value objects (the same payload projection the prompt pillar declares + drift-checks), the one thing blob-only observability tools (Langfuse/Helicone/OTel) structurally can't do. Scope locked by ADR-0024: MetaObjects owns the typed trace + recorder seam + the vendor-NEUTRAL call glue; the provider call + pricing are bring-your-own (plug the stack's LLM library — Vercel AI SDK / LiteLLM / Spring AI — behind the one-method
LlmClient). Shipped in TypeScript (the reference port): shippedlibrary/ai/llm-call.yaml(LlmCallBase) + opt-inlibrariesloader; the recorder (recordLlmCall, never-throws, redaction seam) +buildLlmCallRowwhose key set is gated ==LlmCallBase's fields;deriveTraceFields(typedvoRequest/voResponsejsonb columns derived from a nestedtemplate.prompt's@payloadRef/@responseRef); generatedrecord<Entity>/call<Entity>(extract + persist base + typed in one row);@metaobjectsdev/ai-runtime(LlmClientseam,runLlmCall,callLlm,CompositeRecorder+ optionalLangfuseRecorder/OtelRecorderexporters); shared-table STI (@discriminator/@discriminatorValue, reuses FR-017 TPH). Cross-port (P3) in progress, JVM first: the Java metamodel slice shipped (@responseRefontemplate.prompt+template.*admitted asobject.entitychildren + aTS_PILOT_VOCABregistry-manifest exclusion;ai-trace-prompt-nested+ai-trace-stiun-ledgered in Java). Remaining: the Java recording half (OMDB recorder + thederiveTraceFieldsloader pre-pass +record<Entity>Spring codegen + a persistence round-trip), then Python → C# → Kotlin, then the atomic carve-out close (register@responseRefin every port + removeTsPilotVocabfrom all ports + add it toexpected-registry.json). Phased plan:docs/superpowers/plans/2026-06-06-ai-trace-descope-and-cross-port.md.
-
#195 follow-ups — projection read-model origins. The four capabilities (
origin.aggregate @agg:any|all|collect,origin.computed @expr,origin.first) shipped (validate + type in all 5 ports; TSmeta migrateview synthesis; seeCHANGELOG.md[Unreleased] +docs/superpowers/specs/2026-07-15-issue-195-projection-readmodel-origins-design.md). Remaining as fast-follows: (a) the "not-migrate-managed" escape valve — now tracked as #208 in the projection/view-materialization epic below (an@sqlView-style attribute carrying hand-written view DDL PLUS a distinct "managed elsewhere" marker, generalizing to any DB object, so a genuinely-irreducible view no longer aborts the wholemeta migraterun); (b) acollectnative-array persistence roundtrip gate (Postgrestext[]vs SQLitejson_group_array→ same wire) infixtures/persistence-conformance/. The TS-side real-engine value gate now EXISTS (integration-tests/test/view-lifecycle-{pg,sqlite}.test.tsvalue-probe all four #195 origin kinds — any/all/collect/computed/first — incl. the empty-set pinsany=false/all=true/collect=[]/first=nullon real PG and real SQLite). The remaining work is the CROSS-PORT persistence-conformance scenario (a projection with acollectarray column read by all 5 ports' runtimes), which is blocked on per-port native-array read support: TS + Python already read atext[]→ JSON array (native driver decode + a list branch in each normalizer); C# needs an array/IEnumerablecase inMetaObjects.ConformanceNormalization.NormalizeValue(emit aJsonArray) + a generated/mappedProgramInsightsEF entity; Java needs an OMDB JDBC array-read codec (java.sql.Array→List) forfield.string @isArray(itsNormalizationalready has aListbranch, butJdbcCodecsnever produces aList); Kotlin needs aProgramInsightsViewExposed table with a native-array column type registered inQueryScenarioRunner.tableFor(+ itsDEFERRED_SCENARIOSskip valve in the interim). Note the ports pure-glob-discoverqueries/*.yaml(Java/Python/C# have no skip mechanism), so the scenario cannot land until C#/Java array reads exist.normalization.mdwill gain the "SQL array → JSON array (empty{}→[], NULL→null)" contract when it lands. (c) #204 — SHIPPED (codegen-tsprojection-declnow carries a projection field'sisArray/storage:jsonbthroughextendsinto both the Drizzle view column and the Zod read schema, socollect → T[]types correctly; TS-only, pending the next npm release).origin.computed's expression grammar is designed so #159's arithmetic /case/@via-joined refs slot in as additive node kinds. -
Projection / view-materialization epic (#206–212). Follow-ons from #195 + adopter feedback on migrating legacy SQL-view-heavy schemas. Grouped by effort × 1.0-timing; Group A is TS-
meta migrate-owned (schema is TS-only per ADR-0015 → single-port, no 5-port fan-out).- Group A — concrete, 1.0-shippable (TS migrate/codegen):
- #206 — Docs on-ramp: surface entity read-views (FR-024 §7) as the first answer for legacy
SELECT A.*, extrasviews + an entity-vs-projection decision table. Docs-only, no metamodel change. Shipped. #213 — SHIPPED (schema/write half):meta migratenow excludes derived (origin.*) fields from the write table DDL (newMetaField.isDerived()) AND emits the replica read-view (isWriteThroughwired intobuildProjectionViews, entity-host mode inextractViewSpec— "one emitter, two hosts"); the TS write codecs (Drizzle table + Insert/Update Zod schemas) exclude them too. Gated by a real-Postgres round-trip (emit → apply → introspect → re-diff EMPTY) inview-lifecycle-pg. Was a real correctness bug (silent wrong-table + missing view). #214 — SHIPPED (unreleased): the FR-024 §7 codegen READ half across all five ports — generated reads route to the replica view, the entity read type carries the derived fields via a by-PK re-read (read-your-writes), writes target the table and exclude derived fields. (Flattenedfield.objecton a write-through entity is a tracked sub-limitation.) A shared cross-port #214 gate SHIPPED (unreleased) — and found+fixed a real TS bug. Building it surfaced that the TS reference port's generated REST routes for a write-through entity were never wired to the view:routes-file.tsmounted vanillamountCrudRoutes(table)(no view concept), so the deployed HTTP surface returned GET/POST responses OMITTING the derived field — the read-half had shipped inqueries.ts+ the view but the routes layer was left behind. Fixed:mountCrudRoutesgained an optionalreadView(list/get + post-write re-read route through the view; writes stay on the table), androutes-file.tspasses it for write-through entities. The shared gate lives infixtures/api-contract-conformance/write-through/(a Customer + write-through Order corpus: POST create returns the derivedcustomerName, GET reads it through the replica view) and runs on TS / C# / Kotlin — the ports whose GENERATED artifact re-reads through the view (TSreadView, C# EF.ToViewread-model, Kotlin inline ExposedOrderView). Java and Python are intentionally excluded (weak signal): their generated controller delegates read-your-writes to the runtime (PythonObjectManager) or the consumer persistence seam (Java), which the api-contract in-memory-repo lane bypasses — so a gate there would test a hand-written seam repo, not the generated re-read. Apersistence-conformanceop: roundtripgate was ruled out as the route because that corpus exercises the runtime read path, where write-through view-routing exists only in Python'sObjectManager(TSruntime-ts, Java OMDB, C# EFFindAsync, Kotlin/Exposed all read the write table). - #209 — SHIPPED (released in
0.17.0): derive INNER vs LEFT OUTER join from reference optionality — a NOT-NULL belongs-to FK rendersINNER JOIN(matching the hand-written view + keepingverify --dbfingerprints aligned), a nullable belongs-to or any has-many hop staysLEFT OUTER, with nested-chain demotion (an INNER hop under a LEFT ancestor demotes to LEFT to avoid dropping base rows).extract-view-spec.ts+view-ddl-emit.ts, gated byjoin-type-derivation.test.ts. The optional explicit@join: inner|leftoverride is not needed (the optionality-derived default is correct); defer until an adopter wants to force it. - #207 — SHIPPED (unreleased): View-level
@filter(row-scope WHERE) reusing the 5-portattr.filterAST, lowered to an outerWHEREinemitViewDdl. Closed the single largest functional gap for filtered views (soft-delete / status / type views). Semantic (field + op), never raw SQL. Cross-port validation (dangling + aggregate-derived); op-band / malformed-shape checks are TS-only. - #208 — SHIPPED (unreleased): DDL-ownership escape valves —
source.rdb@sql(a hand-written view body migrate registers + fingerprints + drift-checks but never authors/parses, adopted viamigrate --allow adopt-view) +@unmanaged(skip create/drop/drift for a Flyway/hand-migration-owned view or table). The load-bearing piece is the suppression rule (classify DDL-ownership beforeviewIsDerived), which closes a silent-wrong-synthesis hole. Registration + 6 loader-validation rules cross-port (5 ports); migrate/verify lowering TS-only (ADR-0015). See ADR-0043 +docs/superpowers/specs/2026-07-17-issue-208-ddl-ownership-escape-valves-design.md. Deferred follow-ups: (a)@dependsOnfor@sqlviews — an opaque body'sdependsOnis derived fromextends-anchors only, so a JOINed-but-unanchored table is not tracked for auto-recreate around a columnALTER(add the explicit attr when an adopter hits it); (b) the matview managed path (@sqlon@kind: materializedView— needspg_matviewsintrospection + COMMENT-on-matview + REFRESH); (c) opaque-body column-name verification (verifycross-checks an@sqlview'sinformation_schema.columnsagainst the declared field set).
- #206 — Docs on-ramp: surface entity read-views (FR-024 §7) as the first answer for legacy
- Group B — 1.0-freeze-window vocab decision (needs an owner ruling before the freeze):
- #210 — Retire
origin.*onobject.value(total value purity: no identity, no source, no origins). Pre-1.0 per ADR-0035's window; cross-port payload-VO churn but "mostly node-type relabeling" since the payload path already shares the projection codegen path. Ruling: do the churn now vs. accept the fallback rule-of-thumb and leave the two-spellings seam.
- #210 — Retire
- Group C — post-1.0 backend generalization (design-now, build-later):
- #212 — Events emit projections: resolve the ADR-0007 vs ADR-0028 contradiction (a stream is a channel, not a source). The ADR amendment (drop
source.event; model emission at the surface asapi.eventing/operation.event/binding.messagingwith a payload→projection ref) is cheap to decide now; the eventing surface builds post-1.0. Lands the CQRS+events symmetry: queries return projections, commands take values, events emit projections. - #211 — Backend-agnostic projection materialization (one derivation spec, N lowerings): generalize
SelectSpecfrom RDB-only to document/search/… with an origin × (paradigm,@kind) capability matrix + load-time errors. Large FR; its foundation is Group A landing with the "semantic, not RDB-specific" lens (#207/#208/#209 become the first lowerings). Post-1.0; composes with FR-034 (ecosystem tier).
- #212 — Events emit projections: resolve the ADR-0007 vs ADR-0028 contradiction (a stream is a channel, not a source). The ADR amendment (drop
- Group A — concrete, 1.0-shippable (TS migrate/codegen):
-
FR-019 — Shared + externally-provided enums. Stop redeclaring a
field.enuminline in every consuming entity: a package-level abstractfield.enummaterializes ONE standalone enum type per port (the existing D6extendsreuse vocabulary), and@provided: true— a provenance flag on the named-type declaration (not the field), shared cross-type with value objects — references an existing hand-written type instead of emitting one (per-port namespace via codegen config, never a metadata FQN — retires the C#-only@csEnumType). Decision in ADR-0026; implementation specdocs/superpowers/specs/2026-06-06-fr-019-shared-and-provided-enums-design.md. (Generators are now subclass-extensible across all 5 ports, so this lands on open seams.) -
FR-020 —
@inheritancepersistence strategy (single-table vs joined). TPH (one physical table, nullable subtype columns) is the single implicit strategy today (FR-014/FR-017). FR-020 adds an@inheritanceattr to choose joined (a base table + per-subtype tables, joined on read) as an alternative — additive, default stays TPH (no breaking change). Status: design (proposed, sequenced after FR-017, which shipped). Design:docs/superpowers/specs/2026-06-07-fr-020-inheritance-strategy-design.md. (Was not previously surfaced in this roadmap.) -
FR-025 — Cross-port package-binding codegen config. Config for how a metadata FQN/package maps to each port's native namespace/package at codegen time (the ADR-0001 build-time binding), so cross-package references (and metadata shared across projects, FR-023) emit correct imports per language. Status: design (ready for implementation). Design:
docs/superpowers/specs/2026-06-08-fr-025-cross-port-package-binding-config-design.md. (Was not previously surfaced in this roadmap.) -
MCP exposure of declared prompts/tools — the remaining library-side piece of the prompt-construction pillar. Surface a
template.output/ tool declaration over the Model Context Protocol (model-agnostic) so an LLM host can discover + register it, built on the shipped render / payload / verify / FR-006 / FR-010 primitives. Designed indocs/superpowers/specs/2026-05-22-fr-004-cross-language-prompt-construction-design.md. -
FR-024 — Entity surfaces:
object.projection, universal field-extends, and the declared API. A third object subtype (derived, read-only, borrowed identity viaextends; the declared field set IS the exposure — fail-closed), universalEntity.childextends-resolution (load-time drift gate on every contract shape),@viasingle-hop-unique inference, multi-source entity view behavior, and theapi.operational/operation.query|command/binding.restsurface — across all 5 ports, conformance-gated; the two pre-taxonomy spellings (entity-extends-entity views, proc-results-as-entities) are removed outright (hard cutover, pre-GA). Decisions: ADR-0028 / ADR-0029 / ADR-0030. Design:docs/superpowers/specs/2026-06-12-fr-024-entity-surfaces-projections-design.md; program plan:docs/superpowers/plans/2026-06-12-fr-024-entity-surfaces-program.md. Supersedes the shape-vocabulary half of the FR-021 sketch (itsapi/wireIddirection stands, retyped onto projection/value). -
FR-021 —
apimetadata type + contract projections. Declared API surfaces (operations + per-protocol bindings) over the derived-CRUD default; operation payloads areobject.valueprojections (the sameorigin.*machinery as prompts and views); wire-stablewireIdnumbering lives on the contract projection (never the entity) so domain evolution can't break wire compat. Design sketch:docs/superpowers/specs/2026-06-11-fr-021-api-metadata-and-contract-projections-design.md. Revised by FR-024: contract shapes areobject.projection(query outputs) /object.value(command inputs); subtype vocabularyapi.base/api.operational; see ADR-0030. -
FR-034 — Ecosystem tier: connecting meta-modeled systems over a network. A semantic topology layer that models the ecosystem — many meta-modeled systems and how they call each other — rather than a single system's shapes. C4-style two-level nesting:
system(logical software system) →container.service|client(the deployable network participants), each carryingsurface.provided|consumededges whose@apiRefresolves (FQN, ADR-0041) to anapi.*node in the same or a dependency package; plusenvironment.deployment(the named instantiation that keys a generated per-environment address-config matrix). URLs are not metadata (a generated, fail-closed address contract keyed per environment carries them); the logical topology moves into core (superseding ADR-0030 §5) while the physical tier stays permanently out. Reuses FR-023 (metadata-package transport), ADR-0041 (resolution), and ADR-0029 (the load-time drift gate, now spanning repos → cross-system drift detection = pillar 3, one tier up). Depends on the FR-024 declared-API surface. Owner rulings (2026-07-10): C4-nesting, topology-into-core, names-only environments, defer third-party. Draft, deferred post-1.0. Design:docs/superpowers/specs/2026-07-10-fr-034-ecosystem-tier-connected-systems-design.md. Downstream convergence evidence (a consumer independently re-deriving the consumed-edge address contract + protocol-off-the-type-axis):spec/design-docs/2026-07-11-downstream-convergence-outbound-adapters.md. -
FR-022 — Contract emitters (Tier-2): JSON Schema 2020-12 (canonical + strict structured-output profile) → OpenAPI 3.1 → protobuf. One shared neutral engine per ADR-0020; strict profile targets the cross-provider structured-output intersection (also MCP input schemas); proto emission consumes FR-021
wireIds, maps types per the locked table (Decimal/minor-units/uuid-string/optional/UNSPECIFIED-enum-zero), and inherits wire-compat regression detection viabuf breakingon the emitted artifacts. Design sketch:docs/superpowers/specs/2026-06-11-fr-022-contract-emitters-design.md. -
FR-023 — Metadata packages: cross-repo distribution + reuse. A code-free, versioned artifact (the
metaobjects/tree + manifest) published through each ecosystem's registry (npm/Maven/PyPI/NuGet) and declared viametadataDependenciesin config; loader source composition + overlay/extends across package boundaries (mechanics already shipped) with dependency-then-local merge order, collision rules, and per-package provenance attribution. Design sketch:docs/superpowers/specs/2026-06-11-fr-023-metadata-packages-design.md.- Near-term doc-first quick wins (available now, no new code): the mechanics of cross-project sharing already work — overlay merge, deferred cross-package
extends, and dir/URI loaders — so before the full package-resolution build, ship recipes: (a) a monorepo pattern (one sharedmetaobjects/dir loaded by TS + Java + Python projects), (b) a git-submodule pattern (pull upstream metadata into a localmetaobjects/), and (c) wire the already-defined-but-unused.metaobjects/config.jsonsourcesfield (TS) to the loader so{ kind: "path" }overlays compose. These cover most "share a model across our backends" needs with documentation; FR-023 proper adds true dependency resolution + themetaobjects.pkg.jsonmanifest. TS-onlylibrariesmechanism (metaobjects::ai) is the single existing precedent — generalize it under FR-023.
- Near-term doc-first quick wins (available now, no new code): the mechanics of cross-project sharing already work — overlay merge, deferred cross-package
-
FR-026 — Forms completeness: edit forms, view-render parity, validator wiring (TS web client). Builds on what ships today — create forms (
@emitForm→formFile→useEntityForm+ ZodInsertSchema), field display viaview.*cell renderers (~10 of 13 subtypes), and client form rules (required/length/regex). Gaps to close: (1) edit forms —UpdateSchemais already generated but no codegen consumes it; emit<Entity>EditForm(load existing values as defaults, PATCH, same field-visibility rules as create); (2) view-render parity — registerdatetimeas aview.*subtype (its renderer exists but no metadata path selects it) and add renderers forhotlink/month/radio; (3) validator wiring —validator.numeric/validator.arrayare emitted to Zod but NOT to the client form rules (only field attrs are); (4) view attrs — only@localeis schema'd;@placeholder/@helpText/@step/@rows/@patternare currently ad-hoc; (5) optionallayout.form(field grouping / sections / conditional visibility). TS-web-only by architecture (the browser is the TS-native UI surface). Supersedes the Future "Forms codegen revival" note. Status map from the 2026-06-13 audit. -
FR-027 — DataGrid data export + grid completeness (TS web client).
layout.dataGrid+ the TanStack grid codegen (columns + grid hook) + runtime (server-driven sort / paginate / filter / free-text search, 9 filter ops,withCountenvelope, extensible cell renderers, React + Angular variants) ship solid. Headline gap: data export / download does not exist anywhere. Add CSV / XLSX / PDF / TXT export driven by the grid's current columns + filter/sort state: client-side for the loaded page, plus an optional server-side bulk-export endpoint (GET /<entity>/export?format=…, pagination off, streamed) for full-dataset export; reuse the existing renderescapers.tsCSV formula-injection guard. Optional@exportFormatsattr onlayout.dataGrid. Secondary grid gaps: column width / visibility / reorder / resize metadata (meta.widthis reserved but never populated; no@hidden/@columnWidth), row (multi-)selection, and making server-sidesearchbehavior consistent cross-port. Status map from the 2026-06-13 audit. -
FR-028 — Strict object serializers (cross-port parity) +
meta exportCLI parity. (Baseline for FR-030.) The metadata canonical serializer (loaded metadata → canonical JSON, raw +effective) already ships in all 5 ports, and themeta exportCLI ships in TS. The object-graph strict serializers are uneven: object → JSON strict (with symmetric read) ships only in TS (objectToJson/jsonToObject) and Java (JsonObjectWriter/JsonObjectReader) — missing in Python / C# / Kotlin; object → XML strict write is missing in every port (only the tolerantextractXML read side exists). Backlog: (1) port object→JSON strict to Python / C# / Kotlin (conformance-gated alongside the existingop: roundtripgate); (2) addmeta exportto the Java / Python / C# / Kotlin CLIs. Status map from the 2026-06-13 audit. -
FR-029 — Metadata API + runtime-metadata-driven UI (backend-agnostic). The web UI is TS (browser-native) but must be drivable by metadata fetched from any backend over APIs, so the same grid/forms work regardless of server language. Two delivery modes, both supported + demoed: today's codegen UI, and a new runtime mode that fetches the model and builds the UI dynamically. Gaps: a metadata API endpoint per backend (serve canonical metadata as JSON over HTTP), a browser runtime metadata loader (
runtime-web→ in-browser MetaData read-model), a runtime-driven dataGrid + runtime-driven create/edit forms, a both-ways reference app, and a backend-agnostic guarantee (the TS UI verified against all 5 backends serving the metadata + data APIs). Detail: §"Theme 1" ofdocs/superpowers/specs/2026-06-13-metadata-runtime-ui-and-serializers-gaps.md. -
FR-030 — Runtime metadata-driven serializers: protocols, round-trip, field-subset. Serialize/deserialize an object graph driven by the MetaData itself (honoring
normalization.md), on Pojo or ValueObject instances, resolving theMetaObjectviaMetaObjectAware(fast path) or theObjectClassRegistry. A pluggable serializer SPI so new protocols slot in uniformly: JSON + XML write (revive the legacymetaobjects-core/dynamicJSON+XML), plus a binary protocol (protobuf — reuse FR-022'swireId/type mapping — and/or MessagePack/CBOR) "to show how standardized it is." Per port: a thin adapter over the native serializer (Jackson / System.Text.Json / Pydantic / kotlinx) where one fits, fully custom otherwise. A field-subset/projection serialization parameter (reuses FR-024 projections; shared with grid JSON/XML downloads). Round-trip integrity conformance —json → xml → binary → json, assert no data loss, cross-port. Open ADR: keep bidirectional serialization separate from one-way (lossy) data download, sharing JSON/XML via the field-subset param. Detail: §"Theme 3" of the gap doc. -
FR-031 — MetaData read-path caching (general; serialization is the example). Repeatedly walking the MetaData tree for field/attr/validator/view/children lookups is a hot path for every consumer — codegen, runtime, the UI, and (as the headline example) serializing 100k+ large objects re-queries the tree per object. The MetaData read-model is immutable after load, so memoize these lookups on the MetaData class once. Deliberately not serialization-specific: it's a general read-path cache that any processing benefits from, validated by a throughput benchmark gate (process 100k+ objects, cached-vs-uncached delta) per port, using serialization as the example workload. Low effort, high leverage. (The serialization-specific perf — a per-MetaObject compiled plan + streaming large sets — rides with FR-030, building on this cache.) Detail: §"Theme 4" of the gap doc.
These are exercised in adopter projects on top of the shipped per-port primitives, and are deliberately not tracked as open items in this repo:
- Consumer-adoption validation — downstream consumers migrating onto metaobjects-emitted code across the language paths (the former H5 / H9 / H10). The library surface they exercise (
codegen-spring,MetaObjects.Codegen, the web-client packages, etc.) already ships. - Application-level prompt-pillar consolidation — the end-to-end declared-prompt orchestration and prompt eval harness that sit on top of the per-port primitives (the former H6, minus MCP exposure, which remains a library item above).
Grouping of the Planned work into releases. Multiple items per release is fine. Before 1.0 we keep it lean — consistency fixes + cheap, broadly-leveraged foundations; the big new themes (serializers, downloads, runtime-driven UI) land post-GA where they can be built properly without holding the GA.
- FR-031 — MetaData read-path caching + throughput benchmark. Low effort, high leverage, benefits everything; serialization is the example, not the only consumer. (Doug-prioritized.)
- FR-026 — codegen edit forms + view-render parity (TS web only, small). Create forms ship but edit forms don't — create/edit symmetry is table-stakes for a GA.
meta exportCLI parity (Java/Python/C#/Kotlin) — trivial cross-port CLI consistency (the carve-out of FR-028 that's cheap; object↔JSON port-parity itself rides 1.1).- GA mechanics — the 0.10.0 publish (npm + NuGet/PyPI/Maven re-cut so
meta docs/verify --codegen/--db/ the SDK-docs parity are installable) → smoke → promote to 1.0. - [RESOLVED 2026-07-10] FR-024 — entity surfaces (projection/value taxonomy + declared API).
The breaking half — the projection/value taxonomy + B3–B6 validation parity + projection
codegen — shipped in the 1.0 line across all 5 ports (the pre-GA hard cutover is done, and
the serializer/download field-subset (SER-7) can build on the now-shipped
object.projection). The declared-API surface (api.operational/operation/binding.rest) is confirmed not a 1.0 gate and slips to 1.1, where it becomes the foundation for FR-034 (ecosystem tier). Rationale: it is greenfield additive vocabulary (nothing registered yet), so deferring costs no compatibility and keeps the 1.0 line lean. - [OPTIONAL] FR-019 — shared/provided enums (small, already designed) — slot here or 1.1.
- [OPTIONAL] FR-025 — cross-port package-binding codegen config (ready for implementation) — pulls into 1.0 if FR-024's cross-package generated imports need it; otherwise 1.1.
- [OPTIONAL] MCP exposure — completes the prompt pillar's library side; pull to 1.0 only if "4 complete pillars" is a GA marketing bar, else 1.1.
- Reference-app coordination (wizardsofodd). A live adopter reference —
wizardsofodd.com, source at
Draagon/wizardsofodd — is public: one metadata spine
drives its Cloudflare D1 schema, API types, LLM prompts, and SSE protocol, drift-gated in CI. As
part of the 1.0 launch: (1) bump the reference to the 1.0 packages via a public, drift-gated PR
— a green gate publicly demonstrates upgrade safety (the Dependabot
@metaobjectsdev/*group PR does this); (2) link it from metaobjects.dev as the "see it in production" proof (play it live / read the source / watch the drift gate catch a rename); (3) keep it ≤ one published line behind — fold "bump the reference app" into the release checklist so it never lags.
- FR-024 declared-API surface — the deferred half of FR-024:
api.base/api.operational,operation.query|command,binding.rest,inputRef/outputRef/many; loader ref-resolution + path-template↔identity validation; per-port route-shell codegen (typed handler seam, verb bodies hand-written);meta verify+meta docs; atomicexpected-registry.jsonflip across 5 ports. The foundation FR-034 references. - FR-034 — ecosystem tier (connected systems). Semantic topology for connecting meta-modeled
systems over a network:
system(logical) →container.service|client(deployable participants) →surface.provided|consumed(the API edge,@apiRef→ anapi.*node) +environment.deployment(named instantiation, names-only in v1). URLs stay out of the metamodel (a generated address contract, keyed per environment); supersedes ADR-0030 §5 for the logical tier. Reuses FR-023 (transport) + ADR-0041 (resolution) + ADR-0029 (cross-repo drift gate) — additive vocabulary, no new machinery. Design:docs/superpowers/specs/2026-07-10-fr-034-ecosystem-tier-connected-systems-design.md. - FR-028 finish — object↔JSON strict parity (Python / C# / Kotlin).
- FR-030 core — serializer SPI; XML write (revive the legacy core/dynamic JSON+XML); field-subset via FR-024 projections; Pojo/ValueObject/MetaObjectAware support; json↔xml round-trip conformance. Realizes ADR-0031.
- FR-030 serialization perf — per-MetaObject compiled plan + streaming (on FR-031's cache).
- FR-027 — client export (CSV/XLSX/PDF/TXT) + server bulk-export endpoint (all backends) +
JSON/XML download via the 1.1 serializer & field-subset + export conformance + the secondary
grid gaps (column width/visibility/selection, consistent server
search).
- FR-030 binary — protobuf / MessagePack / CBOR over the SPI → completes the json → xml → binary → json no-data-loss round-trip gate.
- FR-022 — contract emitters (JSON Schema / OpenAPI / protobuf) — overlaps the protobuf
serializer (shared
wireId/type mapping); do together.
- FR-029 — metadata API endpoint (all backends) → browser runtime metadata loader → runtime-driven dataGrid + create/edit forms → both-ways (codegen vs runtime) demo → backend-agnostic verification (the TS UI against all 5 backends).
- FR-023 — metadata sharing (full package resolution; the doc-first quick wins can land any time, independent of release).
- FR-020 —
@inheritancejoined strategy (additive; pairs with a persistence release). - MCP exposure (if not pulled earlier — see below).
- Database-source metadata loader (currently Future).
Candidate directions, not actively tracked — pulled up into Planned only when scheduled.
- Database-source metadata loader — load the metamodel itself from a database (a metaobjects-table schema + a loader that reads it) instead of JSON/YAML files, for a central / runtime-editable metadata registry. FR5e already reserves the
format: "database"error envelope (table + id + optional jsonPath), so the error contract is in place; the loader itself is unbuilt. - Date / case transforms.
- Materialized views, federated entities, search-index sources.
A forward-looking cluster: today the LLM is a consumer of metaobjects (it reads the model, proposes metadata, writes against generated code). The next inflection is the LLM as author of the model — it emits typed metadata (the durable spine), verify gates it before it runs, codegen produces disposable per-language code, and escape hatches cover what metadata can't express. This sits in the seam between "the LLM writes the code" (maximally expressive, opaque, ungovernable output) and "the LLM writes config/flows" (safe but locked to a fixed node/component vocabulary). The same typed-payload + declarative-template + verify mechanism already describes the data model and prompts — extending it to the UI makes the model the single spine an LLM authors across all three render targets. These build on shipped primitives + the planned FRs noted; none are scheduled yet.
- Declared LLM-operation — a metadata node binding a complete I/O unit (input payload VO + prompt template + output VO + parse strategy) as one codegen'd, runtime-resolvable,
verify-able unit. The pieces exist separately today (payload, template, render, output parser); this composes them. Completes the prompt pillar; relates to the MCP-exposure item above. - Bindable view/layout fields + UI action model — a binding attr (literal / data-pointer path / function-call) on
view.*/layout.*nodes, with pointer-resolution validated inverifyexactly as a{{slot}}is validated against a prompt payload; plus a typed UI action/event output VO — the UI's response contract, peer to a prompt's output VO. Makes metadata-driven UI symmetric with metadata-driven prompts. Builds on FR-026/FR-029. - Generative-UI interop — emit a declarative generative-UI catalog (e.g. the A2UI shape: catalog + components + dynamic binding) from native
view/layoutmetadata, and import external catalogs — a standards-interop codegen target alongside Drizzle / EF Core / Pydantic. Builds on FR-022 (contract emitters) machinery. - Portable model interchange — a vendor-neutral, diffable export/import for a whole declared model (data VOs + prompts + UI + actions), building on the canonical serializer (FR-028/FR-030) and metadata packages (FR-023). The fragmentation evidence is real: declarative-flow/agent platforms each ship their own JSON and none interoperate. A neutral interchange for declared app/agent metadata is unclaimed ground.
- Runtime model authoring loop — dynamic VO instantiation from a field tree with no regen step, pluggable template providers (filesystem / database / custom) behind the
renderresolver, andverifypromoted to a first-class runtime gate (validate an LLM-authored-or-mutated template/model before persisting or rendering). Overlaps FR-029's runtime mode; the authoring-gate framing is the new piece.
(Forms codegen revival has been promoted to FR-026 in Planned.)
An earlier version of this roadmap listed H4 — TS codegen Java target as a 2-3 week project to refactor codegen-ts into pluggable targets so a Java target could emit Spring code from TS. That framing is obsolete and retired.
The pattern that has actually shipped across all four language ports is: each port has its own codegen layer in its host language.
| Port | Codegen module | Emits |
|---|---|---|
| TS | codegen-ts |
TS entities, Drizzle, Zod, Fastify routes |
| C# | MetaObjects.Codegen |
EF Core entities, AppDbContext, ASP.NET routes, Postgres DDL |
| Java | codegen-spring |
Spring @RestController, DTO records, repositories, filter allowlists |
| Kotlin | codegen-kotlin |
KotlinPoet output: Exposed tables, Spring controllers, payload VOs, output parsers, stored procs |
| Python | metaobjects.codegen |
Pydantic models, FastAPI routes, output parsers |
A polyglot codegen engine in TS would have meant forcing every Java consumer to install Node/bun just to generate Java — and the C# / Kotlin / Python ports already proved this isn't necessary. Java's codegen-spring is real, shipped, and emits the full cross-port surface (FR-006 / FR-008 / FR-009 / FR-010) alongside the other ports; there is no remaining per-port codegen gap.