Files
cleveragents-core/docs/reference/plan_model.md
T
freemo a64687f2a2
CI / lint (push) Successful in 14s
CI / typecheck (push) Successful in 28s
CI / security (push) Successful in 21s
CI / quality (push) Successful in 15s
CI / integration_tests (push) Successful in 4m25s
CI / build (push) Successful in 15s
CI / unit_tests (push) Successful in 9m8s
CI / docker (push) Successful in 8s
CI / coverage (push) Successful in 6m51s
Docs: Updated specification to clear up a few inconsistencies
2026-02-14 10:59:06 -05:00

16 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 four-phase lifecycle (Action, Strategize, Execute, Apply) 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:

Phase Description Valid Next
ACTION Template stage — defines the work to be done. No significant processing occurs. When used (via agents plan use), spawns a new plan entity in Strategize. The original action remains available by default; single-use actions are deleted after first use. STRATEGIZE
STRATEGIZE LLM generates a strategy / decision tree EXECUTE
EXECUTE Tool-based execution in sandboxed environment. May create additional decisions constrained by Strategize-phase decisions. APPLY, or revert to STRATEGIZE
APPLY Final phase. Merges changes to the target project(s). Terminal states: applied (success), constrained (cannot complete within strategy constraints — may revert to STRATEGIZE), errored, cancelled. (terminal — see Apply Terminal States)

Action is formally a phase in the lifecycle but is unique in that it functions primarily as a reusable template from which plans are instantiated. Actions are also managed as a separate domain model (Action) since they can exist independently of any plan.

Phase Transitions

  • get_next_phase() returns the next phase in order, or None if the plan is in the Apply phase (which is terminal).
  • can_transition_to_next_phase is True only when processing_state == COMPLETE and phase is not APPLY.
  • The normal progression is forward. However, Execute may revert to Strategize when execution discovers that Strategize-phase constraints are too restrictive to proceed. Apply may also revert to Strategize when it enters the constrained state (controlled by the auto_reversion_from_apply automation profile flag). Attempting to skip phases (e.g., STRATEGIZE -> APPLY) raises an error.

Processing States

Within each phase, a plan has a processing state:

State Meaning Applicable Phases
QUEUED Waiting for compute / worker (default) Strategize, Execute, Apply
PROCESSING Currently running Strategize, Execute, Apply
ERRORED Failed; includes error metadata Strategize, Execute, Apply
COMPLETE Finished successfully Strategize, Execute
APPLIED Terminal — changes successfully committed Apply only
CONSTRAINED Terminal — cannot complete within strategy constraints; may trigger reversion to Strategize Apply only
CANCELLED User/system cancelled (terminal for any phase) All phases
  • processing_state always has a value (defaults to QUEUED).
  • The Apply phase uses APPLIED and CONSTRAINED as terminal states instead of COMPLETE.

Phase/State Consistency Rules

The validate_phase_state_consistency model validator enforces:

  1. Apply terminal states — the Apply phase uses APPLIED (success) and CONSTRAINED (cannot proceed within constraints) as terminal states. COMPLETE is not a valid terminal state for the Apply phase.
  2. CANCELLED is terminal — a plan with processing_state=CANCELLED in any phase is considered terminal.
  3. CONSTRAINED triggers reversion — when the Apply phase reaches the CONSTRAINED state, reversion to Strategize may be triggered automatically (controlled by the auto_reversion_from_apply automation profile flag) or require manual user approval.

Computed Properties

Property Type Description
state ProcessingState Alias for processing_state
is_terminal bool True if state is APPLIED, CONSTRAINED, or CANCELLED
is_errored bool True if processing_state == ERRORED
can_transition_to_next_phase bool True if state is COMPLETE and phase is not APPLY
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"

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:

  1. plan_id, name, action, phase, state, description
  2. definition_of_done (if set)
  3. automation_profile, automation_profile_source (if set)
  4. automation_level
  5. projects (if any, with alias/read_only)
  6. invariants (if any, with source tags)
  7. arguments (if any, in stable order)
  8. strategy_actor, execution_actor (if set)
  9. error (if present)
  10. created_at, updated_at
  11. parent_plan_id (if subplan)
  12. subplan_count (if has subplans)

Subplan Hierarchy

Plans support a parent/child hierarchy for decomposition:

  • identity.parent_plan_id — Links to parent plan
  • identity.root_plan_id — Links to root of the tree
  • subplan_config — Configuration for child execution
  • subplan_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_fast or 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).