# Workflow YAML Reference

This page describes the complete YAML schema for defining Yagra workflows.

## Overview

A workflow YAML file defines:
- **Nodes**: Processing units (e.g., classifiers, generators, evaluators)
- **Edges**: Transitions between nodes (unconditional or conditional)
- **Start/End points**: Entry and exit nodes

Yagra validates the YAML against a Pydantic schema (`GraphSpec`) and builds a LangGraph `StateGraph`.

## Top-Level Structure

```yaml
version: "1.0"           # Required: Schema version
start_at: "node_id"      # Required: Entry node ID
end_at:                  # Required: List of exit node IDs
  - "finish"
  - "error_handler"
nodes:                   # Required: List of node definitions
  - id: "node_1"
    handler: "handler_name"
    params: {}
edges:                   # Required: List of edge definitions
  - source: "node_1"
    target: "node_2"
    condition: null      # Optional: Conditional branching
params: {}               # Optional: Global parameters
```

## Node Specification

Each node defines a processing unit.

### Basic Node

```yaml
nodes:
  - id: "classifier"
    handler: "classify_intent"
```

- `id` (str, required): Unique node identifier
- `handler` (str, required): Handler function name (resolved via registry)

### Node with Parameters

```yaml
nodes:
  - id: "generator"
    handler: "generate_answer"
    params:
      prompt_ref: "../prompts/generator.yaml#system"
      model:
        provider: "openai"
        name: "gpt-4.1-mini"
        kwargs:
          temperature: 0.7
          max_tokens: 1000
```

- `params` (dict, optional): Parameters passed to the handler
  - `prompt_ref`: External prompt reference (see [Prompt & Model](prompt_model.md))
  - `model`: Model configuration (inline definition)
  - Custom parameters: Any additional data your handler needs

### Node Handler Signature

Your handler function receives `(state, params)` or just `(state)`:

```python
def my_handler(state: AgentState, params: dict) -> dict:
    prompt = params.get("prompt", {})
    model = params.get("model", {})
    # ... process state and return updates
    return {"key": "value"}
```

Yagra tries calling with `params` first, falls back to `state`-only if that fails.

## Edge Specification

Edges define transitions between nodes.

### Unconditional Edge

```yaml
edges:
  - source: "node_1"
    target: "node_2"
```

Always transitions from `node_1` to `node_2`.

### Conditional Edge

```yaml
edges:
  - source: "classifier"
    target: "faq_bot"
    condition: "faq"
  - source: "classifier"
    target: "general_bot"
    condition: "general"
```

- `condition` (str, optional): Branching label
- The source node must return `{"__next__": "faq"}` or `{"__next__": "general"}`

**Contract**: The source node is responsible for setting `__next__` in the state.

Example:

```python
def classifier(state: AgentState, params: dict) -> dict:
    intent = "faq" if "pricing" in state["query"] else "general"
    return {"intent": intent, "__next__": intent}
```

## Start and End Points

### `start_at`

The node ID where execution begins.

```yaml
start_at: "classifier"
```

### `end_at`

A list of node IDs where execution can terminate.

```yaml
end_at:
  - "finish"
  - "error"
```

Yagra registers these nodes as LangGraph finish points. When execution reaches any of these nodes, the graph stops.

**Note**: Do not write `END` explicitly in YAML—Yagra handles this internally.

## Global Parameters

Optional top-level `params` apply to all nodes unless overridden.

```yaml
params:
  default_temperature: 0.7
  retry_limit: 3

nodes:
  - id: "node_1"
    handler: "handler_1"
    params:
      temperature: 0.9  # Overrides default
```

## Validation Rules

Yagra validates workflows before building the graph:

1. **Schema compliance**: YAML must match `GraphSpec` Pydantic model
2. **Node ID uniqueness**: No duplicate node IDs
3. **Edge references**: All `source`/`target` must reference existing nodes
4. **Start/End validity**: `start_at` and `end_at` nodes must exist
5. **Prompt references**: `prompt_ref` paths must resolve to valid files

Use `yagra validate` to check compliance:

```bash
yagra validate --workflow workflow.yaml --format json
```

## Example: Complete Workflow

```yaml
version: "1.0"
start_at: "retrieve"
end_at:
  - "generate"

nodes:
  - id: "retrieve"
    handler: "retrieve_documents"
    params:
      top_k: 5
  - id: "rerank"
    handler: "rerank_documents"
    params:
      prompt_ref: "../prompts/rerank.yaml#system"
  - id: "generate"
    handler: "generate_answer"
    params:
      prompt_ref: "../prompts/generate.yaml#system"
      model:
        provider: "anthropic"
        name: "claude-3-sonnet"

edges:
  - source: "retrieve"
    target: "rerank"
  - source: "rerank"
    target: "generate"
```

## Next Steps

- [Prompt & Model Configuration](prompt_model.md)
- [Branching & Loops](branching_loops.md)
- [CLI Reference](../cli_reference.md)
