Resource file reference
Resource file reference
This page describes how Mesh will work, not how it works today. It is a live spec of the developer experience, written before the code. Mesh is not released: nothing here can be installed or run yet, and any detail may change.
These tags are the current draft of the Mesh resource-file vocabulary. They can change, be renamed or be removed without notice. Nothing reads these files yet except the parser’s contract check.
A resource file is a .mx file in Marko syntax, parsed by MX. Mesh chooses the tag names. The contracts in packages/compiler/src/contracts.ts describe each tag. They take effect when a file is parsed with parseData from @mxlang/data using the options structural: "reject" and unknownTags: "reject" (packages/compiler/test/helpers.ts shows the call). With those options, an unknown tag or a tag in the wrong place is rejected. Every contract is closed, so an attribute or child tag that is not listed here is an error.
The names are Ash’s names in kebab-case with a trailing ? dropped (belongs_to is belongs-to, allow_nil? is allow-nil). No tag or attribute name ends in ?, by the operator’s ruling of 2026-10-04, and none contains _. Names you choose yourself (an attribute called authorId) and everything inside an expression are not vocabulary and stay as written. A default attribute, such as resource="post", is written on the tag itself. Values Mesh reads statically must be literals. A bare identifier is rejected. The tags change, validate, filter, authorize-if and value are tags whose default attribute is a function.
Each file is expected to have one resource at the root. The contracts cannot express that, so a later stage will enforce it. Nothing does yet.
resource
The root tag. Parent: file root.
| Attribute | Required | Meaning |
|---|---|---|
default (resource="post") |
yes | Resource name |
table |
no | Table name |
domain |
no | Domain the resource belongs to |
Children: attributes (required); relationships, actions, policies, calculations, aggregates (optional). Empty names are rejected.
attributes
Container for the data fields. Parent: resource. Children: uuid-primary-key, attribute (repeatable), create-timestamp, update-timestamp (each at most once). It may be empty today; whether a resource needs an attribute is a later model rule.
uuid-primary-key
Default attribute: the field name (required).
attribute
| Attribute | Required | Meaning |
|---|---|---|
| default | yes | Field name |
type |
yes | One of string, integer, float, boolean, atom, uuid, datetime |
constraints |
when type is atom |
An object literal with one_of, the list of allowed strings (constraints={ one_of: ["draft", "published"] }). Not allowed for other types. one_of is non-empty, with no blanks and no repeats. No other constraint is known yet |
allow-nil |
no | Boolean. Nullable unless allow-nil=false |
public |
no | Boolean flag |
default |
no | Literal that fits type: an integer for integer, a number for float, one of one_of for atom |
create-timestamp, update-timestamp
Default attribute: the field name (required), for example create-timestamp="insertedAt". No other attributes.
relationships
Container. Parent: resource. Children: belongs-to, has-many (both repeatable).
belongs-to, has-many
| Attribute | Required | Meaning |
|---|---|---|
| default | yes | Relationship name |
destination |
yes | Name of the related resource |
actions
Container. Parent: resource. Attribute: defaults, a list of built-in actions to generate, each one of create, read, update, destroy, no repeats, not empty (actions defaults=["read", "destroy"]). Children: create, update, read, destroy (each repeatable).
create, update, destroy, read
Each takes a default attribute (the action name, required). create, update and destroy also take accept, a list of attribute names without blanks or repeats (accept=[] is valid).
| Tag | Child tags |
|---|---|
create, update, destroy |
change, validate (repeatable) |
read |
filter, sort (each at most once), validate (repeatable) |
change, validate, filter, sort
change: default attribute is a function. Parents:create,update,destroy.validate: default attribute is a function;messageis an optional non-empty string. Parents:create,update,destroy,read.filter: default attribute is a function. Parent:read.sort: default attribute is a non-empty list of field names, no blanks or repeats. Parent:read.
policies
Container. Parent: resource. Child: policy (repeatable).
policy
The default attribute is the policy’s condition, required: a check call, or a list of check calls. The checks are action("publish") (an action name) and action_type("read") (one of create, read, update, destroy), each with exactly one string argument (policy=action_type("read"), policy=[action_type("update"), action("publish")]). The call names are JavaScript identifiers, so they keep Ash’s underscore. Needs at least one authorize-if child.
authorize-if
Default attribute is a function. Parent: policy.
calculations
Container. Parent: resource. Child: calculate (repeatable).
calculate
| Attribute | Required | Meaning |
|---|---|---|
| default | yes | Calculation name |
type |
yes | The attribute types except atom |
Needs one value child, a tag whose default attribute is a function.
aggregates
Container. Parent: resource. Child: count (repeatable).
count
| Attribute | Required | Meaning |
|---|---|---|
| default | yes | Aggregate name |
relationship-path |
yes | Name of the relationship to count |
Source
The authoritative definition is packages/compiler/src/contracts.ts, with its behaviour pinned by packages/compiler/test/contracts.test.ts. If this page and the file disagree, the file wins; please fix the page.