# Plan Execute: Strategize & Execute Integration ## Overview The plan executor connects the `PlanLifecycleService` to stub actors that drive plans through the **Strategize** and **Execute** phases. In M1, these actors are local-only stubs (no LLM calls); future milestones will integrate real AI providers. When a `PlanExecutionContext` is provided, the execute phase delegates to `RuntimeExecuteActor` for full tool-calling runtime integration with changeset capture through `ChangeSetStore`. ## Architecture ``` PlanExecutor ├── StrategizeStubActor (read-only, produces decision tree) ├── ExecuteStubActor (legacy stub: sandbox + ChangeSetCapture) ├── RuntimeExecuteActor (runtime: ToolRunner + ChangeSetStore) ├── PlanExecutionContext (plan metadata + resource bindings) └── PlanLifecycleService (phase transitions, persistence) ``` ## Execution Modes | Mode | Actor | Trigger | Output | |---------|---------------------|-----------------------------------|------------------------| | Stub | ExecuteStubActor | No `execution_context` | `ExecuteResult` | | Runtime | RuntimeExecuteActor | `execution_context` is provided | `RuntimeExecuteResult` | ## PlanExecutionContext The `PlanExecutionContext` bridges plan metadata into the tool runtime: ```python from cleveragents.application.services.plan_execution_context import ( PlanExecutionContext, ) from cleveragents.domain.models.core.change import InMemoryChangeSetStore ctx = PlanExecutionContext( plan_id="01HGZ...", decision_root_id="01HGZ...", sandbox_root="/tmp/sandbox", automation_profile="trusted", project_resources={"repo": {"path": "/code"}}, changeset_store=InMemoryChangeSetStore(), ) # Start a changeset for tracking mutations changeset_id = ctx.start_changeset() # Record changes during execution ctx.record_change(entry) # Retrieve changeset cs = ctx.get_changeset(changeset_id) # Summarize context state summary = ctx.summarize() ``` ### Fields | Field | Type | Required | Description | |---------------------|---------------------------|----------|------------------------------------| | `plan_id` | `str` | Yes | ULID of the plan | | `decision_root_id` | `str \| None` | No | Root decision from strategize | | `sandbox_root` | `str \| None` | No | Sandbox filesystem path | | `automation_profile` | `str \| None` | No | Automation profile name | | `project_resources` | `dict[str, Any]` | No | Project resource metadata | | `resource_bindings` | `dict[str, BoundResource]`| No | Resolved resource bindings | | `changeset_store` | `ChangeSetStore` | No | Defaults to InMemoryChangeSetStore | ## RuntimeExecuteActor Wraps `ToolRunner` to execute strategy decisions with changeset capture: ```python from cleveragents.application.services.plan_execution_context import ( RuntimeExecuteActor, RuntimeExecuteResult, ) actor = RuntimeExecuteActor( tool_runner=runner, execution_context=ctx, ) result: RuntimeExecuteResult = actor.execute(decisions) ``` ### RuntimeExecuteResult Fields | Field | Type | Description | |--------------------------|---------------|----------------------------------| | `changeset_id` | `str` | ULID of the produced changeset | | `tool_call_count` | `int` | Number of tool calls made | | `sandbox_refs` | `list[str]` | Sandbox reference paths | | `decision_ids_processed` | `list[str]` | Processed decision node IDs | | `execution_duration_ms` | `float` | Wall-clock execution time (ms) | ## PlanExecutor Runtime Mode The `PlanExecutor` auto-selects runtime vs stub mode: ```python from cleveragents.application.services.plan_executor import PlanExecutor # Stub mode (no execution_context) executor = PlanExecutor(lifecycle_service=lifecycle, tool_runner=runner) assert not executor.has_runtime # Runtime mode (with execution_context) executor = PlanExecutor( lifecycle_service=lifecycle, tool_runner=runner, execution_context=ctx, ) assert executor.has_runtime assert executor.changeset_store is not None # Execute auto-dispatches to RuntimeExecuteActor result = executor.run_execute(plan_id) ``` ### Properties | Property | Type | Description | |---------------------|-----------------------------|--------------------------------------| | `has_runtime` | `bool` | True if execution_context is set | | `changeset_store` | `ChangeSetStore \| None` | Store from execution context | | `execution_context` | `PlanExecutionContext \| None` | The execution context | ## ChangeSetStore Wiring The `ChangeSetStore` protocol defines the interface for changeset persistence: ```python class ChangeSetStore(Protocol): def start(self, plan_id: str) -> str: ... def record(self, changeset_id: str, entry: ChangeEntry) -> None: ... def get(self, changeset_id: str) -> SpecChangeSet | None: ... def get_for_plan(self, plan_id: str) -> list[SpecChangeSet]: ... def summarize(self, changeset_id: str) -> dict[str, Any]: ... ``` `InMemoryChangeSetStore` is the default for M1. Database-backed implementations will be added in D1 milestone. ## Phase Lifecycle | Phase | Actor | Mode | Output | |------------|------------------------|-----------|----------------------------------| | Strategize | StrategizeStubActor | Read-only | Decision tree, invariant records | | Execute | RuntimeExecuteActor | Runtime | ChangeSet via ChangeSetStore | | Execute | ExecuteStubActor | Stub | ChangeSet via ChangeSetCapture | ## Error Handling Failures in either phase are captured with full error context: - `error_message`: The exception message string - `error_details`: Dict with `exception_type`, `traceback`, and `mode` - The plan transitions to `ERRORED` processing state ## Streaming Hooks Both phases accept an optional `stream_callback`: ### Event Types | Event | Phase | Actor | Description | |----------------------------|----------|---------|---------------------------------| | `strategize_started` | Strat. | Stub | Phase processing began | | `strategize_decisions` | Strat. | Stub | Decisions produced | | `strategize_complete` | Strat. | Stub | Phase completed | | `execute_started` | Execute | Stub | Stub execute began | | `execute_step` | Execute | Stub | Stub decision step | | `execute_complete` | Execute | Stub | Stub execute completed | | `runtime_execute_started` | Execute | Runtime | Runtime execute began | | `runtime_execute_step` | Execute | Runtime | Runtime decision step | | `runtime_execute_complete` | Execute | Runtime | Runtime execute completed | ## Module Reference - **`cleveragents.application.services.plan_execution_context`** - `PlanExecutionContext`: Execution context bridging plan to runtime - `RuntimeExecuteActor`: Tool-calling execute actor - `RuntimeExecuteResult`: Runtime execution output model - **`cleveragents.application.services.plan_executor`** - `PlanExecutor`: Orchestrator with runtime/stub mode selection - `StrategizeStubActor`: Local-only strategize actor - `ExecuteStubActor`: Local-only execute actor - `StrategyDecision`, `StrategizeResult`, `ExecuteResult`: Data models