# Modular Design Patterns and Size Constraints
## Modularity Philosophy
The Agent Orchestration Platform employs **strict modularity principles** with size constraints to ensure maintainability, testability, and comprehensibility across all components.
## Size Constraint Framework
### **Module Size Limits**
- **Target Size**: <250 lines per module (optimal for comprehension)
- **Maximum Size**: <400 lines per module (only if splitting creates awkward boundaries)
- **Function Size**: <50 lines per function (maximum complexity manageable)
- **Class Size**: <200 lines per class (single responsibility focus)
### **Complexity Constraints**
- **Cyclomatic Complexity**: ≤10 per function
- **Cognitive Complexity**: ≤15 per function
- **Nesting Depth**: ≤4 levels maximum
- **Parameter Count**: ≤5 parameters per function
## Modular Architecture Patterns
### **1. Single Responsibility Principle**
Each module has one clear, focused responsibility:
```python
# Good: Focused responsibility
# src/types/agent.py - Agent domain types only
@dataclass(frozen=True)
class AgentState:
"""Agent state with lifecycle management."""
# Agent-specific fields only
# src/types/session.py - Session domain types only
@dataclass(frozen=True)
class SessionState:
"""Session state with codebase association."""
# Session-specific fields only
# Bad: Mixed responsibilities
# src/types/everything.py - Too many concerns
class AgentSessionEverything:
"""Handles agents, sessions, security, networking..."""
# Too many responsibilities in one place
```
### **2. Composition Over Inheritance**
Use composition for complex functionality:
```python
# Good: Composition pattern
@dataclass(frozen=True)
class AgentManager:
"""Manages agent lifecycle through composition."""
iterm_manager: ITermManager
claude_manager: ClaudeCodeManager
state_manager: StateManager
security_validator: SecurityValidator
async def create_agent(self, request: AgentCreationRequest) -> AgentCreationResult:
"""Create agent using composed services."""
# Validate with security_validator
# Create iTerm tab with iterm_manager
# Spawn process with claude_manager
# Persist state with state_manager
# Bad: Deep inheritance hierarchy
class BaseManager:
pass
class AgentBaseManager(BaseManager):
pass
class ComplexAgentManager(AgentBaseManager):
"""Too much inherited complexity."""
pass
```
### **3. Interface Segregation**
Define focused interfaces for different concerns:
```python
# Good: Focused interfaces
class AgentLifecycleProtocol(Protocol):
"""Protocol for agent lifecycle operations."""
async def create_agent(self, request: AgentCreationRequest) -> AgentCreationResult:
...
async def terminate_agent(self, agent_id: AgentId) -> None:
...
class AgentHealthProtocol(Protocol):
"""Protocol for agent health monitoring."""
async def check_health(self, agent_id: AgentId) -> HealthStatus:
...
async def get_metrics(self, agent_id: AgentId) -> ResourceMetrics:
...
# Implementation uses both protocols
class AgentManager(AgentLifecycleProtocol, AgentHealthProtocol):
"""Implements both focused protocols."""
pass
```
### **4. Dependency Injection Pattern**
Enable testability and modularity through dependency injection:
```python
# Good: Dependency injection
class SessionManager:
"""Session management with injected dependencies."""
def __init__(
self,
state_storage: StateStorageProtocol,
security_validator: SecurityValidatorProtocol,
git_analyzer: GitAnalyzerProtocol
):
self.state_storage = state_storage
self.security_validator = security_validator
self.git_analyzer = git_analyzer
async def create_session(self, request: SessionCreationRequest) -> SessionCreationResult:
"""Create session using injected dependencies."""
# Easy to test with mocked dependencies
# Easy to swap implementations
# Clear dependencies visible in constructor
# Bad: Hard-coded dependencies
class SessionManager:
"""Session management with hard-coded dependencies."""
def __init__(self):
self.state_storage = SqliteStateStorage() # Hard-coded
self.security_validator = JWTSecurityValidator() # Hard-coded
self.git_analyzer = SystemGitAnalyzer() # Hard-coded
# Difficult to test, inflexible
```
## Module Organization Strategies
### **By Domain (Preferred)**
Organize modules around business domain concepts:
```
src/
├── types/
│ ├── agent.py # Agent domain types (180 lines)
│ ├── session.py # Session domain types (165 lines)
│ ├── security.py # Security domain types (145 lines)
│ └── communication.py # Communication types (120 lines)
├── contracts/
│ ├── agent.py # Agent contracts (200 lines)
│ ├── session.py # Session contracts (180 lines)
│ └── security.py # Security contracts (240 lines)
├── core/
│ ├── agent_manager.py # Agent management (280 lines)
│ ├── session_manager.py # Session management (240 lines)
│ └── coordinator.py # Manager coordination (160 lines)
```
### **Size Management Techniques**
#### **1. Extract Constants and Configuration**
```python
# Before: Mixed concerns in single file (350 lines)
class AgentManager:
def create_agent(self):
max_memory = 512 # Magic number
timeout = 300 # Magic number
# ... 340 more lines
# After: Separated concerns
# src/core/agent_manager.py (220 lines)
from src.core.agent_config import AgentConfiguration
class AgentManager:
def __init__(self, config: AgentConfiguration):
self.config = config
# src/core/agent_config.py (80 lines)
@dataclass(frozen=True)
class AgentConfiguration:
max_memory_mb: int = 512
timeout_seconds: int = 300
# ... other configuration
```
#### **2. Extract Validation Logic**
```python
# Before: Validation mixed with business logic (380 lines)
class AgentCreationService:
async def create_agent(self, request):
# 80 lines of validation logic
if not request.agent_name:
raise ValueError("Name required")
if not re.match(r'^Agent_\d+$', request.agent_name):
raise ValueError("Invalid format")
# ... more validation
# 280 lines of business logic
# ... creation logic
# After: Separated validation (250 + 90 lines)
# src/services/agent_creation.py (250 lines)
from src.validators.agent_validation import AgentRequestValidator
class AgentCreationService:
def __init__(self, validator: AgentRequestValidator):
self.validator = validator
async def create_agent(self, request):
self.validator.validate(request)
# 240 lines of pure business logic
# src/validators/agent_validation.py (90 lines)
class AgentRequestValidator:
def validate(self, request: AgentCreationRequest):
# 80 lines of focused validation logic
```
#### **3. Extract Utility Functions**
```python
# Before: Utilities mixed with core logic (420 lines)
class MessageHandler:
async def send_message(self, agent_id, message):
# 60 lines of message sanitization
sanitized = self._sanitize(message)
# 40 lines of ADDER+ prompt construction
prompt = self._build_adder_prompt(agent_id, sanitized)
# 300 lines of core message handling logic
# After: Separated utilities (240 + 80 + 60 lines)
# src/core/message_handler.py (240 lines)
from src.utils.message_sanitizer import sanitize_message
from src.utils.prompt_builder import build_adder_prompt
class MessageHandler:
async def send_message(self, agent_id, message):
sanitized = sanitize_message(message)
prompt = build_adder_prompt(agent_id, sanitized)
# 220 lines of core logic
# src/utils/message_sanitizer.py (80 lines)
def sanitize_message(message: str) -> str:
# 70 lines of focused sanitization
# src/utils/prompt_builder.py (60 lines)
def build_adder_prompt(agent_id: AgentId, message: str) -> str:
# 50 lines of prompt construction
```
## Testing Modularity
### **Test Organization by Module**
```
tests/
├── types/
│ ├── test_agent.py # Agent type testing (150 lines)
│ ├── test_session.py # Session type testing (130 lines)
│ └── test_security.py # Security type testing (140 lines)
├── core/
│ ├── test_agent_manager.py # Agent manager testing (200 lines)
│ └── test_session_manager.py # Session manager testing (180 lines)
├── utils/
│ ├── test_sanitizer.py # Sanitization testing (90 lines)
│ └── test_prompt_builder.py # Prompt building testing (70 lines)
```
### **Focused Test Cases**
```python
# Good: Focused test class
class TestAgentCreation:
"""Test agent creation functionality only."""
def test_valid_agent_creation(self):
"""Test successful agent creation."""
# Single responsibility test
def test_invalid_name_rejection(self):
"""Test rejection of invalid agent names."""
# Single failure mode test
# Bad: Monolithic test class
class TestEverything:
"""Test all agent, session, and security functionality."""
def test_everything_at_once(self):
"""Test creation, deletion, messaging, security..."""
# Too many concerns in one test
```
## Documentation Modularity
### **Module-Level Documentation**
Each module includes focused documentation:
```python
# src/core/agent_manager.py
"""
Agent Lifecycle Management
This module provides agent lifecycle management with iTerm2 integration
and Claude Code process orchestration. Handles creation, monitoring,
and termination of individual agent instances.
Key Components:
- AgentManager: Primary agent lifecycle coordination
- AgentHealthMonitor: Continuous health checking
- AgentRecovery: Automatic restart and recovery
Integration Points:
- ITermManager: iTerm2 tab management
- ClaudeCodeManager: Process spawning and communication
- StateManager: Persistent state storage
Security Considerations:
- Process isolation enforcement
- Resource limit monitoring
- Secure state persistence
"""
```
### **Function-Level Documentation**
```python
def create_agent(
self,
session_id: SessionId,
agent_name: str,
specialization: Optional[str] = None
) -> AgentCreationResult:
"""
Create new Claude Code agent with comprehensive validation.
This function orchestrates the complete agent creation workflow:
1. Validates request parameters and session capacity
2. Creates isolated iTerm2 tab in session context
3. Spawns Claude Code process with security constraints
4. Injects ADDER+ system prompt with agent identification
5. Initializes health monitoring and state persistence
Args:
session_id: Target session for agent placement
agent_name: Unique agent identifier (Agent_# format)
specialization: Optional role specialization
Returns:
AgentCreationResult with agent details and status
Raises:
ValidationError: Invalid parameters or session state
ResourceError: Insufficient capacity or resources
SecurityError: Security policy violations
Example:
>>> result = await agent_manager.create_agent(
... session_id="session_123",
... agent_name="Agent_1",
... specialization="backend"
... )
>>> assert result.success
>>> assert result.agent_id is not None
"""
```
## Performance Considerations
### **Module Loading Optimization**
```python
# Good: Lazy imports for large dependencies
def get_heavy_processor():
"""Lazy load heavy processing dependencies."""
import expensive_library # Only imported when needed
return expensive_library.HeavyProcessor()
# Good: Conditional imports
if TYPE_CHECKING:
from src.heavy.module import HeavyClass
else:
HeavyClass = None
# Bad: Eager loading of everything
import expensive_library
import another_heavy_library
import yet_another_library
# All loaded at module import time
```
### **Memory Efficiency**
```python
# Good: Efficient data structures
@dataclass(frozen=True, slots=True)
class AgentState:
"""Memory-efficient agent state with slots."""
agent_id: AgentId
session_id: SessionId
# ... other fields
# Good: Generator for large collections
def get_all_agents() -> Iterator[AgentState]:
"""Memory-efficient agent iteration."""
for agent_id in agent_ids:
yield load_agent_state(agent_id)
# Bad: Loading everything into memory
def get_all_agents() -> List[AgentState]:
"""Memory-intensive agent loading."""
return [load_agent_state(id) for id in all_agent_ids]
```
## Error Handling Modularity
### **Module-Specific Exceptions**
```python
# src/core/exceptions.py
class AgentManagerError(OrchestrationError):
"""Base exception for agent manager operations."""
pass
class AgentCreationError(AgentManagerError):
"""Specific error during agent creation."""
pass
class AgentNotFoundError(AgentManagerError):
"""Agent not found in system."""
pass
# src/core/agent_manager.py
class AgentManager:
async def create_agent(self, request):
try:
# Creation logic
except ValidationError as e:
raise AgentCreationError(f"Invalid request: {e}") from e
except ResourceError as e:
raise AgentCreationError(f"Insufficient resources: {e}") from e
```
## Refactoring Guidelines
### **When to Split Modules**
Split when any of these conditions are met:
1. **Size Threshold**: Module exceeds 300 lines
2. **Multiple Responsibilities**: Module handles more than one primary concern
3. **Testing Difficulty**: Module is difficult to test comprehensively
4. **Reuse Opportunities**: Parts of module could be reused elsewhere
5. **Team Boundaries**: Different teams need to work on different parts
### **How to Split Modules**
1. **Identify Boundaries**: Find natural separation points by responsibility
2. **Extract Interfaces**: Define protocols for communication between modules
3. **Move Related Code**: Group related functions, classes, and data together
4. **Update Dependencies**: Adjust imports and dependency injection
5. **Verify Tests**: Ensure all tests still pass after refactoring
6. **Update Documentation**: Revise module and function documentation
This modular design ensures the Agent Orchestration Platform remains maintainable, testable, and comprehensible as it grows in complexity while maintaining strict size constraints and clear responsibility boundaries.