Step A2.beta
14 KiB
Plan Model Reference
Source:
src/cleveragents/domain/models/core/plan.py
Overview
The Plan model is the fundamental unit of orchestration in CleverAgents v3. Plans follow a three-phase lifecycle and are instantiated from Action templates via agents plan use.
NamespacedName
All plans, actions, and projects use a NamespacedName for scoped identification:
[server:][namespace/]<name>
| Field | Type | Default | Description |
|---|---|---|---|
server |
str | None |
None |
Optional server qualifier (e.g., prod, dev) |
namespace |
str |
"local" |
Namespace scope (e.g., local, username, orgname) |
name |
str |
(required) | The item name (1-255 chars) |
Parsing Rules
"my-action"->namespace="local",name="my-action""local/my-action"->namespace="local",name="my-action""myorg/my-action"->namespace="myorg",name="my-action""prod:myorg/my-action"->server="prod",namespace="myorg",name="my-action"
Validation
- Namespace: lowercase alphanumeric with hyphens only. Empty defaults to
"local". - Name: alphanumeric with hyphens or underscores only. Stored lowercase.
PlanIdentity
Every plan has a unique identity with optional hierarchy links:
| Field | Type | Default | Description |
|---|---|---|---|
plan_id |
str |
(required) | Unique ULID (26-char Crockford base32) |
parent_plan_id |
str | None |
None |
Parent plan ULID (set for subplans) |
root_plan_id |
str | None |
None |
Root plan ULID (top-most in tree) |
attempt |
int |
1 |
Attempt counter (increments on re-run, >= 1) |
Lifecycle Phases
Plans progress through four phases in strict order:
| Phase | Description | Valid Next |
|---|---|---|
| STRATEGIZE | LLM generates a strategy / decision tree | EXECUTE |
| EXECUTE | Tool-based execution in sandboxed environment | APPLY |
| APPLY | Changes are merged to the target project(s) | APPLIED |
| APPLIED | Terminal — plan is complete | (none) |
There is no "Action" phase in the plan lifecycle. Actions are a separate domain model representing reusable plan templates.
Phase Transitions
get_next_phase()returns the next phase in order, orNoneif terminal (APPLIED).can_transition_to_next_phaseisTrueonly whenprocessing_state == COMPLETEand phase is not APPLIED.- Only forward transitions are allowed. Attempting to skip phases (e.g., STRATEGIZE -> APPLY) raises an error.
Processing States
Within each phase, a plan has a processing state:
| State | Meaning |
|---|---|
QUEUED |
Waiting for compute / worker (default) |
PROCESSING |
Currently running |
ERRORED |
Failed; includes error metadata |
COMPLETE |
Finished successfully |
CANCELLED |
User/system cancelled (terminal for any phase) |
processing_statealways has a value (defaults toQUEUED).- When
phaseisAPPLIED, theprocessing_stateis automatically corrected toCOMPLETEby thevalidate_phase_state_consistencymodel validator.
Phase/State Consistency Rules
The validate_phase_state_consistency model validator enforces:
- APPLIED phase requires COMPLETE state — if a plan is constructed with
phase=APPLIEDand any other state, it is auto-corrected toCOMPLETE. - CANCELLED is terminal — a plan with
processing_state=CANCELLEDin any phase is considered terminal.
Computed Properties
| Property | Type | Description |
|---|---|---|
state |
ProcessingState |
Alias for processing_state |
is_terminal |
bool |
True if phase is APPLIED or state is CANCELLED |
is_errored |
bool |
True if processing_state == ERRORED |
can_transition_to_next_phase |
bool |
True if state is COMPLETE and phase is not APPLIED |
is_subplan |
bool |
True if parent_plan_id is set |
is_root_plan |
bool |
True if no root_plan_id or root == self |
depth |
int |
0 for root, -1 (placeholder) for non-root |
has_subplans |
bool |
True if subplan_statuses is non-empty |
Action Linkage
Every plan carries an action_name field (required, string) that references the namespaced name of the source Action template. This replaces the old action_id pattern.
action_name: "local/code-coverage"
Project Links
Plans reference projects through project_links: list[ProjectLink] instead of a flat project_ids list. Each link carries:
| Field | Type | Default | Description |
|---|---|---|---|
project_name |
str |
(required) | Namespaced project name |
alias |
str | None |
None |
Optional alias for disambiguation |
read_only |
bool |
False |
Whether the project is read-only in this plan |
Alias Validation
Aliases must match the pattern ^[a-z][a-z0-9_-]{0,63}$:
- Lowercase, starts with a letter
- Alphanumeric, hyphens, underscores only
- Maximum 64 characters
Aliases must be unique within a plan. The validate_project_link_alias_uniqueness model validator raises ValueError on duplicates.
Automation Profile
Plans can carry a resolved automation profile with provenance tracking:
automation_profile: AutomationProfileRef | None
The AutomationProfileRef contains:
| Field | Type | Description |
|---|---|---|
profile_name |
str |
The namespaced profile name (e.g., "trusted") |
provenance |
AutomationProfileProvenance |
Where the profile was resolved from |
AutomationProfileProvenance values: plan, action, project, global.
Resolution follows plan > action > project > global precedence. Once set at plan use time, the profile is locked to the plan.
Automation Level
| Level | Description |
|---|---|
MANUAL |
User must explicitly trigger each phase transition (default) |
REVIEW_BEFORE_APPLY |
Auto strategize + execute, pause before apply |
FULL_AUTOMATION |
All phases run automatically without human input |
Invariants
Plans carry invariant constraints with source provenance:
invariants: list[PlanInvariant]
Each PlanInvariant has:
| Field | Type | Description |
|---|---|---|
text |
str |
The constraint text (natural language, min 1 char) |
source |
InvariantSource |
Where it originated |
InvariantSource values: plan, action, project, global.
Precedence is plan > action > project > global.
Arguments
Plans store resolved argument values and their display order:
| Field | Type | Default | Description |
|---|---|---|---|
arguments |
dict[str, Any] |
{} |
Resolved values (name -> value) |
arguments_order |
list[str] |
[] |
Stable ordering for CLI rendering |
Actor Fields
Plans reference actors for each phase:
| Field | Type | Default | Description |
|---|---|---|---|
strategy_actor |
str | None |
None |
Actor for Strategize phase |
execution_actor |
str | None |
None |
Actor for Execute phase |
review_actor |
str | None |
None |
Optional actor for code review/QA |
apply_actor |
str | None |
None |
Optional actor for release/merge |
estimation_actor |
str | None |
None |
Optional actor for cost/risk estimation |
invariant_actor |
str | None |
None |
Optional actor for invariant reconciliation |
PlanTimestamps
Lifecycle timestamps are tracked in a dedicated PlanTimestamps model:
| Field | Type | Default | Description |
|---|---|---|---|
created_at |
datetime |
now() |
When the plan was created |
updated_at |
datetime |
now() |
Last modification time |
strategize_started_at |
datetime | None |
None |
When strategize phase began |
strategize_completed_at |
datetime | None |
None |
When strategize phase completed |
execute_started_at |
datetime | None |
None |
When execute phase began |
execute_completed_at |
datetime | None |
None |
When execute phase completed |
apply_started_at |
datetime | None |
None |
When apply phase began |
applied_at |
datetime | None |
None |
When the plan reached terminal APPLIED state |
Description and Definition of Done
| Field | Type | Default | Description |
|---|---|---|---|
description |
str |
(required) | Rendered prompt/description defining what the plan does (min 1 char) |
definition_of_done |
str | None |
None |
Rendered, testable completion criteria |
Both are rendered from the action template at plan creation time and stored as plain strings.
Error Tracking
| Field | Type | Default | Description |
|---|---|---|---|
error_message |
str | None |
None |
Error message if errored |
error_details |
dict[str, str] | None |
None |
Additional error context (key-value pairs) |
Execution Placeholders
These fields are populated during the plan lifecycle:
| Field | Type | Default | Description |
|---|---|---|---|
changeset_id |
str | None |
None |
ChangeSet ID from Execute phase |
sandbox_refs |
list[str] |
[] |
Active sandbox reference IDs |
validation_summary |
dict[str, Any] | None |
None |
Validation results before Apply |
decision_root_id |
str | None |
None |
Root decision node ULID |
Metadata
| Field | Type | Default | Description |
|---|---|---|---|
created_by |
str | None |
None |
User/session that created the plan |
tags |
list[str] |
[] |
Tags for organization and filtering |
reusable |
bool |
True |
Whether the source action remains available after use |
read_only |
bool |
False |
Whether plan only performs read operations |
CLI Output
Plan.as_cli_dict() returns a stable dictionary for CLI rendering in table, JSON, and YAML formats. Fields are ordered consistently:
plan_id,name,action,phase,state,descriptiondefinition_of_done(if set)automation_profile,automation_profile_source(if set)automation_levelprojects(if any, with alias/read_only)invariants(if any, with source tags)arguments(if any, in stable order)strategy_actor,execution_actor(if set)error(if present)created_at,updated_atparent_plan_id(if subplan)subplan_count(if has subplans)
Subplan Hierarchy
Plans support a parent/child hierarchy for decomposition:
identity.parent_plan_id— Links to parent planidentity.root_plan_id— Links to root of the treesubplan_config— Configuration for child executionsubplan_statuses— Status tracking for each child
ExecutionMode
Controls how subplans are scheduled:
| Mode | Description |
|---|---|
SEQUENTIAL |
One after another, ordered by sequence (default) |
PARALLEL |
All at once, up to max_parallel |
SubplanMergeStrategy
How to merge results from parallel subplans:
| Strategy | Description |
|---|---|
GIT_THREE_WAY |
Use git merge-file for code (default) |
SEQUENTIAL_APPLY |
Apply in completion order |
FAIL_ON_CONFLICT |
Error if any conflicts |
LAST_WINS |
Later changes overwrite earlier |
SubplanConfig
Configuration for subplan execution, set on parent plans:
| Field | Type | Default | Description |
|---|---|---|---|
execution_mode |
ExecutionMode |
SEQUENTIAL |
How to execute subplans |
merge_strategy |
SubplanMergeStrategy |
GIT_THREE_WAY |
How to merge subplan results |
max_parallel |
int |
5 |
Max concurrent subplans in PARALLEL mode (1-50) |
fail_fast |
bool |
False |
Stop all subplans on first failure |
timeout_per_subplan_seconds |
int | None |
None |
Timeout per subplan in seconds |
retry_failed |
bool |
True |
Automatically retry failed subplans |
max_retries |
int |
2 |
Max retry attempts per subplan (0-5) |
SubplanStatus
Stored on the parent plan to track each child:
| Field | Type | Default | Description |
|---|---|---|---|
subplan_id |
str |
(required) | The subplan's ULID |
action_name |
str |
(required) | Namespaced action name used to create the subplan |
target_resources |
list[str] |
[] |
Resource IDs this subplan operates on |
status |
ProcessingState |
QUEUED |
Current processing state of the subplan |
started_at |
datetime | None |
None |
When execution started |
completed_at |
datetime | None |
None |
When execution completed |
error |
str | None |
None |
Error message if subplan failed |
changeset_summary |
str | None |
None |
Brief summary of changes produced |
files_changed |
int |
0 |
Number of files modified (>= 0) |
attempt_number |
int |
1 |
Current attempt number (>= 1) |
previous_attempts |
list[SubplanAttempt] |
[] |
History of prior execution attempts |
SubplanAttempt
Record of a subplan execution attempt for post-mortem analysis:
| Field | Type | Default | Description |
|---|---|---|---|
attempt_number |
int |
(required) | 1-based attempt counter |
started_at |
datetime |
(required) | When this attempt started |
completed_at |
datetime | None |
None |
When this attempt ended |
error |
str | None |
None |
Error message if attempt failed |
was_retried |
bool |
False |
Whether a subsequent attempt was made |
Computed Properties
| Property | Description |
|---|---|
is_subplan |
True if parent_plan_id is set |
is_root_plan |
True if no root or root == self |
depth |
0 for root, -1 (placeholder) for non-root |
has_subplans |
True if subplan_statuses is non-empty |
Failure Handling
SubplanFailureHandler makes stateless decisions about:
- should_stop_others: Halt remaining subplans? (Yes if
fail_fastor sequential mode) - should_retry: Retry the failed subplan? (Yes for retriable errors within retry limits)
Retriable errors: ValidationError, TimeoutError, TemporaryResourceError, MergeConflictError
Non-retriable errors: ConfigurationError, AuthenticationError, MissingResourceError, CircularDependencyError
Unknown errors are not retried (conservative default).