Skip to main content
Complete reference for ensemble, agent, and component YAML files.
Prefer TypeScript? See the TypeScript API Reference for programmatic ensemble creation with full type safety.

Ensemble Schema

ensemble: string                    # Required: Ensemble name

description: string                 # Optional: Description

apiExecutable: boolean              # Optional: Control Execute API access (default: true)

trigger:                           # Optional: Trigger configuration
  - type: http | webhook | mcp | email | queue | cron | build | cli
    # See Trigger Types section below for type-specific fields

inputs:                            # Optional: Input definitions
  input_name:
    type: string | number | boolean | array | object
    required: boolean
    default: any
    description: string

state:                             # Optional: Ensemble state
  schema:
    field_name: type

agents:                            # Required: Agent list
  - name: string                   # Required: Agent name
    agent: string                  # Agent reference (OR operation)
    operation: string              # Operation type (OR agent)
    inputs:                        # Agent inputs
      key: value
    config:                        # Operation config
      key: value
    condition: string              # Optional: Execution condition
    cache:                         # Optional: Cache config
      ttl: number
      key: string
    retry:                         # Optional: Retry config
      maxAttempts: number
      backoff: exponential | linear
      initialDelay: number
      maxDelay: number
      retryOn: [number]
    timeout: number                # Optional: Timeout (ms)
    state:                         # Optional: State access
      use: [string]
      set:
        field: value

output:                            # Optional: Output definition
  status: number                   # HTTP status code
  headers:                         # Response headers
    key: value
  format:                          # Response format config
    type: json | text | html | xml | csv | markdown | yaml | ics | rss | atom
    extract: string                # Field to extract from body
  body:                            # Response body
    key: value

Agent Schema

agent: string                      # Required: Agent name

description: string                # Optional: Description

apiExecutable: boolean             # Optional: Control Execute API access (default: true)

inputs:                            # Optional: Input definitions
  input_name:
    type: string | number | boolean | array | object
    required: boolean
    default: any
    description: string

state:                             # Optional: Agent state
  schema:
    field_name: type

operations:                        # Required: Operation list
  - name: string                   # Required: Operation name
    operation: string              # Required: Operation type
    config:                        # Operation-specific config
      key: value
    condition: string              # Optional: Execution condition
    cache:                         # Optional: Cache config
      ttl: number
      key: string
    retry:                         # Optional: Retry config
      maxAttempts: number
      backoff: exponential | linear
    timeout: number                # Optional: Timeout (ms)
    state:                         # Optional: State access
      use: [string]
      set:
        field: value

outputs:                           # Optional: Output definition
  output_name: expression

cache:                             # Optional: Agent-level cache
  ttl: number
  key: string

retry:                             # Optional: Agent-level retry
  maxAttempts: number
  backoff: exponential | linear

Component Schema

component: string                  # Required: Component name

version: string                    # Required: Semantic version

description: string                # Optional: Description

type: prompt | template | schema | config

content: string | object           # Component content

Trigger Types

Ensembles can be invoked via multiple trigger mechanisms. Each trigger type has specific configuration fields.

HTTP Trigger

Expose ensembles as HTTP endpoints with support for single or multiple paths.
trigger:
  - type: http
    path: /api/users/:id        # Single path
    methods: [GET, POST]
    auth:
      type: bearer
      secret: ${env.API_TOKEN}
    rateLimit:
      requests: 100
      window: 60
    cors:
      origin: "https://myapp.com"
    public: true                 # Optional: bypass auth

Multi-Path HTTP

Define multiple paths with different methods in a single trigger:
trigger:
  - type: http
    paths:
      - path: /api/v1/users
        methods: [GET, POST]
      - path: /api/v1/users/:id
        methods: [GET, PUT, DELETE]
      - path: /api/v1/users/:id/profile
        methods: [GET, PATCH]
    auth:
      type: bearer
    public: false

Webhook Trigger

Handle incoming webhooks from external services.
trigger:
  - type: webhook
    path: /webhooks/github
    methods: [POST]
    auth:
      type: signature
      secret: ${env.WEBHOOK_SECRET}
    async: true                  # Optional: process asynchronously
    public: false

MCP Trigger

Expose ensemble as an MCP (Model Context Protocol) tool for AI agents.
trigger:
  - type: mcp
    auth:
      type: api_key
    public: false

Email Trigger

Route emails to ensembles for processing.
trigger:
  - type: email
    addresses: [[email protected], [email protected]]
    reply_with_output: true      # Optional: send output as reply

Queue Trigger

Process messages from queues.
trigger:
  - type: queue
    queue: user-events
    batch_size: 10
    max_retries: 3

Cron Trigger

Schedule ensemble execution at specific times.
trigger:
  - type: cron
    cron: "0 8 * * *"            # 8 AM daily
    timezone: "America/New_York"
    enabled: true
    input:                       # Optional: static input
      report_type: "daily"

Build Trigger (NEW)

Execute ensemble at build time for static generation.
trigger:
  - type: build
    enabled: true
    output: ./dist/docs          # Optional: output directory
    input:                       # Optional: build-time input
      action: generate-openapi
    metadata:                    # Optional: metadata
      version: 1.0.0
Use Cases:
  • Generate OpenAPI documentation
  • Pre-render static pages
  • Build search indexes
  • Generate sitemap files
CLI Usage:
ensemble conductor build      # Run all build triggers

CLI Trigger (NEW)

Create custom CLI commands for development and operations.
trigger:
  - type: cli
    command: generate-docs
    description: Generate documentation
    options:
      - name: format
        type: string
        default: yaml
        description: Output format
      - name: output
        type: string
        required: true
        description: Output file path
      - name: verbose
        type: boolean
        default: false
        description: Verbose output
Access Options in Flow:
flow:
  - agent: docs-generator
    input:
      format: ${trigger.options.format}
      output: ${trigger.options.output}
      verbose: ${trigger.options.verbose}
CLI Usage:
ensemble conductor run generate-docs --output ./docs --format markdown --verbose
Option Types:
  • string - Text value
  • number - Numeric value
  • boolean - True/false flag
  • array - Multiple values

Expression Syntax

Variable Access

${input.field}                     # Input variable
${env.VARIABLE}                    # Environment variable
${state.field}                     # State variable
${agent-name.output}               # Agent output
${agent-name.output.nested.field}  # Nested output
${[email protected]}          # Component reference
${trigger.options.format}          # CLI trigger option

Array Indexing

${input.items[0]}                  # First array element
${input.items[2]}                  # Third element (0-indexed)
${input.users[0].name}             # Property of first element
${data.results[1].meta.id}         # Deep nested access

Nullish Coalescing (??)

Returns the first value that is not null or undefined:
${input.name ?? "default"}         # Use "default" if null/undefined
${input.query.name ?? input.body.name ?? "Guest"}  # Chain fallbacks

# Preserves falsy values (unlike ||)
${input.count ?? 0}                # Returns 0 if count is 0, not the fallback
${input.value ?? ""}               # Returns "" if value is ""

Falsy Coalescing (||)

Returns the first truthy value (catches "", 0, false, null, undefined):
${input.name || "default"}         # Use "default" if empty/falsy
${input.count || 10}               # Use 10 if count is 0
${input.enabled || true}           # Use true if enabled is false
${input.a || input.b || "fallback"} # Chain multiple values

Ternary Conditionals (?:)

${input.enabled ? "yes" : "no"}    # Returns "yes" if truthy
${input.count ? input.count : 1}   # Returns count or 1
${input.premium ? 100 : 10}        # Numeric conditional
${input.type ? input.type : "default"} # Path in branches

Boolean Negation (!)

${!input.disabled}                 # true if disabled is falsy
${!input.hidden}                   # true if hidden is false/undefined
${!agent.executed}                 # true if agent didn't run

Conditionals

condition: ${input.value > 10}
condition: ${agent.success}
condition: ${agent.failed}
condition: ${!agent.executed}
condition: ${input.type === 'premium'}
condition: ${input.age >= 18 && input.verified}

Filter Chains

${input.text | uppercase}          # Apply uppercase filter
${input.text | split(" ") | first} # Chain multiple filters
${input.items | length}            # Array/string length
${input.value | default("none")}   # Default if empty

Functions

${Date.now()}                      # Current timestamp
${JSON.stringify(object)}          # JSON encode
${JSON.parse(string)}              # JSON decode
${Math.round(number)}              # Math functions
${array.length}                    # Array length
${array.map(item => item.id)}      # Array map
${array.filter(item => item.active)} # Array filter
${array.reduce((sum, item) => sum + item.value, 0)} # Array reduce
${string.split(',')}               # String split
${string.toUpperCase()}            # String uppercase

Operator Precedence

When combining operators, they’re evaluated in this order:
  1. Ternary (?:) - evaluated first
  2. Nullish coalescing (??) - null/undefined only
  3. Falsy coalescing (||) - all falsy values
  4. Filters (|) - transformation chains
# Complex example
${input.enabled ? input.premium ?? "basic" : "disabled"}
# If enabled is truthy: returns premium or "basic"
# If enabled is falsy: returns "disabled"

Operation-Specific Config

think

config:
  provider: openai | anthropic | cloudflare | groq
  model: string
  prompt: string
  messages: array
  temperature: number
  maxTokens: number
  schema: string | object          # JSON Schema reference or inline schema
  image: string                    # For vision models
  stream: boolean

code

config:
  code: string                     # JavaScript code

storage

# KV
config:
  type: kv
  action: get | put | delete
  key: string
  value: any                       # For put
  ttl: number                      # For put

# D1
config:
  type: d1
  query: string
  params: array

# R2
config:
  type: r2
  action: get | put | delete
  key: string
  value: any                       # For put

# Vectorize
config:
  type: vectorize
  action: search | embed | delete
  query: string                    # For search
  text: string | array             # For embed
  topK: number                     # For search
  namespace: string
  filter: object

http

config:
  url: string
  method: GET | POST | PUT | PATCH | DELETE
  headers: object
  body: any
  timeout: number

tools

config:
  tool: string
  params: object

email

config:
  to: string | array
  from: string
  subject: string
  body: string
  html: string

sms

config:
  to: string
  from: string
  body: string

html

config:
  template: string
  data: object
  html: string                     # Or raw HTML

pdf

config:
  html: string
  filename: string
  format: A4 | Letter
  margin: object

page

config:
  component: string
  props: object
  renderMode: ssr | csr | hybrid

Cache Configuration

cache:
  ttl: number                      # Time to live (seconds)
  key: string                      # Cache key (supports expressions)
Example:
cache:
  ttl: 3600
  key: user-${input.user_id}

Retry Configuration

retry:
  maxAttempts: number              # Max retry attempts (default: 3)
  backoff: exponential | linear    # Backoff strategy (default: exponential)
  initialDelay: number             # Initial delay (ms, default: 1000)
  maxDelay: number                 # Max delay (ms, default: 30000)
  retryOn: [number]                # HTTP status codes to retry (default: [500, 502, 503, 504])

State Configuration

state:
  schema:                          # State schema
    field1: type
    field2: type

  use: [field1, field2]            # Read these fields
  set:                             # Write these fields
    field1: ${expression}
    field2: ${expression}

Condition Expressions

# Simple comparisons
condition: ${value > 10}
condition: ${value === 'active'}
condition: ${value !== null}

# Boolean operations
condition: ${value1 && value2}
condition: ${value1 || value2}
condition: ${!value}

# Agent execution status
condition: ${agent.success}       # Agent succeeded
condition: ${agent.failed}        # Agent failed
condition: ${agent.executed}      # Agent ran
condition: ${!agent.executed}     # Agent didn't run

# Complex conditions
condition: ${input.amount > 1000 && input.verified}
condition: ${user.role === 'admin' || user.role === 'moderator'}

Output Definitions

# Simple output
output:
  result: ${agent.output}

# Multiple outputs
output:
  data: ${process.output}
  metadata:
    timestamp: ${Date.now()}
    version: "1.0"

# Computed outputs
output:
  total: ${items.reduce((sum, item) => sum + item.price, 0)}
  count: ${items.length}

Output Format

The format field in the output block controls response serialization and Content-Type headers. This is the recommended approach for non-JSON responses.

Format Types

TypeContent-TypeDescription
jsonapplication/jsonJSON serialization (default)
texttext/plainPlain text
htmltext/htmlHTML content
xmlapplication/xmlXML content
csvtext/csvCSV serialization from arrays
markdowntext/markdownMarkdown content
yamlapplication/x-yamlYAML serialization
icstext/calendariCalendar format
rssapplication/rss+xmlRSS feed
atomapplication/atom+xmlAtom feed

Simple Format

output:
  status: 200
  format: text
  body:
    content: "Hello, World!"

Format with Extract

Use extract to specify which field from the body should be serialized:
output:
  status: 200
  format:
    type: csv
    extract: users
  body:
    users: ${fetch-users.output}
    metadata: ${meta.output}

Format Examples

CSV Export:
output:
  status: 200
  headers:
    Content-Disposition: attachment; filename="data.csv"
  format:
    type: csv
    extract: records
  body:
    records: ${query.output}
YAML Config:
output:
  status: 200
  format:
    type: yaml
    extract: config
  body:
    config: ${build-config.output}
iCalendar Event:
output:
  status: 200
  headers:
    Content-Disposition: attachment; filename="event.ics"
  format: ics
  body:
    calendar: ${generate-ics.output}
RSS Feed:
output:
  status: 200
  format: rss
  body:
    feed: ${build-feed.output}

API Execution Configuration

Control which agents and ensembles can be executed via the Execute API (/api/v1/execute/agent/* and /api/v1/execute/ensemble/*).

Project-Level Configuration

In conductor.config.ts:
const config: ConductorConfig = {
  api: {
    execution: {
      agents: {
        // When true, agents must have apiExecutable: true to be API executable
        requireExplicit: false
      },
      ensembles: {
        // When true, ensembles must have apiExecutable: true to be API executable
        requireExplicit: false
      }
    }
  }
};

Agent/Ensemble-Level Configuration

Use apiExecutable to control individual agent or ensemble access:
# Explicitly allow API execution
agent: my-public-agent
apiExecutable: true
# Explicitly deny API execution
ensemble: internal-workflow
apiExecutable: false

Behavior Matrix

requireExplicitapiExecutableResult
false (default)undefined✅ Allowed
falsetrue✅ Allowed
falsefalse❌ Denied
trueundefined❌ Denied
truetrue✅ Allowed
truefalse❌ Denied
When requireExplicit: true, agents/ensembles must explicitly opt-in to API execution. This is recommended for production environments where you want fine-grained control over which workflows are externally accessible.

Examples

Complete Ensemble

ensemble: user-onboarding

description: Onboard new users

inputs:
  email:
    type: string
    required: true
  name:
    type: string
    required: true

state:
  schema:
    onboarding_step: number

agents:
  - name: validate-email
    operation: code
    config:
      script: scripts/validate-email-address
    input:
      email: ${input.email}

  - name: create-account
    condition: ${validate-email.output.valid}
    operation: storage
    config:
      type: d1
      query: INSERT INTO users (email, name) VALUES (?, ?)
      params:
        - ${input.email}
        - ${input.name}
// scripts/validate-email-address.ts
import type { AgentExecutionContext } from '@ensemble-edge/conductor'

export default function validateEmailAddress(context: AgentExecutionContext) {
  const { email } = context.input
  const regex = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/

  return { valid: regex.test(email) }
}
  - name: send-welcome
    condition: ${create-account.success}
    operation: email
    config:
      to: ${input.email}
      subject: "Welcome!"
      body: "Welcome ${input.name}!"

output:
  user_id: ${create-account.output.id}
  success: ${send-welcome.success}

Next Steps