> ## Documentation Index
> Fetch the complete documentation index at: https://docs.leeroo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> Deep dive into modules, data flow, and component relationships

## System Architecture

The deployment system uses a **plugin-based architecture** where strategies are self-contained packages that can be added without modifying core code.

```mermaid theme={null}
flowchart LR
    K[Kapso.deploy] --> F[DeploymentFactory]
    F --> SEL[SelectorAgent]
    F --> ADP[AdapterAgent]
    SEL --> REG[StrategyRegistry]
    ADP --> REG
    F --> RUN[Runner]
    RUN --> SW[DeployedSoftware]
    SW --> K
```

| Component             | Module                   | Role                                                    |
| --------------------- | ------------------------ | ------------------------------------------------------- |
| **DeploymentFactory** | `factory.py`             | Orchestrates selection, adaptation, and runner creation |
| **SelectorAgent**     | `selector/agent.py`      | LLM-based strategy selection                            |
| **AdapterAgent**      | `adapter/agent.py`       | Code transformation for target platform                 |
| **StrategyRegistry**  | `strategies/base.py`     | Auto-discovery of strategy plugins                      |
| **Runner**            | `strategies/*/runner.py` | Infrastructure-specific execution                       |
| **DeployedSoftware**  | `software.py`            | Unified wrapper for user interaction                    |

## Module Breakdown

### Directory Structure

```
src/deployment/
├── __init__.py              # Public exports
├── base.py                  # Data models and abstractions
├── factory.py               # DeploymentFactory orchestration
├── software.py              # DeployedSoftware unified wrapper
├── selector/
│   ├── agent.py             # SelectorAgent (strategy selection)
│   ├── selection_prompt.md  # LLM prompt template
│   └── correction_prompt.md # Error correction prompt
├── adapter/
│   ├── agent.py             # AdapterAgent (code transformation)
│   ├── adaptation_prompt.txt # LLM prompt template
│   └── validator.py         # Adaptation validation
└── strategies/
    ├── base.py              # Runner ABC, StrategyRegistry
    ├── README.md            # Strategy development guide
    ├── local/               # Local strategy plugin
    ├── docker/              # Docker strategy plugin
    ├── modal/               # Modal strategy plugin
    ├── bentoml/             # BentoML strategy plugin
    └── langgraph/           # LangGraph strategy plugin
```

***

## Core Components

### DeploymentFactory (`factory.py`)

The **orchestrator** that manages the full deployment pipeline.

**Responsibilities:**

* Coordinate selection, adaptation, and runner creation
* Handle strategy validation
* Create unified Software instances

**Flow:**

```python theme={null}
# Phase 1: Selection
if strategy == DeployStrategy.AUTO:
    setting = cls._select_strategy(config, strategies)
else:
    setting = cls._create_setting(strategy)

# Phase 2: Adaptation  
adaptation = cls._adapt_repo(config, setting, strategies)

# Phase 3: Runner creation
runner = cls._create_runner(config, setting, adaptation)

# Phase 4: Wrap in unified interface
return DeployedSoftware(config=config, runner=runner, info=info)
```

***

### SelectorAgent (`selector/agent.py`)

**LLM-based strategy selection** that analyzes code and chooses the optimal deployment target.

**Responsibilities:**

* Gather selector instructions from all strategies
* Query coding agent to analyze repository
* Return `DeploymentSetting` with chosen strategy

| Method      | Input                                           | Output                           |
| ----------- | ----------------------------------------------- | -------------------------------- |
| `select()`  | `SolutionResult`, optional `allowed_strategies` | `DeploymentSetting`              |
| `explain()` | `SolutionResult`                                | `str` human-readable explanation |

***

### AdapterAgent (`adapter/agent.py`)

**Code transformation and deployment** using coding agents.

**Responsibilities:**

* Create adapted workspace (copy of original)
* Load adapter instructions for target strategy
* Run coding agent to transform code
* Extract endpoint URL and run interface from output

| Method    | Input                                 | Output             |
| --------- | ------------------------------------- | ------------------ |
| `adapt()` | `SolutionResult`, `DeploymentSetting` | `AdaptationResult` |

**Key Output Extraction:**

The adapter looks for special XML tags in the coding agent's output:

```xml theme={null}
<run_interface>{"type": "function", "module": "main", "callable": "predict"}</run_interface>
<endpoint_url>https://my-app.modal.run</endpoint_url>
```

***

### StrategyRegistry (`strategies/base.py`)

**Auto-discovery system** for deployment strategies.

**Responsibilities:**

* Scan `strategies/` directory on startup
* Load configuration and instructions for each strategy
* Provide access to strategy metadata and runner classes

| Method               | Input                         | Output                   |
| -------------------- | ----------------------------- | ------------------------ |
| `list_strategies()`  | optional `allowed: List[str]` | `List[str]`              |
| `get_strategy()`     | `name: str`                   | `DeployStrategyConfig`   |
| `get_runner_class()` | `name: str`                   | `type` (Runner subclass) |

***

### Runner (Abstract Base Class)

**Infrastructure-specific execution** handler.

```python theme={null}
class Runner(ABC):
    @abstractmethod
    def run(self, inputs: Union[Dict, str, bytes]) -> Any:
        """Execute with inputs and return result."""
    
    @abstractmethod
    def stop(self) -> None:
        """Stop and cleanup resources."""
    
    @abstractmethod
    def is_healthy(self) -> bool:
        """Check if runner is healthy and ready."""
```

| Runner            | Strategy  | Execution Method                   |
| ----------------- | --------- | ---------------------------------- |
| `LocalRunner`     | local     | Python `importlib` + function call |
| `DockerRunner`    | docker    | HTTP requests to container         |
| `ModalRunner`     | modal     | `modal.Function.remote()`          |
| `BentoMLRunner`   | bentoml   | HTTP to BentoCloud/local           |
| `LangGraphRunner` | langgraph | LangGraph Cloud API                |

***

### DeployedSoftware (`software.py`)

**Unified wrapper** that users interact with.

```python theme={null}
class DeployedSoftware(Software):
    def run(self, inputs) -> Dict[str, Any]:
        """Execute and return normalized response."""
        
    def stop(self) -> None:
        """Stop the software and cleanup."""
        
    def logs(self) -> str:
        """Get execution logs."""
        
    def is_healthy(self) -> bool:
        """Check if software is running."""
```

***

## Data Models

### DeployConfig

```python theme={null}
@dataclass
class DeployConfig:
    solution: SolutionResult  # The built solution
    env_vars: Dict[str, str]  # Environment variables
    timeout: int = 300        # Execution timeout (seconds)
    coding_agent: str = "claude_code"  # Agent for adaptation
```

### DeploymentSetting

```python theme={null}
@dataclass
class DeploymentSetting:
    strategy: str              # "local", "docker", "modal", etc.
    provider: Optional[str]    # Cloud provider name
    resources: Dict[str, Any]  # CPU, memory, GPU requirements
    interface: str             # "function", "http", etc.
    reasoning: str             # Why this was selected
```

### AdaptationResult

```python theme={null}
@dataclass
class AdaptationResult:
    success: bool
    adapted_path: str           # Path to adapted repo (copy)
    run_interface: Dict[str, Any]  # How to call .run()
    files_changed: List[str]
    error: Optional[str]
```

***

## Strategy Plugin Architecture

Each strategy is a self-contained directory:

```
strategies/{name}/
├── config.yaml              # Strategy configuration
├── selector_instruction.md  # When to use this strategy
├── adapter_instruction.md   # How to adapt code
├── runner.py                # Runtime execution class
└── __init__.py              # Exports
```

### config.yaml Structure

```yaml theme={null}
name: modal
provider: modal
interface: function

runner_class: ModalRunner

default_resources:
  gpu: T4
  memory: 16Gi

run_interface:
  type: modal
  function_name: predict
```

### How Strategies Are Discovered

1. On import, `StrategyRegistry` scans `strategies/` directory
2. Each subdirectory with `selector_instruction.md` AND `adapter_instruction.md` is registered
3. Runner classes are lazy-loaded from `runner.py` when needed

**Adding a new strategy is just adding a directory** - no code changes required in the core system.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Strategies Reference" icon="layer-group" href="/docs/deployment/strategies">
    Detailed guide to each deployment strategy
  </Card>

  <Card title="Adding New Strategies" icon="plus" href="/docs/deployment/adding-strategies">
    Step-by-step guide to add your own deployment targets
  </Card>
</CardGroup>
