Files
cleveragents-core/docs/reference/plan_model.md
T

172 lines
6.2 KiB
Markdown

# 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`