Sevro

Module Authoring

Define data models with entities, attributes, methods, workflows, and triggers.

Modules are the unit of organization in Sevro. A module contains entities, workflows, and triggers. You define modules as YAML files and apply them with the CLI.

Module structure

name: my_module
entities:
  - ref: entity_name
    label: Entity Name
    description: Optional description
    attributes: [...]
    methods: [...]
    triggers: [...]
workflows:
  - name: workflow_name
    nodes: [...]
    connections: {...}

Entities

An entity is a type of thing in your system. Each entity has a ref (machine name), label (display name), and optional description.

entities:
  - ref: contact
    label: Contact
    description: A person in your CRM
    attributes: [...]
    methods: [...]

Attributes

Attributes define the data shape of an entity.

Field reference

FieldTypeRequiredDescription
refstringYesMachine name (snake_case)
labelstringYesDisplay name
descriptionstringNoHuman-readable description
typestringYesOne of: string, number, boolean, date, datetime, enum, reference
is_requiredbooleanNoReject saves when field is missing (default: false)
is_uniquebooleanNoEnforce uniqueness across all records of this entity (default: false)
default_valuestringNoDefault value applied on create if field is absent
allowed_values[]stringNoFor enum type — the valid values
target_entity_refstringNoFor reference type — the entity this points to
on_deletestringNoFor reference type — nullify, restrict, or cascade (default: nullify)
computed_expressionstringNoCEL expression — value is computed, read-only
validation_expressionstringNoCEL expression — must return true or save is rejected

Attribute types

TypeStored asExample
stringstring"hello"
numberint64 or float6442, 3.14
booleanbooltrue
datestring (RFC 3339 date)"2024-01-15"
datetimestring (RFC 3339 datetime)"2024-01-15T10:30:00Z"
enumstring (must be in allowed_values)"draft"
referencestring (record ID)"uuid-of-target"

Examples

attributes:
  - ref: email
    label: Email
    type: string
    is_required: true
    is_unique: true
    validation_expression: "record.email.contains('@')"

  - ref: status
    label: Status
    type: enum
    allowed_values: ["draft", "published", "archived"]
    default_value: "draft"

  - ref: created_at
    label: Created At
    type: datetime
    computed_expression: "now()"

  - ref: author_id
    label: Author
    type: reference
    target_entity_ref: user
    on_delete: nullify

Methods

Methods define how data changes. Every mutation goes through a method — there are no direct create/update endpoints.

Field reference

FieldTypeRequiredDescription
refstringYesMachine name
labelstringYesDisplay name
is_constructorbooleanNoIf true, this method creates new records
conditions[]stringNoCEL expressions — all must be true to proceed
parameters[]objectNoInput parameters the caller must provide
actions[]objectYesField assignments to apply

Parameters

FieldTypeRequiredDescription
refstringYesParameter name
labelstringYesDisplay name
typestringYesOne of: string, number, boolean, date, datetime, enum
is_requiredbooleanNoCaller must provide this value
allowed_values[]stringNoFor enum type

Actions

FieldTypeDescription
targetstringThe attribute ref to set
expressionstringCEL expression — the value to assign

Examples

methods:
  # Constructor — creates a new invoice
  - ref: create_invoice
    label: Create Invoice
    is_constructor: true
    parameters:
      - ref: customer_name
        label: Customer Name
        type: string
        is_required: true
      - ref: amount
        label: Amount
        type: number
        is_required: true
    actions:
      - target: customer_name
        expression: "params.customer_name"
      - target: amount
        expression: "params.amount"
      - target: status
        expression: '"draft"'

  # Method — marks an invoice as paid
  - ref: mark_paid
    label: Mark Paid
    conditions:
      - 'record.status == "draft"'
    actions:
      - target: status
        expression: '"paid"'
      - target: paid_at
        expression: "now()"

  # Method — cancels an invoice
  - ref: cancel
    label: Cancel
    conditions:
      - 'record.status != "paid"'
    actions:
      - target: status
        expression: '"cancelled"'

CEL context

In conditions and actions, you have access to:

  • record — the current record's fields (e.g., record.status, record.amount)
  • params — the method parameters (e.g., params.customer_name)
  • now() — current timestamp
  • uuid() — generate a UUID

See the CEL reference for the full expression language.

Triggers

Triggers fire workflows automatically when events happen.

triggers:
  - event_type: on_create
    workflow_ref: notify_new_contact
  - event_type: on_update
    workflow_ref: sync_contact
    field_watcher: "email"  # only fires when the email field changes
  - event_type: on_delete
    workflow_ref: cleanup_contact_data

Cron triggers

triggers:
  - event_type: on_create  # event_type is required but ignored for cron
    workflow_ref: daily_report
    cron_expression: "0 9 * * *"  # every day at 9am

Workflows

Workflows are DAGs (directed acyclic graphs) of nodes connected by edges. They orchestrate multi-step processes that span entities, modules, and external services.

Node types

TypeDescriptionKey parameters
invoke_methodCall a method on a recordmodule, entity, method, record_ref, arguments
invoke_connectionCall an external APIconnection, action, arguments
evaluateEvaluate CEL expressionsexpressions (map of name → CEL)
branchConditional routingcondition (CEL, must return bool)
sleepPause for a durationduration (e.g., "30s", "5m")

Error handling

Each node declares an on_error policy:

on_error:
  abort: true        # stop the workflow (default)
  # OR
  skip: true         # log error, continue
  # OR
  retry:
    max_attempts: 3
    backoff: exponential  # constant | linear | exponential
    initial_delay: 1s
    max_delay: 30s

Example

workflows:
  - name: order_fulfillment
    description: "Fulfill an order end-to-end"
    input:
      type: object
      properties:
        order_id:
          type: string
    nodes:
      - id: validate
        name: "Validate Order"
        type: invoke_method
        parameters:
          module: commerce
          entity: Order
          method: validate
          record_ref: "$.input.order_id"
        on_error:
          abort: true
      - id: check_stock
        name: "Check Stock"
        type: invoke_method
        parameters:
          module: warehouse
          entity: Inventory
          method: check_availability
        on_error:
          abort: true
      - id: in_stock
        name: "In Stock?"
        type: branch
        parameters:
          condition: "$nodes.check_stock.output.available == true"
        on_error:
          abort: true
      - id: reserve
        name: "Reserve Inventory"
        type: invoke_method
        parameters:
          module: warehouse
          entity: Inventory
          method: reserve
        on_error:
          abort: true
      - id: notify_oos
        name: "Notify Out of Stock"
        type: invoke_method
        parameters:
          module: commerce
          entity: Order
          method: mark_backordered
          record_ref: "$.input.order_id"
        on_error:
          skip: true
    connections:
      validate:
        main:
          - node: check_stock
      check_stock:
        main:
          - node: in_stock
      in_stock:
        true:
          - node: reserve
        false:
          - node: notify_oos

Data flow

Nodes reference data from earlier nodes using CEL with path syntax:

  • $.input.<field> — workflow input
  • $nodes.<node_id>.output.<field> — output of a previous node
  • $nodes.<node_id>.error — error message if the node failed

Applying modules

# Create or update a module from a YAML file
sevro module apply -f module.yaml

# Export an existing module to YAML
sevro module export <module-id> -o module.yaml

# List modules
sevro module list

# Delete a module
sevro module delete <module-id>

sevro module apply is idempotent — if a module with the same name exists, it updates it; otherwise it creates a new one.

Import/export

Modules can be exported and imported via the admin UI or CLI:

  • CLI: sevro module export <id> -o file.yaml → sevro module apply -f file.yaml
  • UI: Module list → Export dropdown (JSON or YAML) → Import button

The YAML format uses snake_case field names matching the proto definitions. Exported YAML strips server-generated fields (IDs, timestamps) so it can be re-applied cleanly.

On this page