# Actor YAML Schema Reference ## Overview An actor defines what an agent can do, how it processes information, and how it interacts with tools and other actors. This document is the complete schema reference for the actor YAML format parsed, validated, and compiled by this library. **Module:** `cleveractors.actor.schema` **Schema Version:** 1.0 ## Table of Contents - [Actor Types](#actor-types) - [Field Definitions](#field-definitions) - [Tool Node Semantics](#tool-node-semantics) - [Graph Constraints](#graph-constraints) - [Validation Rules](#validation-rules) - [Error Messages](#error-messages) - [Examples](#examples) - [Usage](#usage) --- ## Actor Types Actors come in three types, each serving different purposes: ### LLM Actor **Type:** `llm` **Purpose:** Single LLM agent with system prompt and optional tools **Use Case:** Simple conversational agents, code reviewers, assistants **Required Fields:** - `name` - Namespaced actor name - `type: llm` - `provider` - LLM provider name (e.g., `openai`, `anthropic`); resolved at runtime via `ProviderRegistryPort` - `model` - LLM model identifier (e.g., `gpt-4`, `claude-3-opus`) **Optional Fields:** - `system_prompt` - System prompt defining agent behaviour - `tools` - List of tool references or inline definitions - `context_view` - Role-based context filtering - `memory` - Conversation history settings - `context` - File inclusion settings **Example:** ```yaml name: assistants/code_reviewer type: llm provider: openai model: gpt-4 system_prompt: "You are an expert code reviewer..." ``` ### TOOL Actor **Type:** `tool` **Purpose:** Collection of callable tools without LLM interaction **Use Case:** Utility tool bundles, shared tool libraries **Required Fields:** - `name` - Namespaced actor name - `type: tool` - `tools` - At least one tool (reference or inline definition) **Example:** ```yaml name: utilities/file_ops type: tool tools: - files/read_file - files/write_file ``` ### GRAPH Actor **Type:** `graph` **Purpose:** Multi-node workflow with conditional routing **Use Case:** Complex workflows, multi-step processes, agentic loops **Required Fields:** - `name` - Namespaced actor name - `type: graph` - `provider` - LLM provider name (e.g., `openai`, `anthropic`) - `model` - LLM model for agent nodes - `route` - Complete graph topology definition **Optional Fields:** - `system_prompt` - Default prompt for graph-level agents - `tools` - Tools available to all agent nodes - `context_view` - Context filtering for the entire graph - `memory` - Memory settings for the graph - `context` - Context settings **Example:** ```yaml name: workflows/test_driven_dev type: graph provider: openai model: gpt-4 route: nodes: [...] edges: [...] entry_node: planner exit_nodes: [review] ``` --- ## Field Definitions ### Top-Level Fields #### `name` (required) **Type:** `str` **Format:** `namespace/actor_name` **Description:** Unique identifier for the actor in namespaced format **Validation:** - Must contain exactly one forward slash (`/`) - Namespace and name must not be empty - Should use snake_case for both parts **Valid:** - `assistants/code_reviewer` - `workflows/test_driven_dev` - `utilities/file_operations` **Invalid:** - `code_reviewer` (missing namespace) - `assistants/code/reviewer` (too many slashes) - `assistants/` (empty name) #### `type` (required) **Type:** `ActorType` enum **Values:** `llm`, `tool`, `graph` **Description:** Determines actor execution behaviour and compilation target #### `description` (required) **Type:** `str` **Description:** Human-readable description of what the actor does **Best Practices:** - Start with a verb ("Reviews code...", "Processes documents...") - Keep under 200 characters - Be specific about the actor's purpose #### `version` (optional) **Type:** `str` **Default:** `"1.0"` **Description:** Schema version for compatibility tracking #### `provider` (conditional) **Type:** `str` **Required for:** `llm`, `graph` actors **Optional for:** `tool` actors (not used) **Description:** LLM provider name resolved at runtime by the host via `cleveractors.ports.provider_registry.ProviderRegistryPort`. See [ADR-005](../adr/ADR-005-provider-registry-protocol.md) for the runtime resolution contract. **Common Values:** - OpenAI: `openai` - Anthropic: `anthropic` - Google: `google` **Validation:** - `LLM and GRAPH actors require 'provider' field` if missing for `llm` or `graph` actors. #### `model` (conditional) **Type:** `str` **Required for:** `llm`, `graph` actors **Optional for:** `tool` actors (not used) **Description:** LLM model identifier passed to the host's `ProviderRegistryPort` **Common Values:** - OpenAI: `gpt-4`, `gpt-4-turbo`, `gpt-3.5-turbo` - Anthropic: `claude-3-opus`, `claude-3-sonnet`, `claude-3-haiku` - Open source: `mistral-large`, `llama-3-70b` #### `system_prompt` (optional) **Type:** `str` **Description:** System prompt defining agent behaviour and guidelines. Supports Jinja2 template syntax — see [ADR-004](../adr/ADR-004-jinja2-yaml-template-preprocessing.md) for details. **Best Practices:** - Use multi-line YAML strings (`|`) for readability - Include role definition ("You are an expert...") - List specific tasks and constraints - Provide output format guidance #### `tools` (optional / required for `tool` actors) **Type:** `list[str | ToolDefinition]` **Required for:** `tool` actors **Optional for:** `llm`, `graph` actors **Description:** Tools available to the actor **Tool Reference Format:** ```yaml tools: - namespace/tool_name # Reference to a named tool ``` **Inline Tool Definition:** ```yaml tools: - name: utils/count_lines description: Count lines in a file parameters: - name: file_path type: str required: true code: | def count_lines(file_path: str) -> int: with open(file_path, 'r') as f: return len(f.readlines()) ``` --- ### Tool Definition Fields #### ToolParameter **Fields:** - `name` (str, required): Parameter name (must be valid Python identifier) - `type` (str, required): Python type annotation (e.g., `str`, `int`, `list[str]`) - `description` (str, required): Parameter description - `required` (bool, default=True): Whether parameter is required - `default` (any, optional): Default value for optional parameters **Example:** ```yaml parameters: - name: input_file type: str description: Path to input file required: true - name: encoding type: str description: File encoding required: false default: utf-8 ``` #### ToolDefinition **Fields:** - `name` (str, required): Tool name in `namespace/name` format - `description` (str, required): What the tool does - `parameters` (list, optional): List of ToolParameter objects - `code` (str, required): Python code implementing the tool **Validation:** - Tool name must follow `namespace/name` format - Code must be valid Python - Parameter names must be valid identifiers --- ### Memory Configuration #### MemoryConfig **Fields:** - `enabled` (bool, default=True): Enable conversation memory - `max_messages` (int, optional): Maximum messages to retain (None = unlimited) - `max_tokens` (int, optional): Maximum tokens in history (None = unlimited) - `summarize_old` (bool, default=False): Summarize old messages to save tokens **Example:** ```yaml memory: enabled: true max_messages: 50 max_tokens: 4000 summarize_old: false ``` **Use Cases:** - Short conversations: `max_messages: 10-20` - Medium conversations: `max_messages: 50`, `max_tokens: 4000-8000` - Long workflows: `summarize_old: true`, `max_tokens: 16000` --- ### Context Configuration #### ContextConfigSchema **Fields:** - `include_files` (list[str]): Specific files to include in context - `include_dirs` (list[str]): Directories to include in context - `exclude_patterns` (list[str]): Glob patterns to exclude - `max_context_tokens` (int, optional): Maximum context window size **Example:** ```yaml context: include_files: - README.md - pyproject.toml include_dirs: - src/ - tests/ exclude_patterns: - "**/__pycache__/**" - "*.pyc" - "**/.git/**" max_context_tokens: 8000 ``` #### ContextView **Type:** enum **Values:** `strategist`, `executor`, `reviewer`, `full` **Description:** Role-based context filtering hint; consumed by the host's context assembly layer. **Context Views:** - **strategist**: High-level planning view - Project structure, goals, architecture decisions - No implementation details - **executor**: Implementation view - Source code, file contents, specific tasks - Implementation details - **reviewer**: Validation view - Changes and diffs, test results, code quality metrics - **full**: Complete view (use sparingly) - All available context; can exceed token limits --- ## Tool Node Semantics ### Tool References Tool references point to named tools that the host resolves via its tool registry at runtime. Use references when: - The tool is shared across multiple actors - The tool is complex and tested separately - The tool requires specific dependencies **Format:** `namespace/tool_name` **Example:** ```yaml tools: - files/read_file - testing/run_pytest - analysis/extract_entities ``` ### Inline Tool Definitions Inline tools are defined directly in the actor YAML. Use inline tools when: - The tool is actor-specific - The tool is simple (< 50 lines of code) - The tool doesn't require external dependencies **Best Practices:** 1. Keep inline tools simple and focused 2. Include proper error handling 3. Add docstrings to the function 4. Use type hints for all parameters 5. Validate inputs before processing **Example:** ```yaml tools: - name: utils/count_words description: Count words in a text file parameters: - name: file_path type: str description: Path to text file required: true code: | def count_words(file_path: str) -> dict: """Count words in a file and return statistics.""" try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() words = content.split() return { "word_count": len(words), "char_count": len(content), "line_count": content.count('\n') + 1 } except FileNotFoundError: return {"error": f"File not found: {file_path}"} except Exception as e: return {"error": str(e)} ``` --- ## Graph Constraints ### Graph Topology A graph actor's `route` field defines the complete workflow topology. #### RouteDefinition **Fields:** - `nodes` (list[NodeDefinition], required): All nodes in the graph - `edges` (list[EdgeDefinition], required): Connections between nodes - `entry_node` (str, required): Starting node ID - `exit_nodes` (list[str], required): Terminal node IDs ### Node Types #### AGENT Node **Type:** `agent` **Purpose:** LLM-powered decision making and content generation **Configuration:** ```yaml - id: planner type: agent name: Task Planner description: Plans tasks based on requirements config: model: gpt-4 # Can override graph-level model prompt: "You are a task planning expert..." tools: - files/read_file - analysis/extract_requirements ``` #### TOOL Node **Type:** `tool` **Purpose:** Execute specific tools or functions **Configuration:** ```yaml - id: run_tests type: tool name: Test Runner description: Executes pytest test suite config: tool_name: testing/run_pytest parameters: verbose: true coverage: true ``` #### CONDITIONAL Node **Type:** `conditional` **Purpose:** Route execution based on conditions **Configuration:** ```yaml - id: check_results type: conditional name: Result Checker description: Routes based on test results config: conditions: - check: "state.get('tests_passed') == True" route_to: code_review - check: "state.get('tests_passed') == False" route_to: fix_errors ``` **Conditional Expressions:** - Access state with `state.get('key')` - Use Python comparison operators (`==`, `!=`, `<`, `>`, `<=`, `>=`) - Combine with boolean operators (`and`, `or`, `not`) - Conditions are evaluated in order; first match wins #### SUBGRAPH Node **Type:** `subgraph` **Purpose:** Embed another actor as a nested workflow **Configuration:** ```yaml - id: code_review type: subgraph name: Code Reviewer description: Runs full code review workflow actor_ref: local/code-reviewer ``` **Subgraph Rules:** - Reference the actor by its namespaced name via `actor_ref` - State is passed to and from the subgraph - Subgraphs enable workflow composition and reuse - Circular subgraph references are rejected at compile time ### Edge Definition **Fields:** - `from_node` (str, required): Source node ID - `to_node` (str, required): Target node ID - `condition` (str, optional): Conditional routing expression - `priority` (int, default=0): Edge priority (higher = evaluated first) **Example:** ```yaml edges: # Unconditional edge - from_node: planner to_node: executor # Conditional edge - from_node: executor to_node: retry condition: "state.get('retry_count', 0) < 3" priority: 10 # Default edge (lower priority) - from_node: executor to_node: escalate priority: 1 ``` --- ## Validation Rules ### Graph Validation The schema automatically validates graph topology when loading YAML files. #### 1. Unique Node IDs **Rule:** All node IDs must be unique within a graph. **Valid:** ```yaml nodes: - id: planner - id: executor - id: reviewer ``` **Invalid:** ```yaml nodes: - id: planner - id: executor - id: planner # ❌ Duplicate ID ``` **Error:** ``` ValueError: Duplicate node IDs found: {'planner'} ``` #### 2. Entry Node Exists **Rule:** The `entry_node` must reference a valid node ID. **Invalid:** ```yaml nodes: - id: start entry_node: init # ❌ 'init' doesn't exist ``` **Error:** ``` ValueError: Entry node 'init' not found in nodes ``` #### 3. Exit Nodes Exist **Rule:** All `exit_nodes` must reference valid node IDs. **Invalid:** ```yaml exit_nodes: - end1 - finish # ❌ 'finish' doesn't exist ``` **Error:** ``` ValueError: Exit node 'finish' not found in nodes ``` #### 4. Edge References Valid **Rule:** All edge `from_node` and `to_node` must reference valid node IDs. **Invalid:** ```yaml edges: - from_node: a to_node: c # ❌ 'c' doesn't exist ``` **Error:** ``` ValueError: Edge to_node 'c' not found in nodes ``` #### 5. No Cycles **Rule:** Graphs must be acyclic (no circular dependencies). **Invalid:** ```yaml edges: - from_node: a to_node: b - from_node: b to_node: c - from_node: c to_node: a # ❌ Cycle: a → b → c → a ``` **Error:** ``` ValueError: Graph contains cycles involving nodes: ['a'] ``` #### 6. All Nodes Reachable **Rule:** All nodes must be reachable from the entry node. **Invalid:** ```yaml entry_node: start nodes: - id: start - id: process - id: orphan # ❌ Not reachable from 'start' edges: - from_node: start to_node: process ``` **Error:** ``` ValueError: Unreachable nodes detected: {'orphan'} ``` --- ## Error Messages ### Common Validation Errors #### NameError: Invalid Actor Name **Cause:** Actor name doesn't follow `namespace/name` format ```yaml name: code_reviewer # ❌ Missing namespace ``` **Error:** ``` ValueError: Actor name must be namespaced (namespace/name): code_reviewer ``` **Fix:** ```yaml name: assistants/code_reviewer # ✅ ``` #### TypeError: Missing Required Field **Cause:** LLM or GRAPH actor missing `model` field **Error:** ``` ValueError: LLM actors require 'model' field ``` **Cause:** LLM or GRAPH actor missing `provider` field **Error:** ``` ValueError: LLM and GRAPH actors require 'provider' field ``` **Fix:** ```yaml provider: openai ``` #### ValueError: Empty Tools List **Cause:** TOOL actor with no tools defined **Error:** ``` ValueError: TOOL actors require at least one tool ``` #### ValueError: Missing Route **Cause:** GRAPH actor without route definition **Error:** ``` ValueError: GRAPH actors require 'route' field ``` --- ## Examples ### Example 1: Simple LLM Actor ```yaml name: assistants/code_reviewer type: llm description: Reviews Python code for best practices version: "1.0" provider: openai model: gpt-4 system_prompt: | You are an expert Python code reviewer. Review code for: - PEP 8 compliance - Design patterns - Potential bugs - Performance issues context_view: reviewer memory: enabled: true max_messages: 20 ``` ### Example 2: LLM with Inline Tools ```yaml name: assistants/file_analyzer type: llm description: Analyzes files and generates reports version: "1.0" provider: openai model: gpt-4-turbo system_prompt: "Analyze files and provide insights..." tools: - files/read_file # Tool reference - name: utils/count_lines # Inline tool description: Count lines in a file parameters: - name: file_path type: str required: true code: | def count_lines(file_path: str) -> int: with open(file_path, 'r') as f: return len(f.readlines()) ``` ### Example 3: Simple Graph Workflow ```yaml name: workflows/doc_processor type: graph description: Processes documents through multiple stages version: "1.0" provider: openai model: gpt-3.5-turbo route: nodes: - id: extract type: tool name: Text Extractor description: Extracts text from documents config: tool_name: documents/extract_text - id: analyze type: agent name: Analyzer description: Analyzes content config: model: gpt-3.5-turbo prompt: "Analyze the document content..." - id: summarize type: agent name: Summarizer description: Creates summary config: model: gpt-3.5-turbo prompt: "Summarize in 3-5 bullet points..." edges: - from_node: extract to_node: analyze - from_node: analyze to_node: summarize entry_node: extract exit_nodes: - summarize ``` ### Example 4: Complex Graph with Conditionals ```yaml name: workflows/ci_pipeline type: graph description: CI/CD pipeline with test and deploy stages version: "1.0" provider: openai model: gpt-4 route: nodes: - id: build type: tool name: Builder description: Builds the project config: tool_name: ci/build - id: test type: tool name: Test Runner description: Runs test suite config: tool_name: ci/run_tests - id: check_tests type: conditional name: Test Result Checker description: Check if tests passed config: conditions: - check: "state.get('tests_passed') == True" route_to: deploy - check: "state.get('tests_passed') == False" route_to: notify_failure - id: deploy type: tool name: Deployer description: Deploys to production config: tool_name: ci/deploy - id: notify_failure type: tool name: Notifier description: Sends failure notification config: tool_name: notifications/send_alert edges: - from_node: build to_node: test - from_node: test to_node: check_tests # Conditional routing handled by check_tests node entry_node: build exit_nodes: - deploy - notify_failure ``` --- ## Usage ### Loading Actor Configuration ```python from cleveractors.actor.schema import ActorConfigSchema from cleveractors.actor.yaml_loader import load_yaml_text # Load from file with open("actors/code_reviewer.yaml") as f: raw = load_yaml_text(f.read()) actor = ActorConfigSchema.model_validate(raw) # Access fields print(actor.name) # assistants/code_reviewer print(actor.type) # ActorType.LLM print(actor.model) # gpt-4 # Validation is automatic on load: # - All nodes have unique IDs # - Entry/exit nodes exist # - All edges reference valid nodes # - No cycles detected # - All nodes reachable ``` ### Compiling an Actor ```python from cleveractors.actor.compiler import compile_actor compiled = compile_actor(actor) print(compiled.metadata.node_ids) # list of all node IDs print(compiled.metadata.lsp_bindings) # extracted LSP bindings ``` --- ## See Also - [ADR-003: Actor Abstraction Definition](../adr/ADR-003-actor-abstraction-definition.md) - [Actor Configuration Guide](actor_config.md) — practical authoring guide - [Actor Hierarchy Extensions](actor_hierarchy.md) — LSP bindings and tool sources - [Actor Compiler](actor_compiler.md) — compilation pipeline