This document is the canonical reference for defining Nodes in Trellis. It reflects the v0.7+ Universal Action Semantics (“Duck Typing”).
The Node is the atomic unit of the conversation/flow.
We do not rely on rigid type fields (like type: tool). Instead, the properties you define determine the node’s behavior.
do? -> It is an Action Node. The Engine executes the tool.wait or input_type? -> It is an Input Node. The Engine pauses for user input.content? -> It renders text (Markdown).Note: You can mix behaviors, with constraints.
Content+Do= “Talk & Act” (e.g. “Loading…” + Init).Content+Wait= “Talk & Listen” (e.g. “Question?” + Input).- Forbidden:
Do+Wait(in the same node). You cannot act and listen simultaneously (state collision).
type: text # Optional. Inferred from behavior (Defaults to "text").
# --- Behavior: Action (The "Do") ---
do:
name: my_tool_name # Tool to execute
args: # Arguments passed to the tool
id: ""
# --- Behavior: SAGA (The "Undo") ---
undo:
name: revert_tool # Executed if flow rolls back
args:
id: ""
# --- Context Management ---
required_context: # Fails if these keys are missing
- "user_id"
default_context: # Fallback values
theme: "dark"
context_schema: # Type validation for context values
api_key: string
retries: int
tags: [string]
# --- Behavior: Input (The "Wait") ---
wait: true # Pauses for simple text input (Enter)
# OR
input_type: confirm # Pauses for typed input (e.g., [y/N])
input_options: ["A","B"]
save_to: my_variable # Saves input (or tool result) to Context
# --- Flow Control ---
to: next_node_id # Unconditional transition
# OR
transitions:
- condition: input == 'success'
to: success_node
- to: fallback_node
on_error: error_handler_node # Transition if Tool fails
# Signal Handlers
on_timeout: timeout_node # Syntactic Sugar for on_signal["timeout"]
on_signal:
interrupt: exit_node # Handle specific signals from THIS node
on_signal_default:
interrupt: global_exit # RECOMMENDED: Define on Root Node to handle signals across the entire flow.
quit: cleanup_node
timeout: "30s" # Max time to wait for input
In Markdown files, any text below the frontmatter is the content.
---
do: init_db
to: menu
---
**Initializing Database...**
Please wait while we set up tables.
In strictly structured files, use the content key.
id: start
do:
name: init_db
content: "Initializing Database..."
to: menu
Render a message and immediately execute a backend task. The transition happens when the task receives a Result.
# Loading Screen
content: "Checking credentials..."
do: check_creds
save_to: auth_result
transitions:
- condition: input.is_valid
to: dashboard
- to: login_fail
How it works:
check_creds.{"is_valid": true}.auth_result.input.is_valid is evaluated (True).dashboard.For interactions that require specific choices, use type: question (optional if behaviors are clear) or input_type: choice.
# Simple Yes/No
content: "Proceed?"
input_type: confirm
save_to: proceed
# Multiple Choice (Syntactic Sugar)
content: "Pick a color:"
options:
- "Red"
- "Blue"
transitions:
- condition: input == 'Red'
to: red_pill
Note on Options: The
optionslist impliesinput_type: choice. The engine presents these to the user (e.g. arrow keys in CLI).
If an action fails, on_error takes precedence over to.
do: critical_op
on_error: rollback_node
to: success_node
success_node.rollback_node.Define ad-hoc scripts inline (requires --unsafe-inline) or via tools.yaml.
# Ad-hoc execution (Dev Mode)
do:
name: quick_script
x-exec:
command: python
args: ["scripts/calc.py"]
TRELLIS_ARGS (v0.7.10+)All tool arguments are passed as a single JSON object via the TRELLIS_ARGS environment variable. This provides a unified, language-agnostic interface for tool execution.
Example Flow Node:
do:
name: greet_user
args:
name: ""
greeting: "Hello"
config:
debug: true
Tool Implementation (PowerShell):
$TrellisArgs = $env:TRELLIS_ARGS | ConvertFrom-Json
$Name = $TrellisArgs.name
Write-Output "Hello, $Name!"
on_signal_default)Define global signal handlers on your entry node (typically start.md) to handle signals like quit or interrupt from anywhere in the flow.
Example (start.md):
---
id: start
wait: true
to: menu
on_signal_default:
quit: "finish"
interrupt: "catch-interrupt"
---
# Welcome
Press Enter to begin...
How It Works:
/quit or presses Ctrl+C)on_signal handler for that signalon_signal_default on the entry nodeon_signal_default, transitions to the specified nodeErrUnhandledSignalUse Cases:
/quit to go to a cleanup nodeCtrl+C to save state before exitingBest Practice: Define on_signal_default on your root node (start) to provide consistent signal handling across your entire flow.
Trellis v0.7.10+ uses a tiered shutdown strategy (SIGTERM -> Grace Period -> SIGKILL). For tools to benefit from this, they should be “Good Citizens”:
SIGTERM (and SIGINT for local dev).stdout.Example (Python):
import signal
import sys
import json
def handle_shutdown(signum, frame):
# Perform cleanup here
sys.exit(0)
signal.signal(signal.SIGTERM, handle_shutdown)
# ... perform tool logic ...
print(json.dumps({"status": "success"}))
| Property | Type | Description |
|---|---|---|
do |
ToolCall |
Definition of side-effect to execute. |
wait |
bool |
If true, pause for user input (default text). |
content |
string |
Message to display to the user. |
options |
[]string |
Shorthand for choice input. Presents a menu. |
input_type |
string |
text (default), confirm, choice, int. |
input_default |
string |
Default value if user presses Enter. |
input_options |
[]string |
Options for choice input (Low-level). |
save_to |
string |
Context variable key to store Input or Tool Result. |
to |
string |
Shorthand for single unconditional transition. |
transitions |
[]Transition |
List of conditional paths. Evaluated in order. |
on_error |
string |
Target node ID if do fails. |
on_timeout |
string |
Syntactic sugar for on_signal["timeout"]. |
on_interrupt |
string |
Syntactic sugar for on_signal["interrupt"]. |
on_signal |
map[string]string |
Handlers for global signals (interrupt, timeout). |
on_signal_default |
map[string]string |
Global signal handlers (valid only on Root/Entry node). |
tools |
[]Tool |
Definitions of tools available to this node (for LLMs). |
undo |
ToolCall |
SAGA compensation action if flow rolls back. |
required_context |
[]string |
Keys that MUST exist in context or flow errors. |
default_context |
map[string]any |
Default values for context keys if missing. |
context_schema |
map[string]string |
Type constraints for context values (fail fast on mismatch). |
timeout |
string |
Duration (e.g. “30s”) to wait for input before signaling timeout. |
Use context_schema to validate types in the context before a node renders. Supported types:
string, int, float, bool[string], [int]context_schema:
api_key: string
retries: int
tags: [string]
If a value is missing or has the wrong type, execution fails with a ContextTypeValidationError.
When using input_type: confirm, Trellis follows the standard CLI convention:
yes (True) unless an explicit input_default is provided.y, yes, true, 1 (True) or n, no, false, 0 (False) are accepted.yes or no before being saved to save_to or evaluated in transitions.Implementation Example:
input_type: confirm
input_default: "yes" # Overrides convention to make Enter = True
on_denied: stop_flow
to: continue_flow