Appearance
Pipeline editor
The pipeline editor is the large code area in the centre of the FlowPad workspace. It is the <pipeline-editor> custom element registered as PipelineEditorShell (projects/matrix-3/packages/flowpad/src/components/PipelineEditor.ts:201-327). Its actor — PipelineEditor — owns the current code string and the current mode (flow or lisp).
Two modes, auto-detected
The editor decides which language you typed by looking at the first non-comment line (PipelineEditor.ts:259-282):
ts
const trimmed = code.trim();
const withoutComments = trimmed
.split('\n')
.map(line => line.trim())
.filter(line => !line.startsWith(';'))
.join('\n')
.trim();
const isLisp = withoutComments.startsWith('(');
const newMode = isLisp ? 'lisp' : 'flow';The header label flips between JavaScript (Flow DSL) and LISP, and the editor border changes colour: blue (var(--mx-color-primary)) for Flow, green (var(--mx-color-success)) for LISP.
Flow DSL
Fluent JavaScript-like syntax built around flow():
js
flow()
.fromValue({ table: 'products', limit: 10 })
.viaRemote('./db', 'Query')
.mapLocal(rows => rows.filter(x => x.price > 50))
.mapLocal(rows => rows.map(x => ({ name: x.name, price: x.price })))Each chained call adds one stage to the execution plan:
| Call | Stage kind |
|---|---|
.fromValue(seed) | source — provides the initial value |
.viaRemote(mount, op) | remote-rr — request/reply against an actor |
.mapLocal(fn) | local-map — pure transform inside the page |
./db and ./scheme are relative addresses; they resolve to the current authority root's db / scheme mount. $TARGET and $CATALOG_TARGET are placeholder tokens — the runtime substitutes the page's targetMount (default: FLOWPAD-AUTHORITY/system.catalog).
LISP / Scheme
Anything beginning with ( is treated as a LISP expression. The editor wraps it for the VLM (Virtual LISP Machine) before executing:
js
const wrapped = `flow()
.fromValue({ "eval": null, "expr": "${escapedLispCode}" })
.viaRemote("${targetMount}", "eval")`;(PipelineEditor.ts:184-198.) Default target is ./vlm-eval.
The DSL's eval accepts both quoted S-expressions and Scheme-syntax source strings. See dsl/examples.ts for ~80 LISP examples covering arithmetic, lambda/letrec, pattern call/introspect, sandboxing, and live capability mint/revoke.
Run dispatch
Press Ctrl+Enter anywhere in the textarea, or click ▶ RUN in the toolbar above. Both routes call into the shell's _runCode handler:
ts
private _runCode(code: string) {
this.sendToSelf('requestRun', {
code,
mode: this._currentMode,
});
}requestRun is one of the editor actor's accepted ops; the actor re-emits it as a runRequested event that the parent shell forwards to FlowpadApp's runFromCode. FlowpadApp then:
- Compiles the source to a Canonical IR (
compileSourceToCanonicalIR,runtime/queryPipeline.ts). - Emits
flowStartedwith a generatedflowId. - Emits
executionPlannedwith{ language, irKind, adapterPath }so the status pane can render the plan. - Calls
executeCanonicalIR(executionContext, ir)against a derived_runnercontext. - Emits
flowCompleted(orflowError) with the final result, which ResultsPanel then turns into a result child.
The executor enforces per-stage timeouts (FlowpadApp.ts:336-340):
| Address shape | Timeout |
|---|---|
Cross-root (AUTHORITY/mount) | 30000 ms |
Mount contains vlm | 10000 ms |
| Anything else | 5000 ms |
Loading examples
Five built-in examples are coded into FlowpadApp and listed first in any introspection (FlowpadApp.ts:131-203): Basic Query, Filter & Map, Query Tree, Scheme Eval, Security Policy.
The much larger gallery comes from two places:
dsl/examples.ts— ~85 named DSL examples.src/projects/<id>/manifest.json— six bundled "projects" (database, federation, lisp, security, serialization, vlm), each with its own examples.
Click an example in the sidebar — the FlowpadSidebar emits exampleSelected with the example's endpointMount and source code. The shell forwards that to the editor as setCode, which fills the textarea and triggers mode detection.
Keyboard surface
| Key | Action |
|---|---|
Ctrl+Enter | Run the current code |
| Type any text | Saves to the actor as setCode |
| Click an example | Replaces the editor contents |
| Click Clear in the toolbar | Empties the textarea (sends clear op) |
Common DSL recipes
Pulled directly from dsl/examples.ts:
js
// Query and project
flow()
.fromValue({ table: 'products', limit: 20 })
.viaRemote('./db', 'Query')
.mapLocal(rows => rows.filter(x => x.price > 75))
.mapLocal(rows => rows.sort((a, b) => b.price - a.price))
// Introspect a target component (whatever $TARGET points to)
flow()
.fromValue({})
.viaRemote('$TARGET', 'introspect')
// Apply a theme by setting design tokens
flow()
.fromValue({ tokens: { 'color-surface': '#0f172a', 'color-primary': '#3b82f6' } })
.viaRemote('flowpad-page', '$tokens')See also
- Sidebar (actors, packages, examples)
- Running flows and reading results
- Actor integration and IR pipeline
Source:
projects/matrix-3/packages/flowpad/src/components/PipelineEditor.tsandprojects/matrix-3/packages/flowpad/src/runtime/queryPipeline.ts.