Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Authoring with an LLM

The model is text with a published schema, and that is not an accident — it is the bet the product is built on. A binary project file cannot be diffed, reviewed, or written by a language model. This one can.

Give it three things

The schema. runtime model schema prints it. It is generated from the same types that parse your model, so it is exactly what the runtime accepts — not a description of it.

runtime model schema > app-model.schema.json

An example. The app repository’s northwind is small, complete, and exercises every part of the format. A model to imitate is worth more than a specification to infer from.

The error messages. This is the part people skip, and it is the one that makes the difference. Do not ask for a model and hope; ask for a model, run runtime model validate, and give the output back:

$ runtime model validate draft
error[M210]: `companyName` is a `string`, which has no bounded set of values
  --> modules/sales/metrics.yaml (metrics[0].labels)
  help: a label value becomes part of a time series' identity, so only `enum`
        and `boolean` attributes may be labels…

Every diagnostic names the file, the path, what is wrong and usually what to write instead. That is a loop a model can close on its own, and it is why the diagnostics get as much care as the features.

What works well

  • Domain modelling. Entities, attributes, associations, indexes. This is the part LLMs are genuinely good at, and the validator catches what they get wrong.
  • Filling in a shape. “Here is domain.yaml, write me the security.yaml with a role per department.” Mechanical and tedious, which is the ideal case.
  • Explaining an existing model. The whole thing is text, so it fits in a context window and reads as prose.

What to check by hand

Anything in security.yaml. A constraint that is subtly too permissive validates perfectly. runtime serve plus curl -H "Authorization: Bearer $TOKEN" .../api-doc/openapi.json shows what a role can actually reach — which is the check worth doing, because it asks the same policy compiler the requests do.

Decimals. An LLM will write precision: 10, scale: 2 without thinking about whether ten digits is enough for your largest figure. Validation cannot know that.

onDelete. The default is restrict, which is the safe one. A model that specifies cascade everywhere is one that will one day delete more than anybody intended.

What it cannot do

The schema describes the format, not your domain. It will happily let a model generate a beautiful, internally consistent application that models the wrong business. Validation says the YAML is correct; it does not say the model is right.

A note on the shape of the format

Two decisions exist specifically to make this work, and they are worth knowing because they look arbitrary otherwise:

  • No flatten anywhere in the format. Attribute parameters are flat siblings (type: string, maxLength: 120) rather than nested, because the nested form would make the schema stop rejecting unknown fields — so a typo would be caught by neither the parser nor the editor.
  • Every file names its own module: and schemaVersion:. Redundant with the directory it is in, and checked against it, so a file generated in isolation cannot be silently misfiled.