6.2 KiB
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->executeexecute->applyapply->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]:
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:
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):
PLAN-- plan-level constraintsACTION-- action-level constraintsPROJECT-- project-level constraintsGLOBAL-- 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:
plan_id,name,action_namephase,state,descriptiondefinition_of_done(if set)projects,automation_profile(if set),automation_level- Actor references (if set)
arguments(if non-empty),invariants(if non-empty)- Execution fields (if set)
- Error fields (if set)
tags(if non-empty)- Timestamps
- 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