Summary
Define the AgentAdapter protocol — the interface that any coding agent (Claude Code, Codex, Aider, built-in) must implement to be used as a CodeFrame execution engine.
Parent issue: #408
Motivation
CodeFrame currently has two tightly-coupled engines (ReactAgent and legacy Agent) that both implement their own execution patterns. To support frontier coding agents as execution engines, we need a clean abstraction that captures what CodeFrame needs from any agent without caring about implementation details.
Scope
New module: core/agent_adapter.py
AgentAdapter protocol (Python Protocol class):
from typing import Protocol, Iterator
class AgentAdapter(Protocol):
"""Interface for any coding agent that CodeFrame can orchestrate."""
def execute(
self,
task_prompt: str,
workspace_path: Path,
context: AgentContext,
timeout_ms: int = 3_600_000,
) -> AgentResult:
"""Execute a coding task and return the result."""
...
def stream_events(self) -> Iterator[AgentEvent]:
"""Yield progress events during execution (optional)."""
...
@property
def name(self) -> str:
"""Human-readable engine name."""
...
@property
def requires_api_key(self) -> dict[str, str]:
"""Map of required env vars to descriptions.
e.g. {"ANTHROPIC_API_KEY": "Anthropic API key for Claude"}
"""
...
AgentContext dataclass — what CodeFrame provides to every engine:
@dataclass
class AgentContext:
task_id: str
task_title: str
task_description: str
prd_content: str | None # Full PRD text
tech_stack: str | None # Natural language tech stack
project_preferences: str | None # AGENTS.md/CLAUDE.md content
relevant_files: list[str] # Paths to relevant files
file_contents: dict[str, str] # Pre-loaded file contents
blocker_history: list[str] # Previous blocker resolutions
dependency_context: str | None # What dependent tasks produced
verification_gates: list[str] # Gates to pass (ruff, pytest, etc.)
attempt: int # Retry attempt number (0 = first)
previous_errors: list[str] # Errors from previous attempts
AgentResult dataclass — what every engine returns:
@dataclass
class AgentResult:
status: AgentResultStatus # COMPLETED, FAILED, BLOCKED, TIMEOUT
files_modified: list[str]
files_created: list[str]
summary: str # Human-readable summary of changes
error: str | None # Error message if failed
blocker_question: str | None # Question if blocked
token_usage: TokenUsage | None
duration_ms: int
AgentEvent for streaming:
@dataclass
class AgentEvent:
type: str # "progress", "file_changed", "command_run", "error"
message: str
timestamp: datetime
metadata: dict # Engine-specific data
Design Decisions
- Protocol, not ABC: Use Python Protocol for structural subtyping. Adapters don't need to inherit from a base class — they just need to implement the interface.
- Context is rich: CodeFrame assembles all context; the adapter doesn't need to load files or read PRDs.
- Result is simple: CodeFrame just needs to know what changed and whether it worked.
- Streaming is optional: Not all engines support progress events (e.g., Aider).
Acceptance Criteria
Dependencies
- None — this is a foundational definition
Summary
Define the
AgentAdapterprotocol — the interface that any coding agent (Claude Code, Codex, Aider, built-in) must implement to be used as a CodeFrame execution engine.Parent issue: #408
Motivation
CodeFrame currently has two tightly-coupled engines (ReactAgent and legacy Agent) that both implement their own execution patterns. To support frontier coding agents as execution engines, we need a clean abstraction that captures what CodeFrame needs from any agent without caring about implementation details.
Scope
New module:
core/agent_adapter.pyAgentAdapterprotocol (Python Protocol class):AgentContextdataclass — what CodeFrame provides to every engine:AgentResultdataclass — what every engine returns:AgentEventfor streaming:Design Decisions
Acceptance Criteria
AgentAdapterProtocol defined withexecute(),stream_events(),name,requires_api_keyAgentContextcaptures all context CodeFrame currently assemblesAgentResultcaptures outcome, modified files, errors, blockersAgentEventsupports progress streamingReactAgentcan be wrapped to satisfy the protocol (design validation)Dependencies