# Plan Domain Model The `Plan` is the fundamental unit of orchestration in CleverAgents. It is instantiated from an **Action** via `agents plan use` and follows a three-phase lifecycle. ## Phase Lifecycle Plans progress through four phases in strict order: ``` Strategize -> Execute -> Apply -> Applied (terminal) ``` | Phase | Description | |-------------|-----------------------------------------------------| | STRATEGIZE | Generating the execution strategy | | EXECUTE | Carrying out the planned changes | | APPLY | Applying the changeset to the target project(s) | | APPLIED | Terminal state; plan is complete | The **Action** entity is a separate domain object. There is no ACTION phase within the Plan lifecycle. Actions are resolved before plan creation. ### Phase Transitions Valid transitions: - `strategize` -> `execute` - `execute` -> `apply` - `apply` -> `applied` No backward transitions or phase-skipping is allowed. `APPLIED` is terminal. Transitions are validated by `can_transition(from_phase, to_phase)` and require the plan's processing state to be `COMPLETE` before advancing. ## Processing State Plans use a single unified `state` field (type: `ProcessingState`): | State | Description | |------------|----------------------------------------------| | QUEUED | Waiting for compute/worker | | PROCESSING | Currently running | | ERRORED | Failed; includes error metadata | | COMPLETE | Finished successfully | | CANCELLED | User/system cancelled | The `state` field replaces the former dual `action_state` / `processing_state` fields. All phases use the same `ProcessingState` enum. ## Action Linkage Plans reference their originating action by **namespaced name** (not ULID): - `action_name: str` -- required, e.g. `"local/code-review"`, `"org/deploy"` This decouples the plan from the action's database identity and enables cross-server action references. ## Project Links Plans target one or more projects via `project_links: list[ProjectLink]`: ```python class ProjectLink(BaseModel): project_name: str # Namespaced project name (required) alias: str | None # Optional short alias for plan context read_only: bool = False # Whether project is read-only for this plan ``` ### Alias Validation - Lowercase alphanumeric with hyphens or underscores - Must start with a letter or digit - Aliases are auto-lowercased - Duplicate aliases within a plan are rejected A computed property `plan.project_names` returns `[link.project_name for link in plan.project_links]` for backward compatibility. ## Automation Profile Plans store automation configuration: | Field | Type | Description | |------------------------------|-------------------|------------------------------------------| | `automation_level` | `AutomationLevel` | MANUAL, REVIEW_BEFORE_APPLY, or FULL_AUTOMATION | | `automation_profile_name` | `str \| None` | Namespaced name of the resolved profile | | `effective_profile_snapshot` | `dict \| None` | Frozen profile thresholds at creation | The profile snapshot is immutable after plan creation, ensuring reproducibility. ### Automation Levels | Level | Behavior | |----------------------|-------------------------------------------------------| | MANUAL | User triggers each phase transition | | REVIEW_BEFORE_APPLY | Auto strategize + execute, pause before apply | | FULL_AUTOMATION | All phases run automatically | ## Invariants Plans carry a list of `PlanInvariant` constraints: ```python class PlanInvariant(BaseModel): text: str # The invariant constraint text (non-empty) scope: InvariantScope # Where it originated source_name: str | None # Name of the source entity ``` ### Invariant Scope Precedence Scopes (highest to lowest precedence): 1. `PLAN` -- plan-level constraints 2. `ACTION` -- action-level constraints 3. `PROJECT` -- project-level constraints 4. `GLOBAL` -- system-wide constraints Invariants preserve insertion order for stable CLI rendering. ## Arguments Plans store resolved action arguments: - `arguments: dict[str, Any]` -- resolved argument values (JSON-serializable) - `arguments_order: list[str]` -- ordered list of argument names for CLI rendering ## Actor References | Field | Description | |--------------------|--------------------------------------| | `strategy_actor` | Actor for Strategize phase | | `execution_actor` | Actor for Execute phase | | `estimation_actor` | Actor for cost/risk estimation | | `invariant_actor` | Actor for invariant reconciliation | ## Execution Placeholders | Field | Description | |----------------------|------------------------------------------------| | `changeset_id` | ID of the change set produced during Execute | | `sandbox_refs` | References to sandbox instances | | `validation_summary` | Summary of validation results at Apply time | | `decision_root_id` | ULID of the root decision in the decision tree | ## CLI Rendering `Plan.as_cli_dict()` returns a stable-ordered `OrderedDict` suitable for CLI output. Key ordering: 1. `plan_id`, `name`, `action_name` 2. `phase`, `state`, `description` 3. `definition_of_done` (if set) 4. `projects`, `automation_profile` (if set), `automation_level` 5. Actor references (if set) 6. `arguments` (if non-empty), `invariants` (if non-empty) 7. Execution fields (if set) 8. Error fields (if set) 9. `tags` (if non-empty) 10. Timestamps 11. Hierarchy fields (if set) ## Source Location - Model: `src/cleveragents/domain/models/core/plan.py` - Action model: `src/cleveragents/domain/models/core/action.py` - Lifecycle service: `src/cleveragents/application/services/plan_lifecycle_service.py`