DocsArchitectureDirector & Orchestration

The Director is Ryvos's highest-level orchestration system. Given a goal, it uses the LLM to generate a multi-step execution plan as a directed acyclic graph (DAG), executes each node, evaluates results, and evolves the plan if needed.

When to Use the Director

The Director is enabled by default for goal-driven runs. Use it when:

  • The task has multiple distinct steps that depend on each other
  • You need evaluation against specific success criteria
  • The task might need re-planning if initial approaches fail
  • You want automated quality assessment
# Director is used automatically with --director flag
ryvos run --director "migrate the database from PostgreSQL to SQLite"
 
# Or with a goal file
ryvos run --goal migrate.toml "start the migration"

OODA Loop

The Director follows an Observe-Orient-Decide-Act loop:

┌─────────────────────────────────────────────┐
│              Director OODA Loop              │
│                                              │
│  1. OBSERVE: Parse the goal and constraints  │
│  2. ORIENT: Generate execution graph (DAG)   │
│  3. DECIDE: Select entry node                │
│  4. ACT: Execute graph node-by-node          │
│  5. EVALUATE: Check results against goal     │
│  6. EVOLVE: If failed, diagnose and re-plan  │
│                                              │
│  Repeat up to max_evolution_cycles           │
└─────────────────────────────────────────────┘

Goal Definition

Goals are structured definitions with weighted success criteria:

# migrate.toml
[goal]
description = "Migrate user data from PostgreSQL to SQLite"
success_threshold = 0.9
 
[[goal.criteria]]
id = "schema_created"
type = "llm_judge"
weight = 0.3
description = "SQLite schema matches PostgreSQL schema"
prompt = "Does the SQLite database have equivalent tables and columns?"
 
[[goal.criteria]]
id = "data_migrated"
type = "llm_judge"
weight = 0.5
description = "All user records are migrated correctly"
prompt = "Are all records present in SQLite with correct data?"
 
[[goal.criteria]]
id = "tests_pass"
type = "output_contains"
weight = 0.2
description = "Migration tests pass"
value = "test result: ok"
 
[[goal.constraints]]
category = "time"
description = "Complete within 10 minutes"
hard = false
 
[[goal.constraints]]
category = "safety"
description = "Do not drop the PostgreSQL tables"
hard = true

Criterion Types

TypeDescription
output_containsFinal output contains a specific string
output_equalsFinal output exactly matches a string
llm_judgeLLM evaluates the output against a custom prompt
customNamed custom evaluation function

Criteria are weighted. The overall score is the weighted sum of individual scores, and the goal passes if it exceeds success_threshold.

Constraints

CategoryDescription
timeTime limits
costToken/dollar limits
safetyActions to avoid
scopeBoundaries of the task
qualityOutput quality requirements

Hard constraints cause immediate failure if violated. Soft constraints are reported but do not stop execution.

DAG Graph Execution

The Director asks the LLM to generate a DAG of execution nodes:

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  Analyze     │────>│  Create      │────>│  Migrate     │
│  PostgreSQL  │     │  SQLite      │     │  Data        │
│  Schema      │     │  Schema      │     │              │
└──────────────┘     └──────────────┘     └──────┬───────┘
                                                  │
                                           ┌──────┴───────┐
                                           │  Verify      │
                                           │  Migration   │
                                           └──────────────┘

Node Structure

Each node is an independent agent run:

struct Node {
    id: String,              // Unique identifier
    agent_prompt: String,    // What this node should do
    goal: Option<Goal>,      // Optional per-node goal
    max_turns: usize,        // Turn limit for this node
    system_prompt: Option<String>,  // Override system prompt
}

Edge Conditions

Edges between nodes have conditions that control execution flow:

ConditionDescription
AlwaysAlways follow this edge
OnSuccessFollow only if the source node succeeded
OnFailureFollow only if the source node failed
ConditionalFollow if a specific condition is met in the handoff context
LlmDecideAsk the LLM whether to follow this edge

Handoff Context

Nodes share data through a HandoffContext (a HashMap<String, Value>). When a node completes, it can write results that downstream nodes read:

Node A writes: { "schema": "CREATE TABLE users (...)" }
    ↓
Node B reads: handoff["schema"] to create the SQLite tables

Graph Executor

The GraphExecutor walks the DAG:

  1. Start at the entry node
  2. Execute the node as a full agent run
  3. Evaluate edge conditions from the completed node
  4. Follow matching edges to the next node(s)
  5. Repeat until no more nodes or all paths complete
  6. Collect results from all terminal nodes
GraphExecutor::execute(
    nodes,
    edges,
    entry_id,
    runtime,
    session_id,
).await -> ExecutionResult

Evolution Cycles

If the goal is not met after the first graph execution, the Director enters an evolution cycle:

  1. Diagnose — Analyze what went wrong using semantic failure detection
  2. Re-plan — Ask the LLM to generate an improved graph
  3. Execute — Run the new graph
  4. Evaluate — Check against the goal again

This repeats up to max_evolution_cycles (default: 3).

Semantic Failure Types

The Director classifies failures into five categories:

Failure TypeDescription
LogicContradictionThe plan contradicted itself
VelocityDriftProgress stalled or went in the wrong direction
ConstraintViolationA hard constraint was broken
FailureAccumulationToo many individual node failures
QualityDeficiencyOutput quality does not meet criteria

Each failure type generates targeted re-planning instructions. For example, a VelocityDrift failure prompts the LLM to try a fundamentally different approach rather than tweaking the same plan.

Events

The Director publishes events on the EventBus throughout execution:

EventWhen
GraphGeneratedLLM produces the initial DAG
NodeCompleteA single node finishes execution
GoalEvaluatedGoal evaluation completed (score + pass/fail)
EvolutionTriggeredStarting a new evolution cycle
SemanticFailureCapturedA failure type was diagnosed
DecisionMadeRouting decision at a conditional edge

Multi-Agent Orchestrator

For tasks that benefit from specialized agents, the MultiAgentOrchestrator provides routing:

┌─────────────────────────────────────────┐
│          Orchestrator                    │
│                                          │
│  Agent A: code specialist                │
│  Agent B: database specialist            │
│  Agent C: testing specialist             │
│                                          │
│  Task → match_score() → best agent       │
└─────────────────────────────────────────┘

Dispatch Modes

ModeBehavior
ParallelSend task to multiple agents, merge results
RelayPass through agents sequentially, each refining
BroadcastSend to all agents, collect all responses

Agent Capabilities

Each agent in the orchestrator declares:

  • Available tools (subset of the full registry)
  • Specializations (keywords for routing)
  • Security policy overrides (e.g., higher trust for code agent)

Configuration

[agent.director]
enabled = true                    # Enable Director for goal-driven runs
max_evolution_cycles = 3          # Max re-planning attempts

Goals can be passed via the CLI:

# Inline
ryvos run --director "build a REST API for the user model"
 
# From file
ryvos run --goal task.toml "execute the plan"

Next Steps