Skip to main content
View as Markdown

Reusable Actions

The same step usually appears in several automations. A Slack alert, an audit-log write, a call to an internal API. Copying that step into each automation means every future change has to be made in every copy.

app.actions is a library of named templates. Define the step once, with $variable placeholders where the inputs differ:

app.yaml
actions:
  - name: notify-slack
    action:
      type: http
      operator: post
      props:
        url: $env.SLACK_WEBHOOK_URL
        body: { text: '$message' }

Then invoke it from any automation with a ref action, passing the values:

app.yaml
automations:
  - name: order-alert
    trigger: { type: record, table: orders, events: [create] }
    actions:
      - name: alert
        $ref: notify-slack
        $vars: { message: 'New order recorded.' }

Template Properties

Property Description
name Unique kebab-case identifier used by $ref. Starts with a lowercase letter, max 100 characters. Required.
action The step the template runs: any type and operator pair an automation step accepts. Required.
variables Default values for the template's placeholders. Each call site may override them with $vars.
aiAccess Exposes the template to AI clients as the MCP tool {app}_action_{name}, with parameters derived from variables.

Invoking a Template

The ref action is the only action with no operator. It carries a reference and, optionally, the values for this call site:

Property Description
$ref Name of the template to invoke. Must match a template in app.actions.
$vars Values for this invocation. Merged over the template's variables defaults, which they override.
name Step name recorded in run history. The call site's name is kept, not the template's.

Writing type: ref is optional. A $ref is unambiguous on its own, so { name: alert, $ref: notify-slack } and the explicit { name: alert, type: ref, $ref: notify-slack } are the same action.

Variables

A placeholder is a $ followed by an alphanumeric name ($message, $channel). At invocation, the merged variables supply the values:

Rule Detail
Where they resolve In any string value, at any depth inside the template's action block.
Precedence $vars at the call site wins over the template's variables defaults.
Unknown names Left untouched, so $env.SLACK_WEBHOOK_URL and {{trigger.data.id}} survive substitution.

That last rule is what lets a template mix all three reference families. Declare the defaults you want, and leave environment references and automation template variables to be resolved later by their own engines.

The same template with different variables produces different steps:

app.yaml
actions:
  - name: notify-team
    variables:
      channel: general
      message: Something happened.
    action:
      type: http
      operator: post
      props:
        url: $env.SLACK_WEBHOOK_URL
        body: { channel: '$channel', text: '$message' }

automations:
  - name: order-alert
    trigger: { type: record, table: orders, events: [create] }
    actions:
      - { name: alert, $ref: notify-team, $vars: { message: 'New order.' } }
      - { name: escalate, $ref: notify-team, $vars: { channel: ops, message: 'Check stock.' } }

Exposing a Template to AI

A template with an aiAccess block becomes a directly-invocable MCP tool. Its variables become the tool's parameters, so the same declaration that makes a step reusable also makes it callable:

app.yaml
actions:
  - name: archive-order
    variables:
      reference: ''
    action:
      type: record
      operator: update
      props:
        table: orders
        filter:
          conditions: [{ field: reference, operator: equals, value: '$reference' }]
        data: { archived: true }
    aiAccess:
      description: Archive one order by its reference.
      annotations: { readOnly: false, destructive: false, idempotent: true }

Whether the server actually mounts these tools is an operator decision, controlled by MCP_ENABLED. See MCP Server.

Validation

Rule Detail
Unique names A duplicate would make a $ref ambiguous, and it is rejected when the config is decoded.
ref is reserved It collides with the context.actions.ref() method exposed to code action bodies, and is rejected by name.
References resolve A $ref naming a template that does not exist is caught at startup, before the automation can run.

Last updated August 11, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.

Built with Sovrium