Skip to main content
Like AOF? Give us a star!
If you find AOF useful, please star us on GitHub. It helps us reach more developers and grow the community.

AgentFlow YAML Specification

Complete reference for AgentFlow workflow specifications.

Overview

An AgentFlow is a multi-step workflow that orchestrates agents, tools, and integrations in a directed graph. Flows define the sequence of operations with nodes and connections.

Key Characteristics:

  • Flows are pure workflows - no embedded triggers
  • Triggers reference flows - via command bindings in Trigger CRDs
  • Entry point is "start" - connections begin from the "start" node
  • Nodes execute sequentially or conditionally - based on connections

Basic Structure

apiVersion: aof.dev/v1
kind: AgentFlow
metadata:
name: string # Required: Unique identifier
namespace: string # Optional: Namespace for isolation
labels: # Optional: Key-value labels
key: value
annotations: # Optional: Additional metadata
key: value

spec:
description: string # Optional: Human-readable description

context: # Optional: Execution context
kubeconfig: string # Path to kubeconfig
namespace: string # Default K8s namespace
cluster: string # Cluster name
env: # Environment variables
KEY: value
working_dir: string

nodes: # Required: Flow steps
- id: string
type: NodeType
config:
agent: string # For Agent nodes: agent name
fleet: string # For Fleet nodes: fleet name
input: string # Input to pass
tools: [] # Optional: Override agent tools
mcp_servers: [] # Optional: MCP server configs
conditions: []

connections: # Required: Node edges
- from: string # Source node (or "start")
to: string # Target node
condition: string # Optional: Condition expression

config: # Optional: Global flow config
default_timeout_seconds: int
verbose: bool
retry:
max_attempts: int
initial_delay: string
backoff_multiplier: float

Metadata

metadata.name

Type: string Required: Yes

Unique identifier for the flow. Used in CLI commands and referenced by Trigger command bindings.

metadata.labels

Type: map[string]string Required: No

Key-value pairs for categorization and filtering.

Example:

metadata:
name: deploy-flow
labels:
purpose: deployment
team: platform
environment: production

Spec Fields

spec.description

Type: string Required: No

Human-readable description of what this flow does.

spec:
description: "Production deployment workflow with approval gates"

spec.context

Type: object Required: No

Execution context for the flow including environment variables and Kubernetes configuration.

spec:
context:
kubeconfig: ~/.kube/config
namespace: production
cluster: prod-cluster
env:
ENVIRONMENT: production
LOG_LEVEL: info
working_dir: /app

Node Types

Nodes define what happens at each step of the flow.

Agent Node

Execute a single agent.

nodes:
- id: analyze
type: Agent
config:
agent: k8s-agent # Agent name or path
input: "${event.text}" # Input from trigger event
timeout_seconds: 120

Fleet Node

Execute a fleet of agents (multi-agent coordination).

nodes:
- id: diagnose
type: Fleet
config:
fleet: rca-fleet # Fleet name or path
input: "${event.text}"

HumanApproval Node

Wait for human approval before proceeding.

nodes:
- id: approval
type: HumanApproval
config:
message: "Approve deployment to production?"
timeout_seconds: 300 # 5 minute timeout
fallback: reject # Action if timeout: reject | approve

Conditional Node

Branch based on conditions.

nodes:
- id: check-env
type: Conditional
config:
expression: "${context.env} == 'production'"
true_target: production-deploy
false_target: staging-deploy

End Node

Terminal node that produces final output.

nodes:
- id: complete
type: End
config:
message: "${previous.output}"

Response Node

Send response to the triggering platform (Slack, Telegram, etc.).

nodes:
- id: notify
type: Response
config:
message: "${analyze.output}"
format: markdown # text | markdown | blocks

Connections

Connections define the flow between nodes. Every flow starts from the implicit "start" node.

Basic Connection

connections:
- from: start
to: validate
- from: validate
to: deploy
- from: deploy
to: notify

Conditional Connection

connections:
- from: approval
to: deploy
condition: approved # Only if approved
- from: approval
to: notify-rejected
condition: rejected # Only if rejected

Multiple Outputs

A node can connect to multiple targets based on conditions:

connections:
- from: analyze
to: critical-path
condition: severity == "critical"
- from: analyze
to: normal-path
condition: severity != "critical"

Complete Examples

Deployment Flow with Approval

apiVersion: aof.dev/v1
kind: AgentFlow
metadata:
name: deploy-flow
labels:
purpose: deployment
spec:
description: "Production deployment with approval gate"

nodes:
- id: validate
type: Agent
config:
agent: validator-agent
input: "Validate deployment: ${event.text}"

- id: approval
type: HumanApproval
config:
message: |
Deployment validated. Approve deployment?
Version: ${validate.output.version}
Target: ${validate.output.target}
timeout_seconds: 600

- id: deploy
type: Agent
config:
agent: k8s-agent
input: "Deploy ${validate.output.manifest}"

- id: notify-success
type: Response
config:
message: "✅ Deployment complete: ${deploy.output}"

- id: notify-rejected
type: Response
config:
message: "❌ Deployment rejected by user"

connections:
- from: start
to: validate
- from: validate
to: approval
- from: approval
to: deploy
condition: approved
- from: approval
to: notify-rejected
condition: rejected
- from: deploy
to: notify-success

Root Cause Analysis Flow

apiVersion: aof.dev/v1
kind: AgentFlow
metadata:
name: rca-flow
spec:
description: "Multi-model root cause analysis with consensus"

nodes:
- id: collect
type: Fleet
config:
fleet: rca-fleet
input: "${event.text}"

- id: respond
type: Response
config:
message: "${collect.output}"
format: markdown

connections:
- from: start
to: collect
- from: collect
to: respond

Incident Response Flow

apiVersion: aof.dev/v1
kind: AgentFlow
metadata:
name: incident-flow
spec:
description: "Automated incident response workflow"

nodes:
- id: assess
type: Agent
config:
agent: monitoring-agent
input: "Assess incident: ${event.text}"

- id: route
type: Conditional
config:
expression: "${assess.output.severity}"
cases:
critical: escalate
high: page-oncall
default: log-ticket

- id: escalate
type: Agent
config:
agent: pagerduty-agent
input: "Create P1 incident: ${assess.output}"

- id: page-oncall
type: Agent
config:
agent: slack-agent
input: "Page on-call: ${assess.output}"

- id: log-ticket
type: Agent
config:
agent: jira-agent
input: "Create ticket: ${assess.output}"

connections:
- from: start
to: assess
- from: assess
to: route
- from: route
to: escalate
condition: critical
- from: route
to: page-oncall
condition: high
- from: route
to: log-ticket
condition: default

Variable Substitution

Flows support variable substitution using ${...} syntax.

Event Variables

From the triggering event (via Trigger):

VariableDescription
${event.text}Message text
${event.user.id}User ID
${event.user.name}User display name
${event.channel}Channel/chat ID
${event.platform}Platform name (slack, telegram)
${event.timestamp}Event timestamp

Node Output Variables

Access output from previous nodes:

VariableDescription
${node_id.output}Full output from node
${node_id.output.field}Specific field from output
${previous.output}Output from previous node

Context Variables

From flow context:

VariableDescription
${context.namespace}Kubernetes namespace
${context.cluster}Cluster name
${context.env.KEY}Environment variable

Retry Configuration

Configure retry behavior for failed nodes:

spec:
config:
retry:
max_attempts: 3
initial_delay: 1s
backoff_multiplier: 2.0
max_delay: 30s

Per-node retry:

nodes:
- id: deploy
type: Agent
config:
agent: k8s-agent
retry:
max_attempts: 5
initial_delay: 2s

Timeout Configuration

Global timeout:

spec:
config:
default_timeout_seconds: 300

Per-node timeout:

nodes:
- id: long-operation
type: Agent
config:
agent: batch-agent
timeout_seconds: 600

Usage with Triggers

Flows are invoked via Trigger command bindings:

# In a Trigger CRD
apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: slack-production
spec:
type: Slack
config:
bot_token: ${SLACK_BOT_TOKEN}
signing_secret: ${SLACK_SIGNING_SECRET}

commands:
/deploy:
flow: deploy-flow # References this AgentFlow
description: "Deploy to production"
/rca:
flow: rca-flow
description: "Root cause analysis"

default_agent: devops

CLI Usage

Run a flow directly:

# Execute a flow with input
aofctl run flow examples/flows/deploy-flow.yaml -i "deploy v2.1.0 to production"

# Describe a flow
aofctl describe flow examples/flows/deploy-flow.yaml

# Validate flow YAML
aofctl validate flows/deploy-flow.yaml

Best Practices

  1. Keep flows focused - One flow per logical workflow
  2. Use descriptive node IDs - validate, deploy, not step1, step2
  3. Add descriptions - Document what the flow does
  4. Handle failure paths - Use conditional connections for error cases
  5. Set appropriate timeouts - Prevent runaway executions
  6. Use fleets for complex analysis - Multi-agent coordination for RCA