# Studio templates and actions

The places a document template may use, and the shape of an action declared on an object, as the Studio reads them.

A template turns one record into a document. An action is a button on a record page that changes the record in a stated way. Both are declared by an administrator and read by the Studio exactly as written here.

## Template places

A template is a record in the collection `studio.templates` with a title, the object it is for, and a body in Markdown. The body holds places for values. Nothing else is read: no expressions, no arithmetic, no conditions.

- `{{field}}`: The record's own field, written as the Studio draws it: words as themselves, a number as its digits, a date as stored, anything nested as its JSON. Nothing when the record lacks it.
- `{{#each related.<relationship>}} ... {{/each}}`: The block between is written once for each record at the other end of the named relationship, from this record and to it. Blocks do not nest.
- `{{related.<relationship>.field}}`: Inside that block only: the related record's field. Inside the block, {{field}} is still the record's own field.
- `Markdown`: Headings, paragraphs, bullet and numbered lists, quotes, rules, bold, italic and code are drawn in the document. Other Markdown is written as typed.
- `Limit`: A body is at most 20,000 characters, and a relationship fills at most 100 related records unless the Studio setting says otherwise.


**A discharge letter template**

```markdown
# Discharge summary for {{display_name}}

Admitted {{admitted}} to ward {{ward}}.

## Wards during the stay
{{#each related.admitted to}}- {{related.admitted to.name}} ({{related.admitted to.beds}} beds)
{{/each}}
Signed for {{display_name}}.
```


A template that names a field or relationship the object does not have is refused by name when it is saved and again when it is read, so a document is never produced with a hole. Filling a template writes nothing.

## Actions declared on an object

Actions are declared in the object's schema under `x-studio.actions`, so they are versioned, branched and merged with the object. The Studio reads at most 20 actions; a declaration that is not an action is named and left out. An action may be offered only when a condition on the record holds, written in the same condition language a page uses to show a component.

**x-studio.actions on an admissions object**

```json
{
  "x-studio": {
    "actions": [
      {
        "name": "close",
        "label": "Close the admission",
        "kind": "write",
        "set": { "status": "closed", "closed_at": "$now" },
        "roles": ["charge_nurse"],
        "when": { "field": "status", "test": "equals", "value": "open" }
      }
    ]
  }
}
```


- `name`: A letter or an underscore, then letters, digits and underscores. A page names the action by it. Two actions with one name: the second is not read.
- `label`: The button's words.
- `kind`: write. Actions that start an aion workflow or call a liminal subject are not read until the door serves action.run.
- `set`: The fields set and their values, at least one and at most 20. A value must be one the field's type holds: a choice among its choices, a whole number for a whole-number field. The one word $now is the instant pressed, written as a date (2026-10-14) for a date field and as the full instant otherwise; only a date, a date and time or a text field may be set to it.
- `roles`: The roles that may run it; everyone when left out. The Studio does not read roles yet, so every action is offered to everyone until it does.
- `when`: The condition on the record under which the action is offered, in the same condition language a page uses to show a component: a field, a test (equals, not_equals, one_of, greater, less, empty, not_empty, before, after) and a value, or all, any or not of those. Left out, the action is offered on every record. On a record that does not meet it the button is drawn disabled with the condition in words, and a run is refused not_offered after the record is re-read, so a stale page cannot run it.


## Run records

Every press of an action writes one record to `studio.action_runs` before the record is written, and writes its outcome after. The version that writes the run record carries the account of the person who pressed, as every version does. A record page's Runs component lists the runs on that record, the latest first, with how each ended.

- `id`: The collection, the document id, the action's name and the version the record was read at, joined with colons, so every run on one record is one prefix. One press of one action on one version is one run: a second press at that version finds this record and is refused already_run, so nothing is written twice. A run that ended refused may be pressed again.
- `record`: The collection and document id the action ran on.
- `action`: The action's name.
- `kind`: write.
- `started`: The instant pressed, as written by the browser's clock.
- `outcome`: started when first written; then done with the version the record was written as, or refused with the refusal's words. A record that changed between being opened and being pressed is refused, and nothing is written to it.
