Running a studyflow

Execute a studyflow end-to-end in the browser

The Runner is a companion to the Modeler app that walks a participant through a .studyflow diagram one node at a time. It loads the diagram, validates it, then traverses the flow from the StartEvent to the EndEvent, rendering each activity as a UI step.

Opening the runner

The runner lives at run.html (alongside the modeler at app.html). There are three ways to hand it a diagram:

  1. From the Modeler – click Run in the toolbar. The current diagram is serialized to local storage, the runner opens in a new tab, and the seed is passed through the URL.

  2. By URL – append ?studyflow_url=<absolute or relative URL> to fetch a hosted .studyflow file:

    run.html?studyflow_url=/assets/my-study.studyflow&seed=42
  3. By file upload – open run.html directly. A landing screen lets you choose a .studyflow/.bpmn/.xml file from disk.

The seed query parameter (integer) makes random branches deterministic, which is useful for pilot runs and reproducibility.

Launching a study

The runner accepts three URL query parameters:

Parameter Purpose
studyflow_url Absolute or relative URL of a hosted .studyflow file to fetch and run.
diagram_id Key of a diagram stored in the browser’s local storage. Used when the runner is launched from the modeler’s Run button; not useful across browsers or machines.
seed Integer RNG seed. Makes gateway draws (random/stratified branches) reproducible across runs.

studyflow_url and diagram_id are alternatives; if neither is given, the runner shows the file-upload landing screen.

What the runner does

After loading, the runner:

  1. Parses the diagram – both serializations are accepted, YAML .studyflow and legacy BPMN 2.0 XML – using the bundled studyflow + cognitive schemas (plus any optional extension schemas the diagram references).
  2. Pre-fetches the Behaverse runtime manifest if (and only if) the diagram contains a BehaverseTask. Other diagrams skip this network call.
  3. Validates the diagram. Each node kind contributes its own validator (missing required attributes, unsupported types, etc.). Issues are listed in the logs and the run is aborted with a phase=invalid status.
  4. Traverses the diagram starting at the StartEvent. Each node yields a job; the runner renders the corresponding component and waits for the participant to complete or skip it. On EndEvent, the run finishes with phase=done.

Gateway behavior:

  • RandomGateway / StratifiedAllocationGateway – pick one outgoing branch uniformly at random (seeded by ?seed). The stratified variant is currently treated as a random pick; stratification logic is reserved for future work.
  • Exclusive / Inclusive gateway with conditionExpression on an outgoing sequence flow – the first flow whose expression evaluates truthy wins. Conditions are evaluated against the runtime variable bag (nodes call setVariable(name, value) to write to it).
  • No matching condition – the gateway’s default flow is taken if set, otherwise the first un-conditioned outgoing flow, otherwise the first outgoing flow.
  • ParallelGateway – not yet supported; the runner throws.

Built-in node kinds

Node Matches Behavior
Start bpmn:StartEvent Renders consent screen if consentFormUri is set; otherwise advances immediately.
End bpmn:EndEvent Issues a completion code (none/static/dynamic) and redirects via redirectTo if set.
Instruction cognitive:Instruction Renders the markdown content; participant clicks Continue.
Questionnaire cognitive:Questionnaire Renders the chosen instrument (PHQ-9, GAD-7, BDI-II ship as built-ins) and stores responses.
Behaverse Task behaverse:BehaverseTask Embeds the Behaverse Unity runtime in an iframe and bridges messages.
Generic Task Any bpmn:Task / UserTask / ServiceTask / etc. Fallback step with a Continue button.

Other element kinds (data references, score gateways, sub-processes that aren’t traversed inline, etc.) are skipped at run time – they affect modeling and analysis, not execution.

What executes vs what is design-only

Not every element you can model has a dedicated runtime. The current support matrix:

  • Executed nativelyStartEvent (consent), EndEvent (completion code, redirect), Instruction, Questionnaire, BehaverseTask, and the gateways listed above.
  • Generic fallbackCognitiveTask, VideoGame, and Rest are design-time elements; at run time they render the generic task step (a Continue button), like any plain BPMN task.
  • Questionnaire instruments – only PHQ-9, GAD-7, and BDI-II ship as built-in forms. Other instrument values (STAI, PSS, custom IDs, …) fall back to the generic step.
  • ParallelGateway – unsupported; the runner raises an error during validation/traversal.

Configuring Behaverse tasks

A BehaverseTask carries instrument-specific YAML in its configurations property. The Timelines: section supports two styles:

  • Built-in by name – a timeline listed by name only (e.g. XCIT_NB_01) runs a timeline that ships with the Behaverse build.
  • Inline, merged over the baseline – a timeline that declares its own blocks is authored inline. At run time it is merged over the per-scene baseline configuration (Resources/<scene>.json), so you only author the fields that diverge from the defaults. New blocks should set Inherits: Default to pick up the baseline block parameters.

Behaverse tasks can also be driven by a bot instead of a human participant – see LLM and bot participants.

Recording data

The runner can stream run data to a Behaverse data server. Recording is controlled by the Record events toggle in the runner header – it is off by default (privacy first) and the choice is persisted in the browser’s local storage.

To record, configure a data server in the modeler’s Settings (API key; the base URL defaults to https://data.behaverse.org/v1); the study name is taken from the diagram. When the toggle is on and a server is configured, the runner:

  1. Creates a session on the server at the start of the run.
  2. Streams batched studyflow events – trial outcomes, questionnaire responses, and timings – as the participant progresses.
  3. Records a SHA-256 hash of the diagram source alongside the events, so every data point is traceable to the exact study version that produced it.
  4. PATCHes the session with the final status and completion code when the run ends.

If no server is configured (or the toggle is off), the run proceeds local-only – nothing leaves the browser and the study still works end-to-end. See src/runner/dataServer.ts and src/lib/core/runnerSettings.ts for details.

Adding a new node kind

The runner discovers node modules under src/runner/nodes/<kind>/index.tsx at startup. Each module calls registerNode(...) with a match predicate (typically extensionType: 'myschema:MyType'), a toJob(node) mapper, and a React Component. See src/runner/nodes/README.md for the full template – adding a new node kind only requires creating one new folder.

Logs and debugging

The Logs panel (top-right of the runner header) records parsing, validation, and per-node messages. The header also shows the current phase (loading, running, job:<kind>, done, aborted, invalid, error) and the seed if one was passed.

What’s next