Action Shape
An action has a name, typed parameters, a return type, optional metadata, and either abody or an external implementation.
Reading Data
Usesingle when the action needs one record. In HTTP contexts, a missing record is surfaced as a not-found response.
pageOf when the action returns a collection. A page exposes items, total, and offset. Iterate over page.items, not over the page object itself.
where filters support a limited comparison shape. The left side must be a model field or @id. The right side must be an in-scope value, such as an action parameter or local variable, an internal value such as @subject, or a plain string literal.
order by <field> when callers need a stable, user-defined ordering. Ordering supports one persisted scalar field or @id; asc is the default direction, and desc reverses it.
Building Nested Response Bodies
When an endpoint needs to return a parent object with related records nested inside it, query the parent record first, then query the child records and assign the child page’sitems array into the nested schema field.
GET /public/pages/alice returns a nested links array. Because links := links.items returns the queried ProfileLink records directly, each nested link includes the record fields returned by the API, such as id, title, url, position, page, createdAt, and updatedAt.
Writing Data
Usecreate Entity { ... } to insert a record. Use update record { ... } to patch fields on an existing record. Use delete record to remove one.
When you update a variable holding an entity instance, the variable is rebound to the updated instance, so returning the same variable returns the latest fields.
Strings
Use double-quoted strings for text. For dynamic text, prefer template string interpolation with${...} inside the string:
TEXT, NUMBER, or BOOLEAN. For entities, files, pages, and other structured values, interpolate a specific scalar field such as ${task.title} rather than the whole value.
The + operator can concatenate two text-compatible operands, such as TEXT, EMAIL, PHONE_NUMBER, ADDRESS, or URL, and can include NUMBER or BOOLEAN on the other side. Keep each + expression binary. Do not write long chains such as "Task: " + task.title + ", categories: " + categoryNames; use a template string, split the expression into steps, or parenthesize each binary pair.
Control Flow
SLang supports:if/elsefor item in arraywhilebreakandcontinue- boolean logic with
and,or, andnot - arithmetic and comparisons for compatible primitive values
assert(description := "...", rule := condition) when an action should fail unless an invariant is true.