# Workflow Compiler

> Compile visual workflow canvas to Google ADK Python code. Use when generating executable agent code from WorkflowCanvas data structures. Supports all ADK workflow patterns. Use when this capability is needed.

- Skill: `tomevault-io/workflow-compiler` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/workflow-compiler`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/workflow-compiler/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/workflow-compiler

---


# Workflow Compilation

Compile visual workflow canvas designs to executable Google ADK Python code.

## Input Format (WorkflowCanvas)

```typescript
interface WorkflowCanvas {
  id: string;
  name: string;
  description: string;
  nodes: WorkflowNode[];
  edges: WorkflowEdge[];
  rootAgentId: string;
}

interface WorkflowNode {
  id: string;
  type: 'llm' | 'sequential' | 'parallel' | 'loop' | 'condition' | 'custom';
  position: { x: number; y: number };
  data: {
    label: string;
    config: Partial<AgentConfig>;
    children?: string[];
  };
}

interface WorkflowEdge {
  id: string;
  source: string;
  target: string;
  type: 'default' | 'conditional' | 'loop';
  data?: {
    label?: string;
    condition?: string;
    outputKey?: string;
  };
}
```

## Output Format (Python ADK Code)

### Template Structure

```python
"""
Generated workflow: {workflow_name}
Description: {workflow_description}
Generated at: {timestamp}
"""

from google.adk.agents import (
    LlmAgent,
    SequentialAgent,
    ParallelAgent,
    LoopAgent,
    BaseAgent
)
from google.adk.models.lite_llm import LiteLlm

# Agent definitions
{agent_definitions}

# Workflow composition
{workflow_composition}

# Root agent export
root_agent = {root_agent_name}
```

## Compilation Rules

### LLM Agent Node

```python
# Input node
{
  "id": "research",
  "type": "llm",
  "data": {
    "label": "ResearchAgent",
    "config": {
      "modelConfig": {"provider": "gemini", "model": "gemini-2.5-flash"},
      "instruction": "Research the given topic",
      "outputKey": "research_results"
    }
  }
}

# Output code
research_agent = LlmAgent(
    name="ResearchAgent",
    model="gemini-2.5-flash",
    instruction="Research the given topic",
    output_key="research_results"
)
```

### Sequential Agent Node

```python
# Input: Container with ordered children
{
  "id": "pipeline",
  "type": "sequential",
  "data": {
    "label": "DataPipeline",
    "children": ["validate", "process", "report"]
  }
}

# Output code
data_pipeline = SequentialAgent(
    name="DataPipeline",
    sub_agents=[
        validate_agent,
        process_agent,
        report_agent
    ]
)
```

### Parallel Agent Node

```python
# Input: Container with concurrent children
{
  "id": "gatherer",
  "type": "parallel",
  "data": {
    "label": "InfoGatherer",
    "children": ["web_search", "db_search", "api_fetch"]
  }
}

# Output code
info_gatherer = ParallelAgent(
    name="InfoGatherer",
    sub_agents=[
        web_search_agent,  # output_key="web_results"
        db_search_agent,   # output_key="db_results"
        api_fetch_agent    # output_key="api_results"
    ]
)
```

### Loop Agent Node

```python
# Input: Iterative refinement
{
  "id": "refiner",
  "type": "loop",
  "data": {
    "label": "ContentRefiner",
    "config": {"maxIterations": 3},
    "children": ["critic", "reviser"]
  }
}

# Output code
content_refiner = LoopAgent(
    name="ContentRefiner",
    max_iterations=3,
    sub_agents=[
        critic_agent,
        reviser_agent
    ]
)
```

### Conditional Node (Custom)

```python
# Output: Custom BaseAgent subclass
class ConditionalRouter(BaseAgent):
    """Custom conditional routing based on state."""

    positive_agent: LlmAgent
    negative_agent: LlmAgent

    async def _run_async_impl(self, ctx):
        result = ctx.session.state.get("analysis_result", "")

        if "positive" in result.lower():
            async for event in self.positive_agent.run_async(ctx):
                yield event
        else:
            async for event in self.negative_agent.run_async(ctx):
                yield event
```

## Multi-Model Support

```python
# Gemini (native)
model="gemini-2.5-flash"

# OpenAI via LiteLLM
model=LiteLlm(model="openai/gpt-4o")

# Anthropic via LiteLLM
model=LiteLlm(model="anthropic/claude-3-haiku-20240307")

# Ollama via LiteLLM
model=LiteLlm(model="ollama_chat/llama3.2")
```

## Validation Before Compilation

1. **Root agent exists**: `rootAgentId` points to valid node
2. **No orphan nodes**: All nodes reachable from root
3. **No cycles**: DAG structure (except loops)
4. **Children exist**: All `children[]` IDs are valid
5. **Output keys unique**: Parallel agents have distinct keys

## Example Full Compilation

### Input Canvas

```json
{
  "id": "workflow-1",
  "name": "ResearchWorkflow",
  "description": "Gather and synthesize research",
  "rootAgentId": "main",
  "nodes": [
    {"id": "main", "type": "sequential", "data": {"label": "MainWorkflow", "children": ["gather", "synthesize"]}},
    {"id": "gather", "type": "parallel", "data": {"label": "InfoGatherer", "children": ["web", "db"]}},
    {"id": "web", "type": "llm", "data": {"label": "WebSearch", "config": {"outputKey": "web_results"}}},
    {"id": "db", "type": "llm", "data": {"label": "DBSearch", "config": {"outputKey": "db_results"}}},
    {"id": "synthesize", "type": "llm", "data": {"label": "Synthesizer", "config": {"instruction": "Combine {web_results} and {db_results}"}}}
  ]
}
```

### Output Code

```python
"""
Generated workflow: ResearchWorkflow
Description: Gather and synthesize research
"""

from google.adk.agents import LlmAgent, SequentialAgent, ParallelAgent

web_search = LlmAgent(
    name="WebSearch",
    model="gemini-2.5-flash",
    instruction="Search the web for relevant information",
    output_key="web_results"
)

db_search = LlmAgent(
    name="DBSearch",
    model="gemini-2.5-flash",
    instruction="Search the database for relevant records",
    output_key="db_results"
)

info_gatherer = ParallelAgent(
    name="InfoGatherer",
    sub_agents=[web_search, db_search]
)

synthesizer = LlmAgent(
    name="Synthesizer",
    model="gemini-2.5-flash",
    instruction="Combine {web_results} and {db_results} into a comprehensive summary"
)

root_agent = SequentialAgent(
    name="MainWorkflow",
    sub_agents=[info_gatherer, synthesizer]
)
```

---
> Converted and distributed by [TomeVault](https://tomevault.io/claim/rwxproject) — claim your Tome and manage your conversions.
<!-- tomevault:4.0:skill_md:2026-04-16 -->

