The
flows plugin is not loaded by default even though it ships in @ixo/oracle-runtime. Wire it in explicitly via the plugins array (see Opt in). The bundled set in BUNDLED_PLUGINS does not include it.Summary
flows is a flow builder capability. The agent designs reusable flow templates — steps (action blocks), the data wired between them, conditions, schedules, assignees, and forms — and reads the live state of running flows. The agent never executes, signs, mints, holds a key, or enters a PIN; the user runs the flow in the portal, where signing and any state transitions happen.
It coexists with the editor plugin: flows are written as documents over the @ixo/editor Qi Flow engine, using oracle-runtime’s native yjs reads/writes. The plugin does not require editor to be loaded — it contributes its own tool surface.
When to use it
- User wants to build an automation/workflow from steps or action blocks.
- User wants to change a step’s inputs, condition, trigger, schedule, or assignee.
- User wants to know what an action needs (its inputs/prerequisites) before adding it.
- User wants to fill in a form or survey attached to a flow step.
- User wants to inspect a flow run, find out why a step failed, and fix the template.
When NOT to use it
- Editing prose, pages, or BlockNote documents — use
editor. - Actually executing, running, or signing a step — that happens in the portal, by the user. No transaction tooling lives here.
- IXO entity lookups — use
domain-indexer.
Environment variables
The plugin owns no env vars. It relies on the same admin Matrix credentials theeditor plugin reads from the core base env schema:
What it contributes
- Tools: a flow-authoring surface grouped into five buckets — see below.
- Sub-agents: none.
- Middleware: none.
- HTTP routes: none.
- Shared state: reads
state.spaceId/ current flow ref from the per-request runtime context; writes flow documents through the editor Qi Flow engine.
Tools
Discovery — learn what blocks exist and what they need before adding them.list_actions— list available action blocks (optionally filtered by tag).describe_action— return an action’s inputs, outputs, and prerequisites.list_referenceable_fields— list fields the agent can wire from prior steps.
check_link— verify a single field-to-input wiring between two steps.compatible_actions— find actions whose inputs match a step’s outputs.requirements— pure action lookup of required inputs.
read_flow— assemble the full flow document from its native sources.get_step— fetch a single step’s configuration and current state.flow_status— high-level status of the flow and each step.explain_step— explain why a step is in its current state.
validate_flow— run static checks against the current flow.create_flow— start a new flow template fromget_flow_template.add_step,remove_step,reorder_step— manipulate the step list.update_flow_meta— title, description, tags.connect_steps— wire an upstream output to a downstream input.update_step— per-block / delta edit that never disturbs sibling steps.
set_step_inputs— set or replace a step’s static inputs.set_step_conditions— setprops.conditionsdirectly in the frontend evaluator’s operator vocabulary.set_step_schedule— set or clear a step’s schedule.set_step_assignment— set or clear a step’s assignee.set_step_confirmation— toggle the user-confirmation gate before a step runs.set_step_trigger— configure the trigger that starts the flow.
set_form_schema— set or replace a step’s form schema.describe_form— return a form’s schema and current values.fill_form— fill or update form fields.
How the agent should behave
Follow a tight loop: discover → plan → confirm → build → hand off. One discovery pass, one short plan, one user confirmation, then build with the authoring tools. The plugin injects an operating guide into the system prompt while it is loaded — see theFLOWS_OPERATING_GUIDE exported from the package.
Conditions are written directly as props.conditions in the frontend evaluator’s operator vocabulary; the compiler’s verbatim operators never evaluate at runtime.
Delegated integration blocks
Delegated integration blocks let the template author connect their own Gmail, Outlook, or Slack account once at design time and have any runner of the flow send email or post to Slack on the author’s behalf. The runner never connects the integration and never holds the author’s credential — execution goes through an opaque server-side binding. Contrast this withqi/email.send, which sends a pre-registered templated email from the platform owner’s address. Delegated blocks send free-form content from the author’s own account.
Each block is side-effecting and delivers a real message. It runs when the runner clicks it, or automatically when a wired upstream block event fires — there is no slide-to-sign.
Available blocks
Every block declares a required
connection input port that carries the author’s opaque binding — set at design time when the author connects the integration. Runners never populate it.
Input fields
All other fields accept literals or references wired from upstream block outputs (for example, a recipient email pulled from a form’s submission).qi/gmail.email.send
qi/outlook.email.send
qi/slack.message.send
Authoring flow
- The author connects Gmail, Outlook, or Slack once from the flow editor. The binding is stored on the template.
- The author drops the corresponding block into the flow and fills its fields — literals or wires from upstream outputs.
- Runners open the flow and either click the block to send, or let it fire automatically from an upstream event (see below).
Chaining blocks with event triggers
To make a delegated block (or any step) run automatically when an upstream block emits an event, set an event trigger using the flows editor API:setStepEventTrigger writes the same trigger / triggerMode props the compiler produces for a block.event trigger, so the downstream step auto-runs the moment the upstream step emits the named event.
Rules to know:
- Use friendly step ids.
fromStepmust be a short step id (e.g.submit_form). Passing an internal block id (flow_block_*) is rejected. - Upstream action must be event-capable. The same rule
validate_flowenforces at plan level (spec §2.3) is checked here: if the upstream step’s action can’t emit events,setStepEventTriggerthrows and you should fall back to ordering (after) plus an input reference. - Setting the trigger back to
manualclears the event trigger. CallsetStepTrigger(doc, stepId, 'manual')to reset.
update_step via an onEvent patch (takes precedence over a trigger patch when both are given); set_step_trigger sets manual / flow-start and clearing to manual here also removes any event trigger.
Opt in
flows is opt-in. Add the plugin instance explicitly — the bundled loader will not load it for you:
editor plugin with a shared matrixClient, reuse it here so both plugins share the same long-lived sync.
Examples
User: “Build a flow that emails the applicant when their claim is approved.” The agent callslist_actions (tag: claims) to discover blocks, picks a submit/approve/email chain, confirms the plan, then create_flow + add_step + connect_steps + set_step_conditions to wire it up. The user runs the flow from the portal.
User: “What does the submit-claim step need before I can add it?”
The agent calls describe_action with action: 'qi/claim.submit' and reports its required inputs and prerequisites.
User: “Why did the second step of my flow fail?”
The agent calls flow_status followed by explain_step on the failed step to surface the error, then proposes an update_step or set_step_inputs fix on the template.
Where to read next
editor
The Qi Flow engine the builder writes against.
Shared state
spaceId and the per-request flow ref the tools key off.