Compilation Flow
This page explains how data flows through the SDK when compiling an Agent Definition.
Overview
The compilation process follows a clear pipeline:
Builder API -> AgentDefinition -> validate() -> export_yaml()
| | |
Domain Schema + Gates + Static YAMLStep-by-Step Breakdown
Step 1: Build
Developers use fluent builders to construct their agent:
from ainalyn import AgentBuilder, WorkflowBuilder, NodeBuilder
agent = (
AgentBuilder("my-agent")
.version("1.0.0")
.description("My first agent")
.add_workflow(
WorkflowBuilder("main")
.add_node(NodeBuilder("start").type("llm").build())
.build()
)
.build() # ← Returns AgentDefinition
)What happens:
AgentBuilderis an Inbound Adapter- Collects configuration via fluent methods
.build()creates an immutableAgentDefinition
Step 2: Create Domain Entity
The builder creates an AgentDefinition domain entity:
@dataclass(frozen=True)
class AgentDefinition:
name: str
version: str
description: str
workflows: tuple[Workflow, ...]
def __post_init__(self) -> None:
# Domain validation runs immediately
if not DefinitionRules.is_valid_name(self.name):
raise InvalidFormatError(...)What happens:
- Entity is created as frozen (immutable)
__post_init__runs domain validation- Invalid entities cannot exist
Step 3: Compile via API
Developer calls the high-level API:
from ainalyn import compile_agent
from pathlib import Path
result = compile_agent(agent, Path("agent.yaml"))What happens:
compile_agent()is an Inbound Adapter (public API)- Gets
DefinitionServicefrom infrastructure - Delegates to service for orchestration
Internal flow:
# api.py
def compile_agent(definition, output_path=None):
service = _get_service() # From infrastructure
if output_path:
return service.compile_to_file(definition, output_path)
return service.compile(definition)Step 4a: Schema Validation
SchemaValidator checks structural correctness:
class SchemaValidator:
"""Outbound Adapter implementing IDefinitionSchemaValidator"""
def validate_schema(self, definition: AgentDefinition) -> tuple[ValidationError, ...]:
errors = []
# Required fields
if not definition.workflows:
errors.append(ValidationError("E001", "At least one workflow required"))
# Type validation
for workflow in definition.workflows:
if not workflow.nodes:
errors.append(ValidationError("E002", f"Workflow '{workflow.name}' has no nodes"))
return tuple(errors)Checks performed:
- Required fields present
- Type correctness
- Value constraints
- Structural integrity
Step 4b: Review Gates
ReviewGateRules enforces platform-aligned contract checks:
- Contract completeness
- No shadow runtime patterns
- Result sovereignty
- Billing hint only
- EIP dependency declarations
Step 4c: Static Analysis
StaticAnalyzer checks logical correctness:
from ainalyn.domain.rules import DefinitionRules
class StaticAnalyzer:
def analyze(self, definition: AgentDefinition) -> tuple[ValidationError, ...]:
issues = []
for workflow in definition.workflows:
cycles = DefinitionRules.detect_circular_dependencies(workflow)
if cycles:
issues.append(ValidationError(code="CIRCULAR_DEPENDENCY", path=f"workflow:{workflow.name}", message="Cycle detected"))
unreachable = DefinitionRules.get_unreachable_nodes(workflow)
for node_name in unreachable:
issues.append(ValidationError(code="UNREACHABLE_NODE", path=f"workflow:{workflow.name}", message=f"Unreachable node: {node_name}"))
return tuple(issues)Checks performed:
- Workflow cycles
- Unreachable nodes
- Unused resources
Step 4d: Serialization
YamlExporter converts domain to YAML:
class YamlExporter:
"""Outbound Adapter implementing IDefinitionSerializer"""
def serialize(self, definition: AgentDefinition) -> str:
data = {
"name": definition.name,
"version": definition.version,
"description": definition.description,
"workflows": [
self._serialize_workflow(w) for w in definition.workflows
],
}
return yaml.dump(data, sort_keys=False)What happens:
- Domain entities → Python dicts
- Dicts → YAML string
- Platform-compatible format
Step 5: Output
CompilationResult contains the outcome:
@dataclass
class CompilationResult:
validation_result: ValidationResult
yaml_content: str | None # None if validation failed
output_path: Path | None # Set if written to file
@property
def is_successful(self) -> bool:
return self.validation_result.is_validUsage:
result = compile_agent(agent)
if result.is_successful:
print(result.yaml_content)
# Submit to platform
else:
for error in result.validation_result.errors:
print(f"{error.code}: {error.message}")Validation Layers
The SDK has multiple validation layers, each with a specific responsibility:
| Layer | Location | When | Purpose |
|---|---|---|---|
| Domain | domain/entities/ | Entity creation | Invariants that must always hold |
| Schema | adapters/outbound/schema_validator.py | Compilation | Structural correctness |
| Review Gates | domain/rules/review_gate_rules.py | Compilation | Contract gate enforcement |
| Static Analysis | adapters/outbound/static_analyzer.py | Compilation | Logical correctness |
Domain Validation Example
# Cannot create invalid entity
AgentDefinition(name="invalid name!") # Raises InvalidFormatErrorSchema Validation Example
# Valid entity, but missing required fields for platform
agent = AgentBuilder("test").build() # Missing version
result = compile_agent(agent)
# result.validation_result.errors contains "version required"Review Gates Example
# Example: missing task_goal or output_schema triggers gate violations
result = validate(agent)
for error in result.errors:
print(error.code, error.message)Static Analysis Example
# Valid structure, but logical error
workflow = (
WorkflowBuilder("main")
.add_node(NodeBuilder("a").next_nodes("b").build())
.add_node(NodeBuilder("b").next_nodes("a").build()) # Creates cycle!
.build()
)
result = compile_agent(agent)
# result.validation_result.errors contains "cycle detected"Error Handling
Error Categories
| Category | Code Range | Example |
|---|---|---|
| Domain Errors | Exceptions | InvalidFormatError, CyclicDependencyError |
| Schema Errors | E001-E099 | Missing required field |
| Analysis Errors | E100-E199 | Invalid reference |
| Analysis Warnings | W001-W099 | Unused definition |
Error Response
result = compile_agent(agent)
if not result.is_successful:
for error in result.validation_result.errors:
print(f"[{error.code}] {error.message}")
print(f" Path: {error.path}")
print(f" Suggestion: {error.suggestion}")Related Pages
- Hexagonal Architecture - How components are organized
- System Context - SDK’s role in the system
- Validation Guide - User-facing validation docs