Visual Automation
Flowchart Builder
Build AI agent workflows visually. 19 node types, drag-and-drop editor, full access to native tools, LLM, and channels — no code required.
Overview
The Flowchart Builder lets you create complex AI agent workflows without writing code. Instead of building WASM extensions in Rust, you visually connect nodes in a drag-and-drop editor. Flowcharts can make HTTP requests, call LLMs, send messages through channels, execute any native tool, transform data, handle errors, and compose with other flowcharts via sub-flows.
Flowcharts are stored as JSON files and register their tools alongside native and extension tools. The LLM can call flowchart tools during conversations just like any other tool.
Node Types
19
Expression Operators
18
Auto-Trigger Types
3
Max Execution
500 nodes
Node Types
19 node types organized into 4 categories. Each node has a specific purpose and configurable properties.
Control Flow (6)
Entry point that receives tool parameters. Every flowchart tool starts with a Trigger node. Parameters are accessible downstream via $.params.
Evaluates a boolean expression and branches to "true" or "false" handles. Supports operators like ==, !=, >, <, contains, starts_with, matches, and boolean logic (&&, ||, !).
Multi-way branching. Evaluates an expression against a list of cases and routes to the matching case handle (case_0, case_1, ...) or a default handle.
Iterates over an array. Sets $var.loop_item and $var.loop_index for use in the loop body. Configurable max_iterations (default 100) to prevent infinite loops.
Combines data from multiple branches. Supports 3 strategies: merge_objects (deep merge), array_concat (flatten arrays), and first_non_null (coalesce).
Catches errors from upstream nodes. Placed anywhere reachable from the failing node. Returns a configurable fallback_value so execution can continue gracefully.
Actions (7)
Make HTTP/HTTPS requests (GET, POST, PUT, DELETE, PATCH, HEAD). Validates URLs and blocks private IPs. Supports custom headers, body templates, per-node timeout, and retry. Requires network.http permission.
Call the user's configured LLM provider with a prompt template. Supports {{expression}} interpolation in prompts. Configurable max_tokens. Requires ai.inference permission.
Send a message through any connected channel (Discord, Telegram, Slack, etc.). Template-expandable channel_id, recipient, and message. Requires channel.send permission.
Execute any of the 29 built-in native tools by name (exec, read_file, web_search, git, etc.). Tool name and parameters support template expansion. Full access to the entire native tool suite.
Invoke a tool from another flowchart. Enables modular, reusable workflow composition. Recursion is prevented with a depth limit of 10.
Read, write, or delete values from persistent extension storage. Template-expandable keys and values. No permission required.
Read user-set configuration values (stored with _config. prefix). Template-expandable key. No permission required.
Data (3)
Transform data with 4 modes: json_path (extract values), template (interpolate strings), regex (match patterns with capture groups), and json_build (construct objects from templates).
Assign a named variable for use in downstream nodes via $var.{name}. Value is evaluated from an expression. Useful for intermediate calculations and state.
Terminal node that returns the final result. Supports result_template (with JSONPath or {{}} interpolation) or a literal result_value. If no template is set, merges all node outputs.
Utility (3)
Pause execution for a specified duration. Capped at 30 seconds. Useful for rate limiting between API calls.
Emit a debug log message at configurable levels (info, debug, warn, error). Message supports {{}} template interpolation.
Annotation-only node for documentation. Does nothing at runtime. Rendered with a dashed border and sticky-note styling in the editor.
Expression System
Flowcharts use a powerful expression system for accessing data, interpolating strings, and evaluating conditions. Three evaluation modes are available.
Path Expressions (JSONPath)
Navigate through the execution context to access parameters, node outputs, and variables.
# Access tool parameters
$.params.name
$.params.user.email
$.params.items[0]
# Access node outputs by ID
$.nodes.http_1.body.data
$.nodes.transform_1.result
# Access named variables
$var.counter
$var.loop_item
$var.loop_index
# Literals
"hello" 42 3.14 true false null
Template Interpolation
Use {{expression}} to embed expressions inside strings. Templates are used in URL fields, message bodies, prompt templates, and more.
# URL with parameter interpolation
https://api.example.com/users/{{$.params.user_id}}
# LLM prompt with node output
Summarize this data: {{$.nodes.http_1.body}}
# Channel message
Alert: {{$.params.event_type}} from {{$.params.source}}
Condition Operators
Used in Condition and Switch nodes for boolean evaluation. Supports 18 operators.
Condition Examples
# Simple comparison
$.params.status == "active"
# Numeric comparison
$.nodes.http_1.status > 200
# String contains
$.params.message contains "urgent"
# Boolean logic
$.params.role == "admin" && $.params.verified == true
$.params.type == "a" || $.params.type == "b"
# Type checks
$.params.data is_array
$.params.name exists
!$.params.deleted
Visual Editor
The flowchart editor is built with React Flow and provides a full-featured visual programming environment.
Drag nodes from the palette onto the canvas. Connect nodes by dragging from output handles to input handles. Pan and zoom with mouse or trackpad.
All 19 node types organized into 5 categories. Click or drag to add nodes to the canvas.
Select a node to configure it. Dynamic inputs based on node type with inline validation for URLs, JSON, and variable names.
Collapsible panel on Condition, Switch, Transform, SetVariable, and Output nodes showing available expression patterns ($.params, $.nodes, $var).
Condition edges auto-label as "True"/"False". Switch edges label as "Case 0", "Case 1", "Default". Labels update as you connect nodes.
Select nodes and press Ctrl+C / Ctrl+V to duplicate them with new IDs. Pasted nodes are offset by 40px to avoid overlap.
Color-coded minimap showing all nodes. Each node type has a distinct color. Click to navigate to any area of the flowchart.
Real-time validation checks for missing nodes, disconnected graphs, invalid JSON config, and unreachable branches. Errors prevent saving; warnings are advisory.
Execution Engine
Flowcharts are executed by a native Rust engine that traverses the node graph asynchronously. The engine supports parallel branch execution, per-node timeouts, retries, and error handling.
Execution Flow
Tool call received (from LLM or auto-trigger)
↓
Resolve trigger node → store params in context
↓
Execute nodes along edges (sequential chains use loops)
↓
Fan-out: multiple outgoing edges execute branches in parallel
↓
Each action node: permission check → execute → store output
↓
On error: BFS search for reachable ErrorHandler → fallback
↓
Output node: evaluate result template → return value
Auto-Triggers
Flowcharts can be triggered automatically without a user or LLM initiating a tool call. Three trigger types are supported.
Event
Listens to the EventBus for specific event types (e.g., ChannelMessageReceived, UserJoined). Invokes the flowchart tool when a matching event fires, passing event data as parameters.
event_types: string[]
Schedule
Executes at regular intervals using a configurable timer. Minimum interval is 5 seconds. Graceful shutdown on stop. Useful for periodic checks, cleanup, and monitoring.
interval_secs: number (min 5)
Webhook
Registers an HTTP endpoint that triggers the flowchart when called. Request body JSON is passed as parameters. Supports GET, POST, PUT, DELETE methods.
path: string, method: string
"auto_triggers": [
{
"id": "at_1",
"trigger_type": "event",
"tool_name": "main",
"config": { "event_types": ["ChannelMessageReceived"] },
"enabled": true
}
]
Permissions
Action nodes that access external resources are permission-gated. Permissions are declared in the flowchart definition and checked at runtime via the PolicyEngine.
Testing & Debugging
The editor includes a built-in test panel for running flowcharts with sample parameters and inspecting execution traces.
Select the tool to test from the dropdown (flowcharts can define multiple tools)
Enter test parameters as JSON in the textarea
Click Run — the engine executes with tracing enabled
View the result (success output or error message) and execution time
Expand the Node Trace section to see every node that executed, in order
Each trace entry shows: sequence number, status (pass/fail), label, type, duration in ms, and any error message
Definition Format
Flowcharts are stored as JSON files in the flowcharts/ directory. Each file contains the full definition including nodes, edges, tools, permissions, and auto-triggers.
idUnique identifier in format flow.user.{name}. Used for sub-flow references and storage.
name / version / authorHuman-readable metadata. Version follows semver.
enabledWhether this flowchart's tools are registered with the agent. Toggle from UI without deleting.
tools[]Array of tool definitions. Each has a name, description, JSON Schema parameters, and trigger_node_id pointing to the entry Trigger node.
permissions[]Array of capability declarations (capability, reason, required). Same format as extension manifests.
auto_triggers[]Array of auto-trigger definitions (event, schedule, or webhook). Each has its own enabled flag.
nodes[]Array of node objects with id, node_type, label, position ({x, y}), and config object (varies by type).
edges[]Array of edge objects with id, source, target, source_handle, target_handle, and optional label.
viewportEditor viewport state ({x, y, zoom}). Preserved when saving so you return to the same view.
{
"id": "flow.user.greeting",
"name": "Greeting Bot",
"enabled": true,
"tools": [{ "name": "greet", "trigger_node_id": "trigger_1", ... }],
"nodes": [
{ "id": "trigger_1", "node_type": "trigger", ... },
{ "id": "llm_1", "node_type": "llm_request", ... },
{ "id": "output_1", "node_type": "output", ... }
],
"edges": [
{ "source": "trigger_1", "target": "llm_1" },
{ "source": "llm_1", "target": "output_1" }
]
}