Authoring schemas

Extending the Studyflow language with new element types and attributes.

This page is for contributors extending the Studyflow language with new element types or attributes. If you are a researcher or pipeline author using the modeler, see the Elements reference instead.

Studyflow uses direct moddle YAML as the authoring format for schema definitions. The schemas live in src/assets/schemas/ and ship with the modeler:

Core structure

Studyflow moddle YAML files follow this top-level layout:

name: Core
prefix: core
description: Core BPMN extension for modeling research processes.
uri: http://behaverse.org/schemas/studyflow/v1   # version segment = studyflow format version
icon: https://example.org/schema-icon.png    # optional, shown in the modeler
xml:
  tagAlias: lowerCase
associations: []
enumerations: []
types: []
examples: []

The description is shown in the schema palette. The optional icon (URL or iconify <name>) appears next to the schema name. The uri is the stable identifier existing files are matched by – the core schema’s URI intentionally keeps studyflow even though its prefix was renamed to core.

Enumerations

enumerations define reusable closed value lists referenced from properties via type:.

enumerations:
  - name: CompletionCodeTypeEnum
    isAbstract: true
    description: How the completion code is generated when the study ends.
    literalValues:
      - name: None
        value: none
        description: No completion code is issued.
      - name: Static
        value: static
      - name: Dynamic
        value: dynamic

Properties typed with an enum can opt into free-text entry alongside the enum values by setting meta.editable: true.

Types and properties

Each moddle type defines a domain element plus the properties shown in the inspector. Two relationships compose types:

  • extends – pure mixin onto an existing BPMN class. Use it when you only want to add attributes to a BPMN base (e.g. extend bpmn:StartEvent with consentFormUri) without creating a new visual element.
  • superClass – class inheritance. Use it when defining a new concrete element. List the BPMN base first (e.g. bpmn:Task, bpmn:ExclusiveGateway, bpmn:DataStoreReference) and add bpmn:BaseElement so the inspector picks up the standard metadata fields.

Pair superClass with meta.bpmnType so the modeler knows which BPMN shape to render.

types:
  - name: StartEvent
    extends:
      - bpmn:StartEvent
    meta:
      icon: iconify bpmn--start-event
    properties:
      - name: consentFormUri
        description: Link to the consent form. Untick to skip the consent step entirely.
        isAttr: true
        type: String
        meta:
          pinned: false
          optional: true
          categories:
            - Privacy

  - name: RandomGateway
    description: Randomly assigns participants to one of the outgoing branches.
    superClass:
      - bpmn:ExclusiveGateway
      - bpmn:BaseElement
    meta:
      icon: iconify streamline-flex--dice-5
      bpmnType: bpmn:ExclusiveGateway
    properties:
      - name: algorithm
        isAttr: true
        type: studyflow:AssignmentAlgorithmEnum
        default: probabilistic
        meta:
          categories:
            - Assignment

Property modifiers

Property entries carry moddle behavior directly:

  • isAttr: true – serialized as an XML attribute in the BPMN XML form (most scalar properties). The YAML .studyflow format maps every property to a plain key regardless of this flag.
  • isBody: true – serialized as the element’s text body in the BPMN XML form. Used for free-form content like YAML configurations.
  • isMany: true – repeated property (rendered as a list in the inspector).
  • default – initial value.
  • redefines – override the type or default of an inherited property (e.g. redefines: bpmn:Process#isExecutable).
  • replaces – replace an inherited property entirely.

Studyflow-specific modeler behavior lives under meta on the property:

  • meta.pinned: true – always visible in the inspector summary.
  • meta.optional: true – the inspector shows a checkbox to opt the property in.
  • meta.editable: true – enum properties also accept free-text entries.
  • meta.categories: [Privacy] – tab the property lives under in the inspector.
  • meta.condition.language: json + meta.condition.body: { otherField: value } – visibility predicate; the property only appears when other fields match. A value of $set matches whenever the other field has any value.

Function calls (uses / with)

Any activity can declare the function that implements it, GitHub-Actions style. Two properties on the core studyflow:DataOperationActivity trait (which mixes onto every bpmn:Activity) carry the call:

  • uses – a scheme-prefixed reference, <scheme>://<ref>[@<version-or-digest>]. The runner recognizes python:// (an importable callable, e.g. python://[email protected]), docker:// (an image, e.g. docker://ghcr.io/lab/img@sha256:...), and https:// (a script URL). Other schemes are allowed but flagged as unresolved. The ref/version split happens at the last @, so docker digests parse correctly.
  • with – a YAML mapping of arguments passed to the function (GitHub Actions’ with: block), carried as the text body of a studyflow:With wrapper. The inspector edits it under the Execution tab and reveals it once uses is set.
uses: python://[email protected]
with:
  column: rt
  fn: median

In the BPMN XML form, uses is an attribute on the activity (studyflow:uses="...") and with is a <studyflow:with> child element holding the YAML as its body; both round-trip losslessly through the .studyflow YAML form. An activity that carries a uses value shows a function marker on the canvas. The reference runner resolves and validates the call (the uses grammar and that with parses as a YAML mapping) but does not execute it in the browser; execution is delegated to a downstream tool (a workflow engine, an evaluation harness, or a container runtime). See src/assets/examples/function_call_demo.studyflow for a worked example.

Examples

Schemas may define top-level examples entries that appear in the modeler create/append menus. Each entry uses object.type to identify the schema type to instantiate, plus any default property values to apply.

examples:
  - description: Preprocess EEG data for a single subject.
    object:
      type: MapData
      bpmn:name: Preprocess EEG (subject)
      bpmn:documentation: Preprocess EEG data, including filtering, artifact removal, and normalization.
      isDataOperation: true
      icon: iconify icon-park--eeg

Example mixins

examples[].object.mixins lets an example compose additional defaults from other types. This is useful when the example should behave like a specialized BPMN shape without changing the underlying schema class.

examples:
  - description: Preprocess EEG data for a single subject.
    object:
      type: MapData
      bpmn:name: Preprocess EEG (subject)
      bpmn:documentation: Preprocess EEG data, including filtering, artifact removal, and normalization.
      isDataOperation: true
      icon: iconify icon-park--eeg
      mixins:
        - bpmn:SubProcess
  • Use mixins for example-time composition, not for defining reusable schema inheritance. Reusable schema inheritance belongs on types[].superClass.

Nested subprocess flow elements

If an example resolves to bpmn:SubProcess, it may also declare examples[].object.flowElements to create internal nodes and connections together with the root subprocess.

examples:
  - description: Preprocess EEG data for a single subject.
    object:
      type: MapData
      bpmn:name: Preprocess EEG (subject)
      bpmn:width: 420
      bpmn:height: 180
      mixins:
        - bpmn:SubProcess
      flowElements:
        - id: eeg_filter
          type: MapData
          bpmn:name: Filter signal
          x: 70
          y: 65
        - id: eeg_clean
          type: MapData
          bpmn:name: Remove artifacts
          x: 240
          y: 65
        - bpmn:type: bpmn:SequenceFlow
          sourceRef: eeg_filter
          targetRef: eeg_clean

Examples may declare promoted attributes explicitly using schema attributes: definitions.

examples:
  - description: Preprocess EEG data for a single subject.
    attributes:
      param1:
        range: string
        description: Example-specific promoted attribute.
        ifabsent: "default_value"
    object:
      type: MapData
      bpmn:name: EEGPrep

These attributes are not added back onto the original schema class. Instead, the modeler generates an example-scoped derived moddle type for that specific example object, so the extra attributes persist in the saved diagram (both the YAML and the BPMN XML serializations) without changing other MapData examples or the base class definition.

If the same example also includes undeclared scalar properties such as param1: value1, those are inferred onto the same example-scoped derived type rather than onto the parent schema class.

Cross-schema references

Use the schema prefix to reference types from another schema, e.g. studyflow:YAMLString, studyflow:AssignmentAlgorithmEnum, studyflow:DataOperationActivity. The cognitive schema, for example, refers to studyflow:DataOperationActivity#isDataOperation when pinning the data-operation marker off for activities like CognitiveTask.

Common mistakes

  • Prefix mismatch: type references using the wrong prefix (for example core: vs local names, or the legacy studyflow: prefix).
  • Missing type: moddle properties without a type often fall back to string-like behavior and may produce unintended interfaces.
  • Mixing up extends and superClass: use extends to mix attributes onto an existing BPMN base; use superClass to define a new concrete type that inherits behavior.
  • Incorrect BPMN mapping: omit or misconfigure meta.bpmnType and the element may no longer map to the intended BPMN shape.
  • Invalid condition shape: malformed condition.body JSON disables conditional visibility.
  • Incorrect redefines owner: invalid targets are dropped.

Naming conventions

Property names follow camelCase (consentFormUri, completionCodeType), except where a type mirrors an external tool’s CLI one-to-one – e.g. PreprocessfMRI’s output_spaces matches the corresponding fMRIPrep flag verbatim so configurations can be copy-pasted.