Chapter 08
Reference
Everything the language offers, on one page. The authority is
language/appwithai-language.json — when this page and that file disagree, the file wins.
Directives
| Directive | Form | Purpose |
%%meta | %%meta <key>: <value> | Section metadata: name, kind, version, entity, stack. |
%%enum | %%enum Name: a, b, c | A closed vocabulary, reusable by fields and states. |
%%field | %%field E.col enum: Name | Field metadata: enum, ui, default, min, max, help, format. |
%%entity | %%entity E audited: true | Entity metadata: prefix, audited, softDelete, label, icon. |
%%index | %%index E(a, b) [unique] | An index over one or more columns. |
%%category | %%category name: X; icon: Y; entities: A, B | Dashboard grouping. ;-separated keys; only name required. |
%%rule | %%rule name on E event: <hook> priority: <n> | Binds a decision flowchart to an entity and lifecycle event. |
%%action | %%action name <type> when: <expr> … | A side effect a rule emits. See below. |
%%workflow | %%workflow Name entity: E kind: <hook|state|saga> | Names and classifies a workflow section. |
%%hook | %%hook <type> <handler> on E[field: c] | Binds a handler to a lifecycle event. |
%%step | %%step <node> <StepType> <k>: <v> … | Binds a saga flowchart node to an executable step. |
%%rbac | %%rbac role:a|b on E.op | Restricts an operation or transition to roles. |
%%trigger | %%trigger cron:0 7 * * * -> handler on E | An event source: cron:, webhook:, message:. |
%%guard | %%guard field <op> <json> | An automation condition (the builder's dialect). |
%%loop | %%loop L1 while: f <op> v max: n | Repeat-while inside an automation. max: is required. |
Types
| Canonical | Aliases that normalize to it |
string | varchar, char, uuid, guid, id, email, url, phone, password, color |
text | longtext |
integer | int, bigint, smallint |
decimal | number, float, double, money, amount |
boolean | bool |
date | — |
datetime | timestamp, time |
json | jsonb, object, array |
Length is written on the type: string(120) display_name.
Modifiers
| Modifier | Effect |
PK | Primary key; unique; auto-added as string id PK if absent. |
FK | Foreign key; the target is derived from the column name. |
UK / UNIQUE | Unique index. |
OPTIONAL / NULL | Nullable. Everything is required by default. |
Cardinalities
| Operator | Kind | Example |
||--|| | one to one | User ||--|| Profile : has |
||--o{ | one to many | Account ||--o{ Contact : employs |
||--|{ | one to many (at least one) | Order ||--|{ OrderItem : contains |
}o--|| | many to one | Deal }o--|| Stage : in_stage |
}|--|| | many to one (at least one) | OrderItem }|--|| Order : belongs_to |
}o--o{ | many to many | Student }o--o{ Course : enrolls |
}|--|{ | many to many (at least one) | Author }|--|{ Book : writes |
|o--o| | zero or one, both sides | Employee |o--o| Desk : assigned |
Lifecycle hooks
| Hook | Phase · op | Typical use |
beforeCreate | before · create | Normalize, mint a number, set defaults |
afterCreate | after · create | Welcome email, emit an event |
beforeUpdate | before · update | Snapshot, transform, recompute |
afterUpdate | after · update | Sync outward, invalidate a cache |
beforeDelete | before · delete | Block a delete — return false |
afterDelete | after · delete | Clean up files or related rows |
beforeQuery / afterQuery | query | Tenant scoping; post-process results |
beforeRead / afterRead | read | Guard a record; redact fields |
beforeList / afterList | list | Filter or sort; annotate a page |
customValidate | validate · any | Cross-field validation — throw to reject |
Rule actions
| Type | Required | Optional |
trigger-workflow | workflow | message |
validation-error | message | — |
transform | field, value | message |
Saga step types
| Type | Required | Optional | Publishes |
Decision | one of decisionTable / rule | publish | One variable per output column of the matching row |
CreateEntity | entity, fields | as | The new row's id under as |
UpdateEntity | field + one of source/value | entity, targetField, targetSource | — |
DeleteEntity | — | entity, targetField, targetSource, hard | — |
Formula | target, operation | source, operand, value | Its result under target |
REST | url | method, bodyTemplate | — |
Formula operations: multiply, divide, add,
subtract (need source + operand), set (needs
value, stored unchanged — the only way to pass text), copy (needs
source).
Two syntax rules that bite
fields and decisionTable carry JSON and must be the last key
on the line. A value with a // in it — a URL — must have no space after its
key:, because properties split at whitespace before the next key:.
Checker codes worth recognising
| Code | Means | Do |
| EML114 | FK column does not end in _id | Rename it, or accept a plain string with no lookup |
| EML117 | Entity has no primary key | Add string id PK (auto-fixable) |
| EML262 | A step is missing a required property | Check the table above |
| EML264 | A step reads a variable nothing published | Publish it with as: / target:, or it is a column of the triggering row |
| EML265 | Cross-entity write with no row targeting | Add targetSource or targetField |
| EML272 | A decision row leaves an output unset | Give every row every column — the engine discards incomplete rows silently |
| EML284 | An action names a workflow that does not exist | Fix the name, or declare the workflow |
| EML286 | A trigger: rule saga nothing names | Add the action, or make it automatic |
| EML421 / EML424 | No initial state / a state with no path to a terminal | Fix the machine — a record will get stuck there |
| EML426 / EML427 | Enum and state machine disagree | Make the value sets identical |
| EML502 | An FK with no matching relationship | Declare the relationship; lookups depend on it |
Commands
| Command | Does |
bun language/checker.ts <file> | Check a model. --strict fails on warnings, --json for CI. |
bun language/cli/eml.ts info -i <file> | Summarise a model: entity, rule, workflow, hook and index counts. |
bun packages/generator/src/cli/generate.ts generate … | Generate an application. |
bun run db:setup | In a generated app: migrate, then seed. |
bun run dev | In a generated app: API and web together. |
bun run test:e2e:fast | The generated end-to-end suite, minus the volume tests. |
Where things live
| Path | What |
language/appwithai-language.json | The canonical language definition — the authority for everything on this page |
language/spec/ | The prose spec: ERD, rules, workflows, types, directives |
language/examples/crm.eml.mmd | The model this guide builds |
language/checker.ts | The checker |
packages/generator/src/parsers/mermaid.parser.ts | The ERD parser |
packages/generator/templates/ | Every template the generated app is made of |
generated-projects/crm/ | The application, as generated |