Maneuver: Flow DSL Orchestration
Declarative multi-agent workflows with dynamic execution patterns
Table of Contents
- Overview
- Quick Start
- Flow DSL Syntax
- Execution Patterns
- Configuration
- CLI Commands
- Visualization
- Error Handling
- Performance
- Best Practices
- API Reference
- Troubleshooting
Overview
Maneuver is a declarative Battalion orchestration pattern that uses a Flow DSL (Domain-Specific Language) to define complex agent execution patterns. Unlike other Battalion patterns that require explicit code, Maneuver allows you to express workflows as simple text expressions.
Key Features
- Declarative Syntax: Define workflows as text expressions (
agent1 -> agent2) - Mixed Patterns: Combine sequential and parallel execution in a single flow
- Visual Feedback: ASCII and Mermaid.js visualization of flow graphs
- Type-Safe Parsing: Compile-time validation of flow expressions
- Commander Integration: Automatic pattern detection for "flow" keywords
Comparison with Other Patterns
| Pattern | Definition Style | Flexibility | Complexity | Visualization |
|---|---|---|---|---|
| Formation | Programmatic | Sequential only | Low | ❌ |
| Phalanx | Programmatic | Parallel only | Low | ❌ |
| Campaign | Graph/DAG | High | High | Limited |
| Maneuver | DSL Text | High | Medium | ✅ ASCII/Mermaid |
Quick Start
Installation
Maneuver is included in paladin-battalion. Add it to your workspace:
[dependencies]
paladin-battalion = { version = "0.5.0", path = "crates/paladin-battalion" }
tokio = { version = "1.0", features = ["full"] }
Basic Example
use paladin_battalion::maneuver::service::ManeuverExecutionService;
use paladin_battalion::maneuver::Maneuver;
use paladin_battalion::maneuver::parser::FlowParser;
use std::collections::HashMap;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Define flow using DSL
let flow = FlowParser::parse("analyzer -> summarizer -> reviewer")?;
// Create Paladins
let mut agents = HashMap::new();
agents.insert("analyzer".to_string(), create_paladin("analyzer", "Analyze input"));
agents.insert("summarizer".to_string(), create_paladin("summarizer", "Summarize"));
agents.insert("reviewer".to_string(), create_paladin("reviewer", "Final review"));
// Create Maneuver
let maneuver = Maneuver::new("doc-workflow", agents, flow, Default::default())?;
// Execute
let service = ManeuverExecutionService::new(Arc::new(paladin_port));
let result = service.execute(&maneuver, "Document to process").await?;
println!("Final output: {}", result.final_output);
Ok(())
}
CLI Quick Start
# Create a Maneuver configuration
paladin battalion new my-workflow --type maneuver -o workflow.yaml
# Visualize the flow
paladin maneuver visualize -c workflow.yaml --format ascii
# Validate configuration
paladin maneuver validate -c workflow.yaml --verbose
# Execute the workflow
paladin battalion run -c workflow.yaml -t maneuver -i "Process this input"
Flow DSL Syntax
The Flow DSL uses a simple, intuitive syntax for defining agent execution patterns.
Basic Syntax
Sequential Execution
agent1 -> agent2 -> agent3
Output from agent1 flows as input to agent2, then to agent3.
Parallel Execution
(agent1, agent2)
Both agent1 and agent2 execute concurrently with the same input.
Note: Use commas (,) for parallel, not pipes (|).
Nested Patterns
agent1 -> (agent2, agent3) -> agent4
agent1executes first- Output flows to both
agent2andagent3(parallel) - Combined output flows to
agent4
Syntax Rules
| Element | Syntax | Example | Description |
|---|---|---|---|
| Agent | name | analyzer | Alphanumeric identifier |
| Sequential | -> | a -> b | Arrow operator |
| Parallel | , | (a, b) | Comma separator |
| Grouping | () | (a, b) | Parentheses for precedence |
Valid Examples
# Simple sequential
agent1 -> agent2
# Simple parallel
(agent1, agent2)
# Mixed nested
start -> (analyzer, reviewer) -> end
# Complex workflow
intake -> (technical, business, security) -> synthesis -> review
# Deep nesting
a -> (b -> (c, d), e) -> f
Invalid Syntax
# ❌ Pipe operator (use comma instead)
(agent1 | agent2)
# ❌ Missing parentheses for parallel
agent1 -> agent2, agent3
# ❌ Spaces in agent names
my agent -> another agent
# ❌ Empty groups
() -> agent1
# ❌ Trailing operators
agent1 ->
Execution Patterns
Sequential Pattern
Flow: agent1 -> agent2 -> agent3
Behavior:
- Execute
agent1with initial input - Pass
agent1output toagent2as input - Pass
agent2output toagent3as input - Return
agent3output as final result
Use Cases:
- Data transformation pipelines
- Multi-stage analysis
- Progressive refinement
Example:
// Flow: "extractor -> translator -> formatter"
let flow = FlowParser::parse("extractor -> translator -> formatter")?;
// Input: "Extract data from: <raw_text>"
// extractor output: "Data: {...}"
// translator output: "Translated: {...}"
// formatter output: "Formatted report: {...}" (final)
Parallel Pattern
Flow: (agent1, agent2, agent3)
Behavior:
- Execute all agents concurrently with same input
- Wait for all to complete
- Combine outputs (concatenation or custom logic)
- Return combined result
Use Cases:
- Multi-perspective analysis
- Expert panel reviews
- Parallel processing
Example:
// Flow: "(tech_reviewer, business_reviewer, security_reviewer)"
let flow = FlowParser::parse("(tech_reviewer, business_reviewer, security_reviewer)")?;
// All receive: "Review this proposal: {...}"
// Output combines all three perspectives
Nested Pattern
Flow: agent1 -> (agent2, agent3) -> agent4
Behavior:
- Execute
agent1with initial input - Pass output to both
agent2andagent3(parallel) - Wait for both to complete
- Combine their outputs
- Pass combined result to
agent4 - Return
agent4output as final result
Use Cases:
- Divide-and-conquer workflows
- Multi-faceted analysis with synthesis
- Complex decision trees
Example:
// Flow: "analyzer -> (summarizer, translator) -> reviewer"
let flow = FlowParser::parse("analyzer -> (summarizer, translator) -> reviewer")?;
// 1. analyzer processes input
// 2. summarizer + translator work in parallel on analysis
// 3. reviewer synthesizes both outputs into final result
Execution Order Visualization
Sequential: agent1 → agent2 → agent3
t₀ t₁ t₂
Parallel: agent1
↙ ↘
agent2 agent3
↘ ↙
(combine)
Nested: agent1
↓
┌───┴───┐
agent2 agent3
└───┬───┘
agent4
Configuration
Maneuver Configuration
use paladin_battalion::maneuver::{ManeuverConfig, ErrorStrategy, OutputFormat};
use std::time::Duration;
let config = ManeuverConfig::new()
.with_error_strategy(ErrorStrategy::ContinueParallel)
.with_output_format(OutputFormat::Concatenate)
.with_pass_output_as_input(true)
.with_timeout(Duration::from_secs(300))
.with_timing_metrics(true);
let maneuver = Maneuver::new("workflow", agents, flow, config)?;
Error Strategies
pub enum ErrorStrategy {
/// Stop immediately on first error
FailFast,
/// Continue parallel branches but fail sequential chains on error
ContinueParallel,
/// Log errors but continue execution regardless
IgnoreErrors,
}
When to Use:
- FailFast: Critical workflows where any failure invalidates the result
- ContinueParallel: Parallel sections can fail independently
- IgnoreErrors: Best-effort workflows, collect whatever partial results are available
Output Formats
pub enum OutputFormat {
/// Concatenate all outputs with newlines (default)
Concatenate,
/// JSON array with each agent's output as an element
JsonArray,
}
Example Outputs:
// Concatenate (default)
"Output from agent1\n---\nOutput from agent2\n---\nOutput from agent3"
// JsonArray
r#"["output from agent1", "output from agent2", "output from agent3"]"#
YAML Configuration
type: maneuver
name: "document-workflow"
# Flow expression using DSL
flow: "analyzer -> (summarizer, translator) -> reviewer"
# Available Paladins (must match names in flow)
paladins:
- inline:
name: "analyzer"
system_prompt: "Analyze the input document"
model: "gpt-4"
temperature: 0.7
provider:
type: openai
- inline:
name: "summarizer"
system_prompt: "Create a concise summary"
model: "gpt-4"
temperature: 0.5
provider:
type: openai
- inline:
name: "translator"
system_prompt: "Translate to simple language"
model: "gpt-4"
temperature: 0.5
provider:
type: openai
- inline:
name: "reviewer"
system_prompt: "Final review and synthesis"
model: "gpt-4"
temperature: 0.6
provider:
type: openai
# Optional: visualize before execution
visualize: "ascii"
CLI Commands
Create Maneuver Configuration
paladin battalion new my-workflow --type maneuver --output workflow.yaml
Creates a template YAML file with example flow and agents.
Visualize Flow
# ASCII tree visualization
paladin maneuver visualize -c workflow.yaml --format ascii
# Mermaid flowchart (for documentation)
paladin maneuver visualize -c workflow.yaml --format mermaid
# Save to file
paladin maneuver visualize -c workflow.yaml --format ascii -o flow.txt
Output Example (ASCII):
└─> analyzer
├─> [PARALLEL]
│ ├─> summarizer
│ └─> translator
└─> reviewer
Output Example (Mermaid):
flowchart LR
agent_analyzer
agent_analyzer --> parallel_1[Parallel]
parallel_1 --> agent_summarizer
parallel_1 --> agent_translator
parallel_1 --> agent_reviewer
Validate Configuration
# Basic validation
paladin maneuver validate -c workflow.yaml
# Verbose validation with detailed output
paladin maneuver validate -c workflow.yaml --verbose
Validates:
- Flow expression syntax
- All agents referenced in flow exist in config
- Paladin configuration structure
- Provider settings
Execute Maneuver
# Interactive execution
paladin battalion run -c workflow.yaml -t maneuver
# With input provided
paladin battalion run -c workflow.yaml -t maneuver -i "Process this text"
# Save output to file
paladin battalion run -c workflow.yaml -t maneuver -i "Input" -o result.json
# Verbose execution
paladin battalion run -c workflow.yaml -t maneuver -v
Visualization
ASCII Tree Format
Perfect for terminal output and debugging:
└─> intake
├─> [PARALLEL]
│ ├─> technical
│ ├─> business
│ └─> security
└─> synthesis
└─> review
Features:
- Box-drawing characters (├─>, └─>, │)
- Clear hierarchy visualization
- Sequential and parallel markers
- Nested structure representation
Mermaid Flowchart Format
Ideal for documentation and presentations:
flowchart LR
agent_intake
agent_intake --> parallel_1[Parallel]
parallel_1 --> agent_technical
parallel_1 --> agent_business
parallel_1 --> agent_security
parallel_1 --> agent_synthesis
agent_synthesis --> agent_review
Features:
- Web-ready visualization
- Integrates with GitHub/GitLab/documentation tools
- Professional diagram quality
- Exportable to SVG/PNG
Programmatic Visualization
use paladin_battalion::maneuver::visualizer::{FlowVisualizer, VisualizationFormat};
let flow = FlowParser::parse("a -> (b, c) -> d")?;
// ASCII visualization
let ascii = FlowVisualizer::to_ascii(&flow);
println!("{}", ascii);
// Mermaid visualization
let mermaid = FlowVisualizer::to_mermaid(&flow);
println!("{}", mermaid);
// Using format parameter
let viz = FlowVisualizer::visualize(&flow, VisualizationFormat::Ascii);
Error Handling
Validation Errors
use paladin_battalion::maneuver::parser::FlowParseError;
match FlowParser::parse("agent1 -> (agent2 | agent3)") {
Ok(flow) => { /* Success */ },
Err(FlowParseError::InvalidCharacter { position, character }) => {
eprintln!("Invalid character '{}' at position {}", character, position);
// Error: Invalid character '|' at position 17
},
Err(e) => eprintln!("Parse error: {}", e),
}
Execution Errors
use paladin_battalion::maneuver::ManeuverError;
match service.execute(&maneuver, input).await {
Ok(result) => println!("Success: {}", result.final_output),
Err(ManeuverError::AgentNotFound(name)) => {
eprintln!("Agent '{}' not found in configuration", name);
},
Err(ManeuverError::ExecutionError(msg)) => {
eprintln!("Execution failed: {}", msg);
},
Err(e) => eprintln!("Error: {}", e),
}
Error Recovery
// Configure error handling strategy
let config = ManeuverConfig::new()
.with_error_strategy(ErrorStrategy::IgnoreErrors);
// Execution continues despite failures
let result = service.execute(&maneuver, input).await?;
// Check status
match result.status {
ExecutionStatus::Success => println!("All agents succeeded"),
ExecutionStatus::PartialSuccess => println!("Some agents failed"),
ExecutionStatus::Failed => println!("Execution failed"),
}
// Inspect individual outputs
for (agent, output) in result.step_outputs {
if output.is_empty() {
println!("Agent {} failed", agent);
}
}
Performance
Benchmarks
Based on battalion_benchmarks.rs:
| Metric | Value | Notes |
|---|---|---|
| Parse Time | <1ms | Average for typical flows |
| Validation | <0.5ms | Per agent validation |
| Overhead | 10-50ms | Framework overhead only |
| Sequential (3 agents) | ~3-5s | Depends on LLM latency |
| Parallel (3 agents) | ~1-2s | Concurrent execution |
Optimization Tips
1. Minimize Sequential Chains
❌ Slow: a -> b -> c -> d -> e -> f (6 sequential calls)
✅ Fast: a -> (b, c, d) -> e (3 stages total)
2. Use Parallel Where Possible
// Slow: Sequential when order doesn't matter
"tech_review -> security_review -> legal_review"
// Fast: Parallel independent reviews
"(tech_review, security_review, legal_review)"
3. Configure Timeouts
let config = ManeuverConfig::new()
.with_timeout(Duration::from_secs(120)) // Per-agent timeout
.with_error_strategy(ErrorStrategy::ContinueParallel); // Don't wait for failures
4. Optimize Agent Prompts
- Keep system prompts concise
- Use lower
max_loopsvalues when possible - Set appropriate temperature values
5. Monitor Timing Metrics
let config = ManeuverConfig::new()
.with_collect_timing_metrics(true);
let result = service.execute(&maneuver, input).await?;
if let Some(metrics) = result.timing_metrics {
for (agent, duration) in metrics {
println!("{}: {}ms", agent, duration.as_millis());
}
}
Best Practices
1. Flow Design
Keep Flows Simple
// ✅ Good: Clear, easy to understand
"intake -> analyze -> decide"
// ❌ Bad: Too complex, hard to debug
"a -> (b -> (c, d -> (e, f)), g -> (h, i)) -> j"
Use Descriptive Names
// ✅ Good: Clear purpose
"document_analyzer -> sentiment_classifier -> report_generator"
// ❌ Bad: Cryptic names
"agent1 -> agent2 -> agent3"
2. Agent Configuration
Specialize Agents
Each agent should have a clear, focused responsibility:
- name: "analyzer"
system_prompt: "Analyze technical feasibility only. Focus on implementation challenges."
- name: "risk_assessor"
system_prompt: "Assess security and privacy risks only."
- name: "synthesizer"
system_prompt: "Combine technical analysis and risk assessment into recommendation."
Use Consistent Naming
Match agent names in flow expression exactly:
// Flow uses: analyzer, summarizer, reviewer
flow: "analyzer -> summarizer -> reviewer"
// Paladins must use same names:
agents.insert("analyzer", ...);
agents.insert("summarizer", ...);
agents.insert("reviewer", ...);
3. Error Handling
Always Handle Errors
// ✅ Good: Explicit error handling
match service.execute(&maneuver, input).await {
Ok(result) => process_result(result),
Err(ManeuverError::AgentNotFound(name)) => {
log_error!("Missing agent: {}", name);
return default_result();
},
Err(e) => {
log_error!("Execution failed: {}", e);
retry_with_fallback();
},
}
// ❌ Bad: Unwrapping
let result = service.execute(&maneuver, input).await.unwrap();
Choose Appropriate Strategy
// Critical workflows: fail fast
let config = ManeuverConfig::new()
.with_error_strategy(ErrorStrategy::FailFast);
// Best-effort workflows: collect partial results
let config = ManeuverConfig::new()
.with_error_strategy(ErrorStrategy::IgnoreErrors);
4. Testing
Validate Flows Early
#[test]
fn test_workflow_validation() {
let flow = FlowParser::parse("analyzer -> summarizer").unwrap();
let mut agents = HashMap::new();
agents.insert("analyzer".to_string(), create_test_agent("analyzer"));
agents.insert("summarizer".to_string(), create_test_agent("summarizer"));
let result = Maneuver::new("test", agents, flow, Default::default());
assert!(result.is_ok());
}
Test Visualizations
#[test]
fn test_flow_visualization() {
let flow = FlowParser::parse("a -> (b, c)").unwrap();
let ascii = FlowVisualizer::to_ascii(&flow);
assert!(ascii.contains("PARALLEL"));
assert!(ascii.contains("a"));
assert!(ascii.contains("b"));
assert!(ascii.contains("c"));
}
5. Documentation
Document Complex Flows
# Flow explanation:
# 1. Intake agent validates and normalizes input
# 2. Three specialists analyze in parallel:
# - Technical feasibility
# - Business value
# - Security implications
# 3. Synthesis agent combines all perspectives
# 4. Final review for quality assurance
flow: "intake -> (technical, business, security) -> synthesis -> review"
API Reference
Core Types
FlowParser
pub struct FlowParser;
impl FlowParser {
/// Parse a flow expression from text
pub fn parse(input: &str) -> Result<FlowExpression, FlowParseError>
}
FlowExpression
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FlowExpression {
/// Single agent execution
Agent(String),
/// Sequential execution (agent₁ → agent₂ → ...)
Sequential(Vec<FlowExpression>),
/// Parallel execution (agent₁, agent₂, ...)
Parallel(Vec<FlowExpression>),
}
impl FlowExpression {
/// Get all agent names referenced in this expression
pub fn agent_names(&self) -> Vec<String>
}
Maneuver
pub struct Maneuver {
pub name: String,
pub agents: HashMap<String, Paladin>,
pub flow: FlowExpression,
pub config: ManeuverConfig,
}
impl Maneuver {
/// Create a new Maneuver with validation
pub fn new(
name: impl Into<String>,
agents: HashMap<String, Paladin>,
flow: FlowExpression,
config: ManeuverConfig,
) -> Result<Self, ManeuverError>
/// Validate that all flow agents exist
pub fn validate(&self) -> Result<(), ManeuverError>
}
ManeuverConfig
pub struct ManeuverConfig {
pub error_strategy: ErrorStrategy,
pub output_format: OutputFormat,
pub pass_output_as_input: bool,
pub timeout: Option<Duration>,
pub collect_timing_metrics: bool,
pub detailed_observability: bool,
}
impl ManeuverConfig {
pub fn new() -> Self
pub fn with_error_strategy(self, strategy: ErrorStrategy) -> Self
pub fn with_output_format(self, format: OutputFormat) -> Self
pub fn with_timeout(self, timeout: Duration) -> Self
}
ManeuverResult
pub struct ManeuverResult {
/// Final aggregated output
pub final_output: String,
/// Individual agent outputs
pub step_outputs: HashMap<String, String>,
/// Execution order
pub execution_order: Vec<String>,
/// Per-agent timing (if enabled)
pub timing_metrics: Option<HashMap<String, Duration>>,
/// Execution status
pub status: ExecutionStatus,
}
ManeuverExecutionService
pub struct ManeuverExecutionService {
paladin_port: Arc<dyn PaladinPort>,
}
impl ManeuverExecutionService {
pub fn new(paladin_port: Arc<dyn PaladinPort>) -> Self
pub async fn execute(
&self,
maneuver: &Maneuver,
input: &str,
) -> Result<ManeuverResult, ManeuverError>
}
Visualization
FlowVisualizer
pub struct FlowVisualizer;
impl FlowVisualizer {
/// Generate ASCII tree visualization
pub fn to_ascii(flow: &FlowExpression) -> String
/// Generate Mermaid flowchart
pub fn to_mermaid(flow: &FlowExpression) -> String
/// Generate visualization in specified format
pub fn visualize(flow: &FlowExpression, format: VisualizationFormat) -> String
}
pub enum VisualizationFormat {
Ascii,
Mermaid,
}
Troubleshooting
Common Issues
1. Parse Error: Invalid Character '|'
Problem: Using pipe operator for parallel execution
// ❌ Wrong
let flow = FlowParser::parse("(agent1 | agent2)")?;
Solution: Use comma instead
// ✅ Correct
let flow = FlowParser::parse("(agent1, agent2)")?;
2. AgentNotFound Error
Problem: Agent name in flow doesn't match configured agents
// Flow references "analyzer"
let flow = FlowParser::parse("analyzer -> summarizer")?;
// But agent is named "Analyzer" (different case)
agents.insert("Analyzer".to_string(), paladin);
Solution: Use exact same names
// ✅ Correct - exact match
agents.insert("analyzer".to_string(), paladin);
3. Missing Parentheses for Parallel
Problem: Forgetting parentheses around parallel agents
// ❌ Wrong - will be parsed as "agent1 -> agent2", "agent3"
let flow = FlowParser::parse("agent1 -> agent2, agent3")?;
Solution: Always use parentheses for parallel
// ✅ Correct
let flow = FlowParser::parse("agent1 -> (agent2, agent3)")?;
4. Timeout Errors
Problem: Agents taking too long to execute
// Default timeout may be too short
let config = ManeuverConfig::default(); // 300s default
Solution: Increase timeout for slow workflows
// ✅ Longer timeout
let config = ManeuverConfig::new()
.with_timeout(Duration::from_secs(600)); // 10 minutes
5. Partial Results from Parallel Execution
Problem: Some agents fail in parallel execution
Solution: Use appropriate error strategy
// Continue despite failures
let config = ManeuverConfig::new()
.with_error_strategy(ErrorStrategy::ContinueParallel);
let result = service.execute(&maneuver, input).await?;
// Check which agents succeeded
for (agent, output) in result.step_outputs {
if !output.is_empty() {
println!("{} succeeded: {}", agent, output);
}
}
Debugging Tips
1. Enable Verbose Logging
env_logger::init(); // In main()
// Set RUST_LOG=debug
// Will show detailed execution trace
2. Visualize Before Executing
paladin maneuver visualize -c config.yaml --format ascii
Visual inspection often reveals flow logic issues.
3. Validate Configuration
paladin maneuver validate -c config.yaml --verbose
Catches configuration mismatches before execution.
4. Check Timing Metrics
let config = ManeuverConfig::new()
.with_collect_timing_metrics(true);
let result = service.execute(&maneuver, input).await?;
if let Some(metrics) = result.timing_metrics {
for (agent, duration) in metrics {
if duration > Duration::from_secs(60) {
println!("⚠️ {} took {}s", agent, duration.as_secs());
}
}
}
5. Inspect Individual Outputs
let result = service.execute(&maneuver, input).await?;
// Check each agent's output
for agent in result.execution_order {
if let Some(output) = result.step_outputs.get(&agent) {
println!("\n=== {} ===", agent);
println!("{}", output);
}
}
Getting Help
- Documentation: https://github.com/DF3NDR/paladin-dev-env/docs
- Issues: https://github.com/DF3NDR/paladin-dev-env/issues
- Discussions: https://github.com/DF3NDR/paladin-dev-env/discussions
- Examples:
examples/directory in repository
Advanced Topics
Custom Output Formatting
use paladin_battalion::maneuver::OutputFormat;
// Implement custom aggregation logic
let config = ManeuverConfig::new()
.with_output_format(OutputFormat::JsonArray);
// Result will be JSON:
// {"agent1": "output1", "agent2": "output2"}
Integration with Commander
Commander automatically detects Maneuver patterns:
use paladin_battalion::commander::CommanderBuilder;
use paladin_core::platform::container::battalion::BattalionStrategy;
// Maneuver is explicit-only — it is NOT selected by Auto mode.
// You must explicitly set BattalionStrategy::Maneuver and provide a flow expression.
let commander = CommanderBuilder::new(paladin_port)
.strategy(BattalionStrategy::Maneuver)
.paladins(paladins)
.flow("agent1 -> agent2 -> agent3".to_string())
.build()?;
let result = commander.execute("Process this document").await?;
Performance Tuning
For high-throughput systems:
// Minimize overhead
let config = ManeuverConfig::new()
.with_collect_timing_metrics(false) // Disable if not needed
.with_detailed_observability(false) // Reduce logging
.with_error_strategy(ErrorStrategy::FailFast); // Fast failure
// Use connection pooling for LLM providers
// Pre-validate flows at startup
// Cache parsed flow expressions
Last Updated: February 2026 Version: 0.1.0 Status: Production Ready