Thanks for your interest! MetaObjects is a cross-language metadata standard with five language ports (TypeScript, C#, Java, Python, Kotlin) kept in lockstep by shared conformance corpora. This guide covers how to propose changes.
- New here and looking for a place to jump in? Browse the
good first issuelabel for low-barrier, well-scoped starting points. - This is a primarily one-person, part-time project — issues and PRs are welcome, but expect reviews on the order of days, not hours.
- For anything non-trivial (new metamodel behavior, a new generator, a cross-language change), open an issue first to discuss the approach. Small, obvious fixes can go straight to a PR.
- MetaObjects is a public repository. Never include private/other-project names,
client names, personal information, or absolute local paths in code, docs, fixtures,
or commit messages. Use generic terms ("a downstream consumer", "a sibling
project") and repo-relative paths (
<repo-root>). A CIleak-scanjob and a local pre-commit hook enforce this.
- Fork the repo and create a branch from
main. - Make your change following the discipline below — tests first (TDD).
- Run the gates locally with
scripts/ci-local.sh(or--quickto skip the docker integration suite) and make sure it's green. This matters: to keep CI costs down, the heavy correctness gates (the cross-port conformance matrix, the full Java reactor, the drift/mutation gates, and the integration-tests testcontainers matrix) no longer run automatically on PRs — they are release gate (v*) + on-demand only. Local CI is now the primary correctness gate. - Open a pull request against
mainand fill out the PR template. - The public-repo
leak-scangate still runs on every PR; a maintainer runs the full gates (locally or via the on-demand workflow) and approves before merge.
The metamodel vocabulary (types, subtypes, attributes) is identical across all five
ports, enforced by the conformance corpora. Adding or changing metamodel behavior
means adding/updating a conformance fixture so every port verifies it — see
spec/conformance-tests.md and
fixtures/conformance/.
- Never invent a metamodel attribute (ADR-0023). Every accepted attribute must come
from a registered provider plus a
registry-conformancefixture. If a generator can derive something from existing metadata, derive it — don't add an attribute. Seespec/decisions/ADR-0023-strict-metadata-provenance.md. - Preserve the cross-language wire format and vocabulary exactly — see CLAUDE.md → Cross-language porting.
- TDD — write the failing test first, then the implementation.
- Named constants for metamodel strings — never inline
"field","object", etc. (TS:server/typescript/packages/metadata/src/constants.ts). - No
anyescape hatches (TS) — useunknownand narrow. - No backwards-compat hacks.
- Match the surrounding code's style, naming, and idioms.
- Read an existing generator/port before adding a new one — the patterns are intentionally consistent.
# TypeScript — once, at the repo root:
bun install
cd server/typescript && bun test # TS server suite (run scoped, never a bare root `bun test`)
cd server/csharp && dotnet test # C#
cd server/java && mvn test # Java + Kotlin
cd server/python && pytest # Python (in its .venv)Cross-language persistence / api-contract corpora (Docker + Testcontainers) run via
scripts/integration-test.sh.
Because the heavy gates no longer auto-run on PRs (cost), reproduce the full CI locally with one command:
scripts/ci-local.sh # full parity: leak-scan, all-port conformance,
# java reactor, drift/mutation gates, + docker
# integration suite
scripts/ci-local.sh --quick # everything except the docker integration suiteIt SKIPS (loudly, not silently) any port whose toolchain (bun/dotnet/uv/mvn) isn't
installed. The .githooks/pre-push hook additionally runs the TS build+typecheck
gate and a Java pom-version drift guard on every push (activate hooks once per
clone: git config core.hooksPath .githooks).
Maintainers only — see docs/RELEASING.md.
By contributing, you agree your contributions are licensed under the project's Apache License 2.0.