> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ensemble.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# YAML Schema Reference

> Complete YAML configuration reference

**Complete reference for ensemble, agent, and component YAML files.**

<Note>
  Prefer TypeScript? See the [TypeScript API Reference](/conductor/reference/ts-schema) for programmatic ensemble creation with full type safety.
</Note>

## Ensemble Schema

```yaml theme={null}
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

```yaml theme={null}
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

```yaml theme={null}
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.

```yaml theme={null}
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:

```yaml theme={null}
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.

```yaml theme={null}
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.

```yaml theme={null}
trigger:
  - type: mcp
    auth:
      type: api_key
    public: false
```

### Email Trigger

Route emails to ensembles for processing.

```yaml theme={null}
trigger:
  - type: email
    addresses: [support@company.com, info@company.com]
    reply_with_output: true      # Optional: send output as reply
```

### Queue Trigger

Process messages from queues.

```yaml theme={null}
trigger:
  - type: queue
    queue: user-events
    batch_size: 10
    max_retries: 3
```

### Cron Trigger

Schedule ensemble execution at specific times.

```yaml theme={null}
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.

```yaml theme={null}
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:**

```bash theme={null}
ensemble conductor build      # Run all build triggers
```

### CLI Trigger (NEW)

Create custom CLI commands for development and operations.

```yaml theme={null}
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:**

```yaml theme={null}
flow:
  - agent: docs-generator
    input:
      format: ${trigger.options.format}
      output: ${trigger.options.output}
      verbose: ${trigger.options.verbose}
```

**CLI Usage:**

```bash theme={null}
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

```yaml theme={null}
${input.field}                     # Input variable
${env.VARIABLE}                    # Environment variable
${state.field}                     # State variable
${agent-name.output}               # Agent output
${agent-name.output.nested.field}  # Nested output
${component.name@v1.0.0}          # Component reference
${trigger.options.format}          # CLI trigger option
```

### Array Indexing

```yaml theme={null}
${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`:

```yaml theme={null}
${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`):

```yaml theme={null}
${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 (?:)

```yaml theme={null}
${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 (!)

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

### Conditionals

```yaml theme={null}
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

```yaml theme={null}
${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

```yaml theme={null}
${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

```yaml theme={null}
# 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

```yaml theme={null}
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

```yaml theme={null}
config:
  code: string                     # JavaScript code
```

### storage

```yaml theme={null}
# 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

```yaml theme={null}
config:
  url: string
  method: GET | POST | PUT | PATCH | DELETE
  headers: object
  body: any
  timeout: number
```

### tools

```yaml theme={null}
config:
  tool: string
  params: object
```

### email

```yaml theme={null}
config:
  to: string | array
  from: string
  subject: string
  body: string
  html: string
```

### sms

```yaml theme={null}
config:
  to: string
  from: string
  body: string
```

### html

```yaml theme={null}
config:
  template: string
  data: object
  html: string                     # Or raw HTML
```

### pdf

```yaml theme={null}
config:
  html: string
  filename: string
  format: A4 | Letter
  margin: object
```

### page

```yaml theme={null}
config:
  component: string
  props: object
  renderMode: ssr | csr | hybrid
```

## Cache Configuration

```yaml theme={null}
cache:
  ttl: number                      # Time to live (seconds)
  key: string                      # Cache key (supports expressions)
```

Example:

```yaml theme={null}
cache:
  ttl: 3600
  key: user-${input.user_id}
```

## Retry Configuration

```yaml theme={null}
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

```yaml theme={null}
state:
  schema:                          # State schema
    field1: type
    field2: type

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

## Condition Expressions

```yaml theme={null}
# 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

```yaml theme={null}
# 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

| Type       | Content-Type           | Description                   |
| ---------- | ---------------------- | ----------------------------- |
| `json`     | `application/json`     | JSON serialization (default)  |
| `text`     | `text/plain`           | Plain text                    |
| `html`     | `text/html`            | HTML content                  |
| `xml`      | `application/xml`      | XML content                   |
| `csv`      | `text/csv`             | CSV serialization from arrays |
| `markdown` | `text/markdown`        | Markdown content              |
| `yaml`     | `application/x-yaml`   | YAML serialization            |
| `ics`      | `text/calendar`        | iCalendar format              |
| `rss`      | `application/rss+xml`  | RSS feed                      |
| `atom`     | `application/atom+xml` | Atom feed                     |

### Simple Format

```yaml theme={null}
output:
  status: 200
  format: text
  body:
    content: "Hello, World!"
```

### Format with Extract

Use `extract` to specify which field from the body should be serialized:

```yaml theme={null}
output:
  status: 200
  format:
    type: csv
    extract: users
  body:
    users: ${fetch-users.output}
    metadata: ${meta.output}
```

### Format Examples

**CSV Export:**

```yaml theme={null}
output:
  status: 200
  headers:
    Content-Disposition: attachment; filename="data.csv"
  format:
    type: csv
    extract: records
  body:
    records: ${query.output}
```

**YAML Config:**

```yaml theme={null}
output:
  status: 200
  format:
    type: yaml
    extract: config
  body:
    config: ${build-config.output}
```

**iCalendar Event:**

```yaml theme={null}
output:
  status: 200
  headers:
    Content-Disposition: attachment; filename="event.ics"
  format: ics
  body:
    calendar: ${generate-ics.output}
```

**RSS Feed:**

```yaml theme={null}
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`:

```typescript theme={null}
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:

```yaml theme={null}
# Explicitly allow API execution
agent: my-public-agent
apiExecutable: true
```

```yaml theme={null}
# Explicitly deny API execution
ensemble: internal-workflow
apiExecutable: false
```

### Behavior Matrix

| `requireExplicit` | `apiExecutable` | Result    |
| ----------------- | --------------- | --------- |
| `false` (default) | `undefined`     | ✅ Allowed |
| `false`           | `true`          | ✅ Allowed |
| `false`           | `false`         | ❌ Denied  |
| `true`            | `undefined`     | ❌ Denied  |
| `true`            | `true`          | ✅ Allowed |
| `true`            | `false`         | ❌ Denied  |

<Note>
  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.
</Note>

***

## Examples

### Complete Ensemble

```yaml theme={null}
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}
```

```typescript theme={null}
// 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) }
}
```

```yaml theme={null}
  - 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

<CardGroup cols={2}>
  <Card title="TypeScript API" icon="code" href="/conductor/reference/ts-schema">
    TypeScript API reference
  </Card>

  <Card title="CLI Commands" icon="terminal" href="/conductor/reference/cli-commands">
    Command line reference
  </Card>

  <Card title="Operations" icon="bolt" href="/conductor/operations/overview">
    Operation details
  </Card>

  <Card title="Starter Kit" icon="layer-group" href="/conductor/starter-kit/overview">
    Pre-built agents
  </Card>
</CardGroup>
