@metaobjectsdev/sdk 0.11.6 → 0.12.0
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.
- package/agent-context/skills/metaobjects-codegen/references/python.md +76 -0
- package/agent-context/skills/metaobjects-codegen/references/typescript.md +4 -0
- package/agent-context/skills/metaobjects-verify/SKILL.md +3 -3
- package/agent-context/skills/metaobjects-verify/references/migration.md +37 -0
- package/agent-context/templates/always-on.md.mustache +1 -1
- package/dist/agent-context/assemble.d.ts.map +1 -1
- package/dist/agent-context/assemble.js +9 -2
- package/dist/agent-context/assemble.js.map +1 -1
- package/package.json +2 -2
- package/scripts/regen-agent-context-conformance.ts +31 -0
- package/src/agent-context/assemble.ts +9 -2
|
@@ -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
|
|
41
|
-
complementary check
|
|
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
|
|
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;
|
|
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
|
-
|
|
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":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAkC,MAAM,YAAY,CAAC;AAIzE,SAAS,cAAc,CAAC,WAAmB,EAAE,MAAc;IACzD,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,CAAC,CAAC;IAC9D,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACrC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAe,CAAC;AAC3D,CAAC;AAED,SAAS,SAAS,CAAC,WAAmB,EAAE,KAAY;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxE,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;IAC7F,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;IAC7F,OAAO;QACL,IAAI,EAAE,UAAU,UAAU,KAAK,UAAU,
|
|
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.
|
|
3
|
+
"version": "0.12.0",
|
|
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.
|
|
59
|
+
"@metaobjectsdev/metadata": "0.12.0",
|
|
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
|
-
|
|
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({
|