Use the visual editor
This recipe walks through building or changing a workflow in the Meridian graph editor (the config plane), from opening a workflow in edit mode to a validated YAML save. It assumes you already know the workflow model — if you do not, start with your first workflow and keep the workflow DSL reference open.
The editor is the React Flow component in
apps/config-plane/app/components/WorkflowEditor.tsx, mounted by
apps/config-plane/app/page.tsx.
Open the editor
- From the workflow list, select a workflow and click Edit. This navigates
to
/?wf=<file>&edit=1and mounts the editor on the existing spec. - To start from scratch, click New. This navigates to
/?new=1&edit=1and mounts the editor on a blank spec (apiVersion: meridian/v3, a default trigger, no nodes). - In edit mode the workflow list pane disappears — the whole width goes to the palette, canvas, and inspector. Return to the list through the Workflows breadcrumb (the unsaved-changes guard will stop you if you have pending edits).
Know the three panes
- Left — palette. The AI assistant box, the trigger selector, and the node catalogue grouped by category.
- Centre — canvas. The toolbar (name, and in new mode a filename), the graph itself, and a status bar.
- Right — inspector. Context-sensitive: it shows the selected node's controls, or the simulation panel, or a hint when nothing is selected.
Set the trigger
- In the palette, pick an entry from the Trigger dropdown. Every workflow
has exactly one trigger; changing it replaces the
triggernode. - Changing the trigger removes any edges that started from the old trigger — re-wire downstream nodes to the new trigger's outputs afterwards.
Add nodes
- Filter the catalogue with the search box (matches label, description, and type id) if the list is long.
- Click a palette entry to drop the node on the canvas; it is selected automatically so you can configure it right away. The coloured dot marks the node's role (source, compute, gateway, human-task, agent, transform…).
- To place a node already wired to something, drag from a port into empty space instead — see Wire ports.
- Rename a node by selecting it and editing Identifier in the inspector;
the id is slugified to
[A-Za-z0-9_]and must be unique. Delete a node with the Delete button in the inspector or the Delete/Backspace key. Edges attached to it are pruned automatically.
Configure a node
Select a node; the inspector renders controls that depend on the node type:
- Config fields for static nodes (for example a human-task SLA), typed as text / number / boolean.
- Dynamic editors for the core transform and gateway primitives — a
From→Into picker for
transform.convert(filtered to conversions compatible with what is already wired), an object-type picker fortransform.make/transform.break, a condition field forflow.guard, and a case list forflow.switch. Condition fields autocomplete field paths and expect JEXL;mapinfers its item/result types from the wiring. See branch with guards and switch and loop with map.
Config edits recompute the node's ports and drop any edge whose socket no longer exists, so wire types after you finish configuring.
Wire ports
Grounding for the concepts here lives in wire ports and the dataflow model; the mechanics in the editor are:
Draw a connection
- Drag from an output handle to an input handle.
- The editor validates the connection against the resolved port types. An incompatible pair is rejected with an error message and no edge is created; a compatible one flashes a confirmation.
- An input accepts only one cable — a new connection replaces the previous one.
The exception is
after, a multi-branch join, which accumulates cables (see sequence with after and done).
Create a compatible node by dragging into space
- Drag from a port and release on empty canvas.
- A menu lists only nodes that fit: from an output, nodes that can consume
the type; from an input, nodes that can produce it. Flow ports (
after) are excluded from these suggestions. - Pick one — the editor creates the node, wires it, and infers dynamic types from the anchor port.
Insert a node on an existing link
- Hover an edge and click the ≡ button at its midpoint.
- Choose an action — insert a compatible
convert,break, ormakenode, or delete the link. The original edge is replaced by wiring through the inserted node.
Expose object ports (double-click)
An object-typed port shows a single socket. To wire its fields individually:
- Double-click the object port to expand it into one sub-port per field.
- Wire the sub-ports you need.
- Double-click any sub-port to collapse the group back into the single object socket.
The same expand/compose toggles are available as checkboxes under Split ports in the inspector. (Ports are re-registered on the fly when they change, so a freshly exposed sub-port is immediately connectable.)
Set fixed values and exposed parameters
Two inspector sections let you supply data without a cable:
- Fixed inputs — type a constant directly onto an unwired primitive/coded input port. Wiring a port hides its fixed-value control.
- Parameters as ports — tick a config field to expose it as an input port so it can be driven by the graph instead of a constant. Un-ticking it removes the port and any edge into it.
Read live validation
- Wiring is checked as you connect (type match, port existence).
- The status bar reflects overall state: saved, unsaved (edits pending), or invalid (last action produced an error). It also shows node and connection counts, and flags a brand-new workflow.
- This is only the editor's in-canvas feedback. The authoritative static checks run on save and in simulation; for the two layers of validation see two-level validation and validate a workflow.
Save (YAML round-trip)
- Set the workflow name in the toolbar. When creating a new
workflow, also set the filename — it must match
<name>.workflow.yaml(allowed characters[A-Za-z0-9._-]). - Click Save YAML (or Create workflow in new mode). The editor builds a
spec from the current graph and POSTs it to
/api/workflows/save, which validates it and writes the YAML file. - On rejection the errors are shown inline and nothing is written. On success
the current state becomes the new "saved" baseline (the guard disarms), and a
newly created workflow redirects to
/?wf=<file>&edit=1.
The saved YAML round-trips: reopening the file rebuilds the same graph, including node positions, split/exposed ports, and inline values.
The unsaved-changes guard
The editor snapshots the spec after the catalogue loads and compares it to the current graph. While they differ:
- Closing or reloading the tab triggers the browser's leave-confirmation.
- Clicking an internal link (breadcrumb, "View", a workflow in the rail) prompts a confirmation before navigating away.
Saving clears the pending state. If you want to discard changes instead, confirm the navigation away without saving.
Next steps
- Dry-run the graph before committing: simulate a workflow.
- Generate or restructure a workflow from a prompt: use the AI assistant.
- Add a review step: add human validation.
- Use an agent node: use agents in a workflow.
- Once saved, run and resolve and monitor executions.