The notes a model needs to write Yoke that compiles.
Generated from the language definition for language 1.0.
These are the notes a model needs to write Yoke that compiles and lints clean: the shape of a source, the invariants the compiler and the ruleset enforce, and the vocabulary the grammar is closed by.
A source
- A FastYoke app is one Yoke source file.
app <slug> "Name" { tagline "…" category "…" icon <name> }opens it; a bare slug is the first-party idfastyoke.<slug>, a backticked slug (appcrm"CRM") is the app id verbatim. - Each
entity Name "Singular" plural "Plural" { … }lists its fields askey: typelines with modifiers such asrequired,label "…",pii,mask except Role, andallow Role, Other. The types:text,longtext,number,money USD,boolean,date,datetime,enum a, b, c,file,json,ref Other,sequence,computed <type> = <expr>. - An entity's lifecycle is its
workflow { initial S states A, B, S terminal Z event: A -> B }block. State names are PascalCase, exactly one isinitial,terminallists the states a job ends in, andCancelledis reserved: cancellation is the admin override, never a state or a transition (fsm/cancelled-state). - A transition is
event: From -> To, optionally guarded:requires field, other(the fields are present),when <expr>(a comparison over the record's own fields, e.g.when role == "manager" and notes < 5), orguard jsonlogic { … }. Events are snake_case verbs. A self-loop (From -> From) must carry a guard (fsm/unbounded-self-loop). A workflow may name its legal path withguarantee A -> B -> C: the first name is the initial state, the last is terminal, and each step has a transition. An edge that leaves that path or returns to it is markedaside. A self-loop is not a step of the guarantee.idempotency job, event, client_keynames the retry key, on the workflow or on one transition. A date, a datetime,timestamp, orevent_timestampis rejected.fail Otherafter the target names the other outcome of a model call.by Managernames who may fire the event. It is an actor list, and it is not a guard.invariant <expr>on the entity or inside the workflow is a contract. The expression is the one the language already has. - A transition's
dolines are effects; the verbs:append,update,delete,transition,spawn,webhook,run,algorithm,recompute,notify,schedule,infer,classify,extract,summarize. do infer "…" from field schema { name: text, score: enum low, high } timeout 5s into name, scorecalls the tenant's configured model with only the named fields. The schema uses field types exceptref,computed, andfile. A matching answer moves the job to the target and writesinto. Extra fields, a timeout, or text that is not the schema move it to thefailstate. Replay of the same idempotency key does not call the model again. Apiifield infromiseffect/infer-over-pii. A tenant that is not entitled reportseffect/infer-requires-eeand the engine refuses.do classify urgency from notes into urgency timeout 5s, and the same shape withextractorsummarize, is that same action. The name is the capability. The prompt lives in tenant policy or a package, so the workflow does not carry it, and lint does not call a model. The schema is the types of theintofields, or aschema { … }block when one is written. When no prompt is configured, the engine takes thefailstate and does not call a model.do infer "…"is the form that still prints a prompt string.- Queries are
query name(param: type) = select … from Entity where … sort … limit n. Pages arepage slug "Title" list [Entity] { … }orpage slug "Title" detail Entity { … }holding blocks;nav [a, b]andhome afollow.seed demo { Entity row { key: value } state S }seeds records; a bare word in a value names another seeded row. - A
view name (param: Entity, row: query) { … }is a reusable element tree;use name (args)mounts it from a page or another view. Inside a view only<param>.<field>and aneachvariable reach data (thisis unbound there). - Identifiers may contain
-between alphanumerics, so subtraction is written with spaces.//comments are allowed. Never add anengineblock: a tenant-authored app cannot carry one. A block type the registry does not know ispage/unknown-block-type.
Blocks and elements
A page or view body holds one block per line. Every head takes its subject, then options as <word> <value> in any order, then an optional #id pin, and any element takes a trailing when <expr> gate. A container's body is { … }. Anything else is the generic block <type> [#id] { <json config> }.
| Head | Renders on | Subject | Options |
|---|---|---|---|
list | list pages | Entity | columns, label, size, search, sort, layout |
board | list pages | schema | summary, label, hide, size, layout |
section | detail templates | "…" | — |
field | either | field | label, display |
related | detail templates | Entity | columns, label, sum, state, empty, sort |
jobs | detail templates | — | label, summary, updated |
action | either | "…" | on, confirm, help, permission, visible, enabled |
stat | either | "…" | — |
chart | either | "…" | kind |
card | either | — | title |
columns | either | — | — |
tabs | either | — | — |
text | either | expr | style, format |
badge | either | expr | colour |
image | either | expr | alt |
link | either | expr | — |
each | either | word | layout, columns |
use | either | view | — |
Examples
Three small sources. Each one compiles. The shipped catalogue is not this set.
Work order
A job moves along a legal path. A parts hold leaves that path and comes back.
app `field-service` "Field service" {
tagline "A service work order."
category "Operations"
icon box
tier free
brand primary #4f46e5
}
entity ServiceWorkOrder "Service work order" plural "Service work orders" {
notes: longtext
workflow {
initial Dispatched
states Dispatched, EnRoute, OnSite, Invoiced, Closed, PartsHold
terminal Closed
guarantee Dispatched -> EnRoute -> OnSite -> Invoiced -> Closed
idempotency job, event, client_key
dispatch: Dispatched -> EnRoute
arrive: EnRoute -> OnSite
note: OnSite -> OnSite when notes is not null
hold: OnSite -> PartsHold aside
release: PartsHold -> OnSite aside
invoice: OnSite -> Invoiced requires notes
close: Invoiced -> Closed
}
}
Approval
One role approves along the path, or denies and leaves it.
app `approvals` "Approvals" {
tagline "A request waits for one decision."
category "Operations"
icon check
}
entity Request "Request" plural "Requests" {
decision: enum approved, denied
reason: text
workflow {
initial Submitted
states Submitted, Approved, Denied
terminal Approved, Denied
guarantee Submitted -> Approved
idempotency job, event, client_key
invariant decision == "approved" or decision == "denied" or reason == ""
approve: Submitted -> Approved when decision == "approved" by Manager
deny: Submitted -> Denied when decision == "denied" aside by Manager
}
}
Ledger posting
A draft is posted, or voided. A posted entry stays posted.
app `ledger` "Ledger" {
tagline "Post an entry, or void the draft."
category "Finance"
icon book
}
entity Entry "Entry" plural "Entries" ledger {
amount: money USD
memo: text
side: enum debit, credit
workflow {
initial Draft
states Draft, Posted, Voided
terminal Posted, Voided
guarantee Draft -> Posted
idempotency job, event, client_key
invariant amount > 0
post: Draft -> Posted requires memo by Bookkeeper
void: Draft -> Voided aside by Bookkeeper
}
}
Reserved words
Never an identifier; a colliding name is written in backticks: and, app, asc, bridge, by, contribute, data, desc, do, else, entity, false, from, guard, having, in, is, like, limit, me, nav, not, null, offset, or, page, query, requires, rule, script, seed, select, sort, this, true, use, view, when, where, workflow.
Replying
- Reply with exactly one fenced ```yoke block holding what was asked for: the complete source when the ask is the app, or only the element lines of the addressed body when the ask is a body. Prose outside the fence is ignored; a second fence is a failure.
- Carry everything the ask does not name through unchanged, comments included. Keep the
appline's slug as it is. - A lint finding may carry
suggestion. Applysuggestion.opsas edit operations and lint again. Do not invent a JSON dialect (states: [A, B],from:) and do not rewrite the file by hand whenopsis present. A finding withoutsuggestionhas no single safe repair.