@metaobjectsdev/sdk 0.11.6-rc.1 → 0.12.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,76 @@
1
+ # Python codegen specifics
2
+
3
+ The Python port targets FastAPI consumers. Codegen runs through the **`metaobjects`
4
+ console-script** (`pip install metaobjects`). As on every port, schema migrations
5
+ are **Node-`meta`-owned** (ADR-0015): `meta migrate` / `meta verify --db` run
6
+ through the Node `meta` tool — the Python CLI has **no `migrate` subcommand** and
7
+ `metaobjects verify --db` is rejected. Everything below is `metaobjects`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pip install metaobjects # provides the `metaobjects` console-script
13
+ # consumer runtime deps (you provide these — codegen does not pin them):
14
+ pip install "pydantic>=2" fastapi
15
+ ```
16
+
17
+ ## Run
18
+
19
+ ```bash
20
+ metaobjects gen ./metadata --out ./generated [--package <pkg>]
21
+ metaobjects gen ./metadata --out ./generated --generators entity,routes,filter-allowlist
22
+ metaobjects verify ./metadata --codegen # codegen-drift gate (regenerate into a
23
+ # temp dir + diff vs the committed --out tree)
24
+ ```
25
+
26
+ `metaobjects verify` defaults to `--codegen` (the codegen-output drift gate; it shares
27
+ the exact `gen` code path so the two can't diverge). `--templates` is the prompt/template
28
+ drift gate (see the prompts reference). Schema migration + live-DB drift are **not**
29
+ `metaobjects` — they run through the Node `meta` tool (see the migration reference).
30
+
31
+ ## Generators
32
+
33
+ Wire generators by their stable name (`--generators <names>`), or run the default set.
34
+ Output lands under `--out` (with the `@generated` guard header). Metadata is the same
35
+ canonical JSON every port reads (fused-key form, `source.rdb` + `@table`, `@column` for
36
+ a renamed physical column).
37
+
38
+ | Stable name | Output |
39
+ |---|---|
40
+ | `entity` | one **Pydantic model** per `object.entity` / projection (the `entity-model` generator): typed fields from the metadata, nullability from `@required`, `@maxLength`/validators, enum fields → a Python `Enum`. This is the typed data model. |
41
+ | `routes` | a **FastAPI `APIRouter`** per writable entity (`source.rdb @kind="table"`) on the cross-port REST contract (`?filter[field][op]=`, `?sort=field:asc`, `?limit`/`?offset`, `?withCount=1` envelope, 400/404 envelopes). The router declares a repository **`Protocol`** you implement and inject. |
42
+ | `filter-allowlist` | per-entity filter allowlist (FR-009 — the server-side field+operator allowlist the routes validate against). |
43
+ | `payload` / `output-parser` / `output-prompt` / `extractor` / `render-helper` / `trace-helper` | the `template.output` prompt-pillar artifacts — see the **prompts** reference. |
44
+ | `template` | the generic Mustache `template` primitive. |
45
+
46
+ ## No ORM — you own persistence (unlike the C# port)
47
+
48
+ Python codegen emits the **Pydantic models + the FastAPI routers**, but **no ORM /
49
+ persistence layer and no runnable server**. Two things you hand-write:
50
+
51
+ 1. **The repository** — each generated router depends on a repository `Protocol`;
52
+ implement it against your datastore (SQLAlchemy / asyncpg) and inject it.
53
+ 2. **The app entrypoint** — there is no generated `main.py`. Create one and mount the
54
+ routers:
55
+ ```python
56
+ from fastapi import FastAPI
57
+ from generated.author_router import router as author_router
58
+ app = FastAPI()
59
+ app.include_router(author_router)
60
+ ```
61
+
62
+ ## Known gaps (current — may require a hand-edit)
63
+
64
+ - **Single-field, `int` PKs only.** The generated router/repository assume a single
65
+ `int` primary key (`id: int`). Non-`int` single-field PKs and composite PKs need a
66
+ hand-edit until specified.
67
+ - **DTO = `dict[str, Any]`.** Request bodies for `POST`/`PATCH`/`PUT` are typed
68
+ `dto: dict[str, Any]` and responses return `Any`; the repository `Protocol` uses
69
+ `Any` for the row type. The typed Pydantic model from the `entity` generator exists —
70
+ you can tighten the router signatures to it by hand.
71
+
72
+ ## Re-scaffold this context
73
+
74
+ `metaobjects agent-docs --server python [--out <dir>]` (re)scaffolds the slim always-on
75
+ Markdown + these `metaobjects-*` skills into the project — the Python tool bundles the
76
+ agent-context tree, so a Python consumer needs no Node `meta`.
@@ -129,6 +129,10 @@ Generated files carry an `@generated by @metaobjectsdev/codegen-ts` header; the
129
129
  runner overwrites those and refuses to touch files without it. Hand-customizations
130
130
  that metadata can't express live in sibling `<Entity>.extra.ts` files.
131
131
 
132
+ **Output format:** `meta gen` (and the CLI generally) is TTY-aware — human-readable
133
+ text on a terminal, TOON on a pipe or agent. Override with `--format toon|json|text`.
134
+ TOON is the structured default for agents; `--format json` is also available.
135
+
132
136
  ## Multiple output targets
133
137
 
134
138
  A `targets: { web: { outDir }, api: { outDir } }` registry plus a per-generator
@@ -37,9 +37,9 @@ can't drift by construction).
37
37
  - **`--db`** — schema drift. Introspects the live database and fails if it has
38
38
  diverged from metadata. This is a **schema concern, so it is the Node toolchain's
39
39
  job regardless of your server language** (see migrations below). On the JVM ports
40
- a runtime startup validator catches generated-table drift at app boot as a
41
- complementary check, but the authoritative DB-vs-metadata gate is the Node
42
- `verify --db`.
40
+ a runtime startup validator *can* catch generated-table drift at app boot as an
41
+ optional complementary check (if your project wires one), but the authoritative
42
+ DB-vs-metadata gate is the Node `verify --db`.
43
43
 
44
44
  - **`--codegen`** — regeneration drift. Re-runs generation and diffs the result
45
45
  against the committed generated files; a non-empty diff means someone edited
@@ -21,8 +21,45 @@ npm install --save-dev @metaobjectsdev/cli @metaobjectsdev/migrate-ts
21
21
  You point the tool at the **same database your server connects to** — its
22
22
  connection is independent of your runtime tier.
23
23
 
24
+ ## Output format
25
+
26
+ `meta migrate` (and the CLI generally) is TTY-aware: when stdout is a terminal it
27
+ emits human-readable text; when piped to an agent or CI system it defaults to TOON
28
+ (a compact, unambiguous machine-readable format). Override with `--format`:
29
+
30
+ ```bash
31
+ meta migrate ... --format toon # TOON (machine-readable, the pipe/agent default)
32
+ meta migrate ... --format json # JSON
33
+ meta migrate ... --format text # human-readable text (the TTY default)
34
+ ```
35
+
36
+ Structured errors and next-step hints are also emitted on stdout (not stderr) in the
37
+ active format, so callers can parse them without scraping stderr.
38
+
24
39
  ## The workflow
25
40
 
41
+ ### Fresh database: baseline first
42
+
43
+ The default `meta migrate` path is **offline** — it diffs metadata against a
44
+ committed schema snapshot rather than the live DB. On a fresh database there is no
45
+ snapshot yet; run the `baseline` step once before the first migration generate:
46
+
47
+ ```bash
48
+ meta migrate baseline --dialect sqlite # seed snapshot from metadata (no DB needed)
49
+ meta migrate baseline --dialect postgres # same for Postgres
50
+ meta migrate baseline --from-db --db postgresql://... --dialect postgres
51
+ # alternative: seed from live DB (for existing schemas)
52
+ ```
53
+
54
+ `baseline` writes a reference snapshot to `.metaobjects/migrations/` and exits
55
+ without emitting any SQL. After this, `meta migrate --dialect <d> --slug <name>`
56
+ operates offline against that snapshot.
57
+
58
+ If you run `meta migrate` before baselining, the CLI surfaces a structured
59
+ next-step hint pointing to the exact `baseline` command.
60
+
61
+ ### Generating a migration
62
+
26
63
  1. **Generate a migration** by diffing metadata vs the prior state (the live DB or a
27
64
  committed snapshot). The engine emits paired `up.sql` + `down.sql`:
28
65
 
@@ -6,7 +6,7 @@ MetaObjects is a metadata standard: typed metadata in `metaobjects/` is the dura
6
6
  spine; generated code is the disposable artifact. Regenerate with `{{codegenCommand}}`.
7
7
 
8
8
  ## Principles
9
- - Pattern-derivable from metadata = codegen, never hand-write (FKs, CRUD, validators, finders).
9
+ - Pattern-derivable from metadata = codegen, never hand-write FKs, CRUD, validators, finders, and the database schema and migrations. The schema is a disposable, generated artifact: change the metadata and regenerate, never hand-write SQL.
10
10
  - Never hand-edit generated files — change the metadata and regenerate (three-way merge preserves hand-written regions).
11
11
  - Use the generated constants for any string that names metadata.
12
12
  - The loaded metadata model is READ-ONLY — never inject nodes or mutate the tree at load time (no "enrich the model on load" hooks). Need an extra field/column? Author it in the metadata, or derive it during codegen (read the metadata, emit output). Mutating the loaded model makes it diverge from what's declared — a bad practice reserved for very rare cases.
@@ -1 +1 @@
1
- {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/agent-context/assemble.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AA4BzE,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,aAAa,EAAE,CAoCrF"}
1
+ {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/agent-context/assemble.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAiCzE,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,aAAa,EAAE,CAsCrF"}
@@ -13,7 +13,12 @@ function stackLine(contentRoot, stack) {
13
13
  const serverPart = stack.servers.length ? stack.servers.join(", ") + " server" : "no server";
14
14
  const clientPart = stack.clients.length ? stack.clients.join(", ") + " client" : "no client";
15
15
  return {
16
- line: `Stack: ${serverPart}, ${clientPart}; migrations are TS.`,
16
+ // Describe only what the stack actually declares — never assert a migration
17
+ // binding (the tool states invariants; the project states bindings). The
18
+ // "schema + migrations are metadata-derived" invariant lives in the template
19
+ // principle, and the always-installed metaobjects-verify/migration reference
20
+ // fragment carries the project-agnostic how. See issue #1.
21
+ line: `Stack: ${serverPart}, ${clientPart}.`,
17
22
  codegenCommand: meta ? meta.codegenCommand : "meta gen",
18
23
  };
19
24
  }
@@ -41,10 +46,12 @@ export function assemble(opts) {
41
46
  out.push({ path: `.claude/skills/${skill}/SKILL.md`, contents: body });
42
47
  const refDir = join(skillDir, "references");
43
48
  if (existsSync(refDir) && statSync(refDir).isDirectory()) {
49
+ // Deploy-all: every reference fragment is installed; the agent reads the
50
+ // one(s) matching its stack (SKILL.md points to them). Robust to
51
+ // stack-detection misses — a narrow/empty stack never starves the agent.
44
52
  const refs = readdirSync(refDir)
45
53
  .filter((f) => f.endsWith(".md"))
46
54
  .map((f) => f.replace(/\.md$/, ""))
47
- .filter((token) => stack.tokens.has(token))
48
55
  .sort();
49
56
  for (const token of refs) {
50
57
  out.push({
@@ -1 +1 @@
1
- {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/agent-context/assemble.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/agent-context/assemble.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaobjectsdev/sdk",
3
- "version": "0.11.6-rc.1",
3
+ "version": "0.12.0-rc.1",
4
4
  "description": "Workspace helpers and agent-docs utilities for MetaObjects projects.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -56,7 +56,7 @@
56
56
  "access": "public"
57
57
  },
58
58
  "dependencies": {
59
- "@metaobjectsdev/metadata": "0.11.6-rc.1",
59
+ "@metaobjectsdev/metadata": "0.12.0-rc.1",
60
60
  "zod": "^3.23.0"
61
61
  },
62
62
  "devDependencies": {
@@ -0,0 +1,31 @@
1
+ // Regenerate the agent-context conformance goldens from the assembler.
2
+ // Run after an intentional change to assemble() (e.g. deploy-all references):
3
+ // bun scripts/regen-agent-context-conformance.ts
4
+ import {
5
+ readFileSync, writeFileSync, mkdirSync, rmSync, existsSync, readdirSync,
6
+ } from "node:fs";
7
+ import { join, dirname } from "node:path";
8
+ import { assemble } from "../src/agent-context/assemble.js";
9
+ import { makeStack } from "../src/agent-context/resolve.js";
10
+
11
+ const CONTENT_ROOT = join(import.meta.dir, "../../../../../agent-context");
12
+ const CORPUS = join(import.meta.dir, "../../../../../fixtures/agent-context-conformance");
13
+
14
+ for (const name of readdirSync(CORPUS)) {
15
+ const dir = join(CORPUS, name);
16
+ if (!existsSync(join(dir, "stack.json"))) continue;
17
+ const spec = JSON.parse(readFileSync(join(dir, "stack.json"), "utf8")) as {
18
+ servers: string[];
19
+ clients: string[];
20
+ };
21
+ const stack = makeStack(spec.servers as never, spec.clients as never);
22
+ const files = assemble({ contentRoot: CONTENT_ROOT, stack });
23
+ const expDir = join(dir, "expected");
24
+ rmSync(expDir, { recursive: true, force: true });
25
+ for (const f of files) {
26
+ const out = join(expDir, f.path);
27
+ mkdirSync(dirname(out), { recursive: true });
28
+ writeFileSync(out, f.contents);
29
+ }
30
+ console.log(`${name} -> ${files.length} files`);
31
+ }
@@ -16,7 +16,12 @@ function stackLine(contentRoot: string, stack: Stack): { line: string; codegenCo
16
16
  const serverPart = stack.servers.length ? stack.servers.join(", ") + " server" : "no server";
17
17
  const clientPart = stack.clients.length ? stack.clients.join(", ") + " client" : "no client";
18
18
  return {
19
- line: `Stack: ${serverPart}, ${clientPart}; migrations are TS.`,
19
+ // Describe only what the stack actually declares — never assert a migration
20
+ // binding (the tool states invariants; the project states bindings). The
21
+ // "schema + migrations are metadata-derived" invariant lives in the template
22
+ // principle, and the always-installed metaobjects-verify/migration reference
23
+ // fragment carries the project-agnostic how. See issue #1.
24
+ line: `Stack: ${serverPart}, ${clientPart}.`,
20
25
  codegenCommand: meta ? meta.codegenCommand : "meta gen",
21
26
  };
22
27
  }
@@ -48,10 +53,12 @@ export function assemble(opts: { contentRoot: string; stack: Stack }): Assembled
48
53
 
49
54
  const refDir = join(skillDir, "references");
50
55
  if (existsSync(refDir) && statSync(refDir).isDirectory()) {
56
+ // Deploy-all: every reference fragment is installed; the agent reads the
57
+ // one(s) matching its stack (SKILL.md points to them). Robust to
58
+ // stack-detection misses — a narrow/empty stack never starves the agent.
51
59
  const refs = readdirSync(refDir)
52
60
  .filter((f) => f.endsWith(".md"))
53
61
  .map((f) => f.replace(/\.md$/, ""))
54
- .filter((token) => stack.tokens.has(token))
55
62
  .sort();
56
63
  for (const token of refs) {
57
64
  out.push({