Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions build-an-oracle/reference/bundled-plugins/flows.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

`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`](/build-an-oracle/reference/bundled-plugins/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.

Check warning on line 24 in build-an-oracle/reference/bundled-plugins/flows.mdx

View check run for this annotation

Mintlify / Mintlify Validation (ixoworld) - vale-spellcheck

build-an-oracle/reference/bundled-plugins/flows.mdx#L24

Did you really mean 'yjs'?

## When to use it

Expand All @@ -35,7 +35,7 @@

- Editing prose, pages, or BlockNote documents — use [`editor`](/build-an-oracle/reference/bundled-plugins/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`](/build-an-oracle/reference/bundled-plugins/domain-indexer).

Check warning on line 38 in build-an-oracle/reference/bundled-plugins/flows.mdx

View check run for this annotation

Mintlify / Mintlify Validation (ixoworld) - vale-spellcheck

build-an-oracle/reference/bundled-plugins/flows.mdx#L38

Did you really mean 'lookups'?

## Environment variables

Expand All @@ -43,7 +43,7 @@

| Var | Required | Description |
| --- | --- | --- |
| `MATRIX_BASE_URL` | yes (base schema) | Matrix homeserver base URL. |

Check warning on line 46 in build-an-oracle/reference/bundled-plugins/flows.mdx

View check run for this annotation

Mintlify / Mintlify Validation (ixoworld) - vale-spellcheck

build-an-oracle/reference/bundled-plugins/flows.mdx#L46

Did you really mean 'homeserver'?
| `MATRIX_ORACLE_ADMIN_USER_ID` | yes (base schema) | Admin Matrix user ID. |
| `MATRIX_ORACLE_ADMIN_ACCESS_TOKEN` | yes (base schema) | Admin Matrix access token. |

Expand Down Expand Up @@ -85,10 +85,10 @@
- `connect_steps` — wire an upstream output to a downstream input.
- `update_step` — per-block / delta edit that never disturbs sibling steps.

**Settings** — per-step mutators with narrow scope.

Check warning on line 88 in build-an-oracle/reference/bundled-plugins/flows.mdx

View check run for this annotation

Mintlify / Mintlify Validation (ixoworld) - vale-spellcheck

build-an-oracle/reference/bundled-plugins/flows.mdx#L88

Did you really mean 'mutators'?

- `set_step_inputs` — set or replace a step's static inputs.
- `set_step_conditions` — set `props.conditions` directly in the frontend evaluator's operator vocabulary.

Check warning on line 91 in build-an-oracle/reference/bundled-plugins/flows.mdx

View check run for this annotation

Mintlify / Mintlify Validation (ixoworld) - vale-spellcheck

build-an-oracle/reference/bundled-plugins/flows.mdx#L91

Did you really mean 'evaluator's'?
- `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.
Expand All @@ -104,8 +104,88 @@

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 the `FLOWS_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.

Check warning on line 107 in build-an-oracle/reference/bundled-plugins/flows.mdx

View check run for this annotation

Mintlify / Mintlify Validation (ixoworld) - vale-spellcheck

build-an-oracle/reference/bundled-plugins/flows.mdx#L107

Did you really mean 'evaluator's'?

## 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 with `qi/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**.

Check warning on line 113 in build-an-oracle/reference/bundled-plugins/flows.mdx

View check run for this annotation

Mintlify / Mintlify Validation (ixoworld) - vale-spellcheck

build-an-oracle/reference/bundled-plugins/flows.mdx#L113

Did you really mean 'templated'?

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

| Block | Sends from | Emits |
| --- | --- | --- |
| `qi/gmail.email.send` | Author's connected Gmail | `email.sent` |
| `qi/outlook.email.send` | Author's connected Outlook | `email.sent` |
| `qi/slack.message.send` | Author's connected Slack workspace | `message.sent` |

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`**

| Field | Required | Notes |
| --- | --- | --- |
| `recipient_email` | yes | Single recipient. |
| `body` | yes | Plain text unless `is_html` is `true`. |
| `subject` | no | Subject line. |
| `cc`, `bcc` | no | Comma-separated addresses. |
| `is_html` | no | Render `body` as HTML. |

**`qi/outlook.email.send`**

| Field | Required | Notes |
| --- | --- | --- |
| `to_email` | yes | Single recipient. |
| `subject` | yes | Subject line. |
| `body` | yes | Plain text unless `is_html` is `true`. |
| `to_name` | no | Display name for the recipient. |
| `cc_emails`, `bcc_emails` | no | Comma-separated addresses. |
| `is_html` | no | Render `body` as HTML. |

**`qi/slack.message.send`**

| Field | Required | Notes |
| --- | --- | --- |
| `channel` | yes | Channel ID or name, e.g. `#general` or `C0123456`. |
| `markdown_text` | no | Message body in Slack markdown. |
| `thread_ts` | no | Parent message timestamp to reply within a thread. |

### Authoring flow

1. The author connects Gmail, Outlook, or Slack **once** from the flow editor. The binding is stored on the template.
2. The author drops the corresponding block into the flow and fills its fields — literals or wires from upstream outputs.
3. 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:

```ts
import { setStepEventTrigger } from '@ixo/oracle-runtime';

setStepEventTrigger(doc, 'send_confirmation', {
fromStep: 'submit_form',
event: 'form.submitted',
});
```

`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.** `fromStep` must 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_flow` enforces at plan level (spec §2.3) is checked here: if the upstream step's action can't emit events, `setStepEventTrigger` throws and you should fall back to ordering (`after`) plus an input reference.
- **Setting the trigger back to `manual` clears the event trigger.** Call `setStepTrigger(doc, stepId, 'manual')` to reset.

From the agent's authoring tools, the same behaviour is exposed through `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:
Expand Down
Loading