Files
temp/docs/reference/plan_cli.md
T
hurui200320 414abb1396 fix(cli): add missing --yes flag to plan apply command (#1127)
## Summary

Adds the `--yes`/`-y` flag to the `lifecycle-apply` CLI command as required by the specification (`agents plan apply [--yes|-y] <PLAN_ID>`). Without `--yes`, a confirmation prompt now displays before proceeding with the destructive Apply phase. With `--yes`, the apply proceeds immediately without prompting.

Closes #932

## Changes

### Source Code
- **`src/cleveragents/cli/commands/plan.py`**: Added `yes: Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompt")] = False` parameter to `lifecycle_apply_plan`. Added `typer.confirm()` prompt before the apply operation, consistent with the pattern used by `rollback_plan`, `correct_plan`, and other destructive commands.
  - Confirmation prompt text matches spec exactly: `"Apply changes for plan {plan_id}?"` producing `Apply changes for plan <ID>? [y/N]:`.
  - Fixed redundant plan ID display when `pre_plan` is `None` — now shows `"Apply changes for plan X?"` instead of `"Apply plan X (X)?"`.
  - Added `except ValueError` handler consistent with sibling commands `lifecycle_execute_plan` and `_lifecycle_apply_with_id`.
  - Added `except Exception` catch-all handler with `isinstance(e, (typer.Abort, typer.Exit))` re-raise guard, consistent with `lifecycle_execute_plan`.
  - Moved `PlanPhase` and `ProcessingState` imports to module level per CONTRIBUTING.md §Import Guidelines.

### TDD Tag Removal (Bug Fix Workflow)
- **`features/tdd_plan_apply_yes_flag.feature`**: Removed `@tdd_expected_fail` tag (leaving `@tdd_bug` and `@tdd_bug_932` as permanent regression guards).
- **`robot/tdd_plan_apply_yes_flag.robot`**: Removed `tdd_expected_fail` tag (leaving `tdd_bug` and `tdd_bug_932`).

### Test Updates
Updated all existing `lifecycle-apply` invocations across 17 test/benchmark files to pass `--yes`, since the new confirmation prompt would otherwise abort in non-interactive test environments:
- 9 Behave step definition files
- 3 Robot Framework helper scripts
- 2 Robot Framework e2e acceptance tests
- 3 ASV benchmark files (4 invocations: `cli_robot_flow_bench.py` ×2, `m1_sourcecode_smoke_bench.py` ×1, `plan_cli_smoke_bench.py` ×1)

### Confirmation Prompt Tests (New + Strengthened)
- **`features/tdd_plan_apply_yes_flag.feature`**: 5 scenarios total:
  - `lifecycle-apply recognises the --yes long flag` — verifies flag acceptance, prompt suppression, exit code 0, and `apply_plan` was called
  - `lifecycle-apply recognises the -y short flag` — same as above for short flag
  - `lifecycle-apply without --yes prompts for confirmation and user declines` — verifies `"Apply cancelled."` message, `exit_code == 0`, and `apply_plan` was NOT called
  - `lifecycle-apply without --yes prompts for confirmation and user accepts` — verifies prompt appears, `exit_code == 0`, and `apply_plan` was called
  - `lifecycle-apply catches unexpected exceptions cleanly` — verifies `"Unexpected error"` output, no traceback leak, non-zero exit code (exercises the `except Exception` catch-all)
- **`features/steps/tdd_plan_apply_yes_flag_steps.py`**: Refactored step definitions:
  - `_make_mock_plan` uses `PlanPhase` and `ProcessingState` enum types instead of raw strings
  - `_make_mock_plan` uses `datetime.now(tz=UTC)` instead of timezone-naive `datetime.now()`
  - Unified prompt suppression step handles both `--yes` and `-y` via parameterised step pattern
  - Added `When` step for unexpected error scenario with `RuntimeError` side_effect
  - Added `Then` step for non-zero exit code assertion
- **Feature/Robot documentation**: Updated stale descriptions that said "implementation does not accept --yes" to reflect the flag is now implemented.

### Documentation
- **`docs/reference/plan_cli.md`**: Updated `lifecycle-apply` section with:
  - `### Synopsis` heading with code block
  - `### Options` table listing `--yes/-y` and `--format/-f` flags
  - `### Arguments` table listing `PLAN_ID`
  - Matches the style used by other command sections in the same file

## Review Fixes (Cycle 3 — Luis's review)

| ID | Severity | Issue | Resolution |
|----|----------|-------|------------|
| M1 | Medium | `typer.Abort()` on user decline produces exit code 1 and redundant "Aborted." | Changed to `raise typer.Exit(0)` — consistent with `correct_decision` and legacy `apply` |
| M2 | Medium | Missing exit code assertion on decline scenario | Added `And the lifecycle-apply exit code should be 0` to the decline scenario |
| M3 | Medium | Spec compliance: "summary of pending changes" not implemented | Deferred — spec example shows summary *after* confirmation, not before; implementation matches spec. Ticket-vs-spec ambiguity noted. |
| L1 | Low | Missing `except Exception` catch-all handler | Added catch-all matching `lifecycle_execute_plan` pattern; re-raises `typer.Abort`/`typer.Exit` |
| L2 | Low | Documentation description not updated | Expanded description in `plan_cli.md` to explain confirmation prompt and `--yes` |
| L3 | Low | Dead code `is not None` guards | Removed both guards — `get_plan()` raises `NotFoundError`, never returns `None` |
| I1 | Info | Duplicate `PlanPhase` import | Hoisted import to top of `try` block, eliminating duplicate at old line 2087 |
| I2 | Info | `typer.confirm` without explicit `default=False` | Added `default=False` for consistency with sibling commands |
| L4 | Low | No test for `--yes` after positional arg | Not addressed — Typer/Click handles both orderings; low risk |
| L5 | Low | No test for auto-select + interactive prompt | Not addressed — separate concern outside ticket scope |
| I3 | Info | Robot helper only tests flag recognition | By design — noted as informational |

## Review Fixes (Cycle 4 — Self-QA)

| ID | Severity | Issue | Resolution |
|----|----------|-------|------------|
| Major-1 | Major | No test for `except Exception` catch-all handler | Added new scenario `"lifecycle-apply catches unexpected exceptions cleanly"` with `RuntimeError` side_effect; asserts `"Unexpected error"` output, no traceback, non-zero exit |
| Minor-2 | Minor | Missing `ValueError` handler inconsistent with siblings | Added `except ValueError as e:` with `"[red]Execution Error:[/red]"` before catch-all, matching `lifecycle_execute_plan` and `_lifecycle_apply_with_id` |
| Minor-3 | Minor | Flag scenarios don't verify `apply_plan` called | Added `And the lifecycle-apply should have called apply` to both `--yes` and `-y` scenarios |
| Minor-4 | Minor | Stale docstring in Robot helper references `tdd_expected_fail` inversion | Updated to reflect bug is fixed and tests serve as regression guards |
| Minor-5 | Minor | `plan_cli.md` lacks Options table for `lifecycle-apply` | Added Synopsis, Options, and Arguments sections matching sibling command style |
| Nit-6 | Nit | Duplicated step defs for `--yes` vs `-y` prompt suppression | Unified into single parameterised step `"the lifecycle-apply {flag} output should not contain the confirmation prompt"` |
| Nit-7 | Nit | `datetime.now()` timezone-naive | Changed to `datetime.now(tz=UTC)` |
| Nit-8 | Nit | `_make_mock_plan` params use `str` instead of enum types | Changed to `PlanPhase` and `ProcessingState` enum types |

## Review Fixes (Cycle 5 — Jeff's approval note)

| ID | Severity | Issue | Resolution |
|----|----------|-------|------------|
| Import-1 | Minor | `PlanPhase`/`ProcessingState` imports inside function body instead of module level | Moved to module-level import per CONTRIBUTING.md §Import Guidelines |

## Known Limitations / Deferred Items

- **M3: Ticket AC mentions "summary of pending changes"** but the spec example only shows `"Apply changes for plan <ID>? [y/N]: y"` without a change summary. The implementation shows plan ID only (matching the spec), not a change summary. This is a ticket-vs-spec ambiguity; recommend discussing with ticket author.
- **Legacy `apply` command** accepts `--yes` but does not pass it to `_lifecycle_apply_with_id()`. This is a pre-existing issue outside the scope of this ticket.
- **`pre_plan is None` branch** has no explicit test. Pre-existing architectural issue; no action taken.

## Quality Gates

| Gate | Result |
|------|--------|
| `nox -s lint` |  passed |
| `nox -s typecheck` |  passed (0 errors) |
| `nox -s unit_tests` |  passed (471 features, 12,424 scenarios, 0 failures) |
| `nox -s integration_tests` |  passed (1,727 tests, 0 failures) |
| `nox -s e2e_tests` |  passed (41 tests, 0 failures) |
| `nox -s coverage_report` |  passed (≥97% coverage) |

Reviewed-on: cleveragents/cleveragents-core#1127
Reviewed-by: Jeffrey Phillips Freeman <jeffrey.freeman@cleverthis.com>
Co-authored-by: Rui Hu <rui.hu@cleverthis.com>
Co-committed-by: Rui Hu <rui.hu@cleverthis.com>
2026-03-26 07:50:09 +00:00

8.5 KiB

Plan CLI Reference

The agents plan command group manages plans in the CleverAgents v3 plan lifecycle.

Commands

Command Description
agents plan use Create plan from action + project(s)
agents plan lifecycle-list List plans with optional filters
agents plan status Show plan status / details
agents plan execute Transition to Execute phase
agents plan lifecycle-apply Transition to Apply phase
agents plan cancel Cancel a non-terminal plan
agents plan diff Show ChangeSet as unified diff
agents plan artifacts Show ChangeSet ID, sandbox refs, summary
agents plan explain Explain a single decision
agents plan tree Display decision tree for a plan

agents plan use

Create a plan from an action template and one or more projects.

Synopsis

agents plan use <ACTION_NAME> [PROJECTS...] [OPTIONS]

Options

Flag Description
--project, -p Project name (repeatable for multiple projects)
--arg, -a Argument value in name=value format (repeatable)
--automation-profile Automation profile name (e.g., trusted, manual)
--invariant Invariant constraint text (repeatable)
--strategy-actor Override strategy actor (namespace/name format)
--execution-actor Override execution actor (namespace/name format)
--estimation-actor Override estimation actor (namespace/name format)
--invariant-actor Override invariant reconciliation actor
--format, -f Output format: json, yaml, plain, table, rich

Actor Override Validation

All actor override flags require namespaced format: namespace/name (e.g., openai/gpt-4, anthropic/claude-3). Invalid formats are rejected with a descriptive error.

Examples

# Basic usage with one project
agents plan use local/code-coverage my-project --arg target_coverage=80

# Multiple projects
agents plan use local/lint proj-1 proj-2

# With automation profile and invariants
agents plan use local/refactor my-project \
  --automation-profile trusted \
  --invariant "No new warnings" \
  --invariant "Maintain backward compatibility"

# With actor overrides
agents plan use local/code-coverage my-project \
  --strategy-actor openai/gpt-4 \
  --execution-actor anthropic/claude-3 \
  --estimation-actor openai/gpt-4

# JSON output
agents plan use local/lint my-project --format json

agents plan status

Show status of one or all v3 lifecycle plans.

Synopsis

agents plan status [PLAN_ID] [--format FORMAT]

When called without a plan ID, displays a summary table of all active plans including automation profile and invariant count columns.

Output Fields

  • ID: Truncated plan ULID
  • Name: Namespaced plan name
  • Phase: Current lifecycle phase
  • State: Processing state
  • Profile: Automation profile name (if set)
  • Invariants: Count of attached invariants
  • Terminal: Whether the plan is in a terminal state

agents plan lifecycle-list

List v3 lifecycle plans with optional filtering.

Synopsis

agents plan lifecycle-list [REGEX] [OPTIONS]

Options

Flag Description
--phase Filter by phase (strategize, execute, apply)
--state Filter by processing state
--processing-state Alias for --state
--project, -p Filter by project name
--action Filter by action name
--format, -f Output format

Output Fields

Includes Profile and Invariants columns in all output formats when present on the plan.

agents plan execute

Run the current plan phase synchronously. Detects the plan's current phase and processes it inline:

  • Strategize/queued — runs the strategize phase to completion, then auto-progresses to Execute if the automation profile permits.
  • Strategize/complete — transitions to Execute and runs it.
  • Execute/queued — runs the execute phase to completion.

When no plan ID is given, auto-selects the single eligible plan.

agents plan execute [PLAN_ID] [--format FORMAT]

Internal Wiring

The CLI handler shares a single PlanLifecycleService instance between the command logic and the PlanExecutor to avoid stale in-memory cache reads after phase transitions. See CLI Executor Wiring for details.

agents plan lifecycle-apply

Transition a plan from Execute to Apply phase. Because Apply is a destructive operation (it merges sandbox changesets into real project resources), a confirmation prompt is displayed by default. Pass --yes / -y to skip the prompt in scripts or CI pipelines.

Synopsis

agents plan lifecycle-apply [--yes|-y] [PLAN_ID] [--format FORMAT]

Options

Flag Description
--yes, -y Skip the confirmation prompt and apply immediately
--format, -f Output format: json, yaml, plain, table, rich

Arguments

Argument Description
PLAN_ID Plan ID to apply (optional; auto-selects if only one eligible)

agents plan cancel

Cancel a non-terminal plan.

agents plan cancel PLAN_ID [--reason REASON] [--format FORMAT]

agents plan diff

Show ChangeSet as unified diff for a plan.

agents plan diff PLAN_ID [--correction ID] [--format FORMAT]

agents plan artifacts

Show plan artifacts including ChangeSet ID and sandbox references.

agents plan artifacts PLAN_ID [--format FORMAT]

agents plan explain

Explain a single decision in the plan decision tree.

Synopsis

agents plan explain <DECISION_ID> [OPTIONS]

Options

Flag Description
--format, -f Output format: json, yaml, plain, table, rich
--show-context Include context snapshot details
--show-reasoning Include rationale and actor reasoning

Alternatives considered are always included in the output.

Examples

# Default rich output
agents plan explain 01HXYZ1234567890ABCDEFGH

# JSON with full context
agents plan explain 01HXYZ1234567890ABCDEFGH --format json --show-context

# Show reasoning
agents plan explain 01HXYZ1234567890ABCDEFGH --show-reasoning

# YAML output with all details
agents plan explain 01HXYZ1234567890ABCDEFGH --format yaml \
  --show-context --show-reasoning

agents plan tree

Display the decision tree for a plan.

Synopsis

agents plan tree <PLAN_ID> [OPTIONS]

Options

Flag Description
--format, -f Output format: json, yaml, plain, table, rich
--show-superseded Include superseded decisions in the tree
--depth Maximum tree depth (0 = unlimited, default: 0)

Examples

# Default rich tree view
agents plan tree 01HXYZ1234567890ABCDEFGH

# Table format
agents plan tree 01HXYZ1234567890ABCDEFGH --format table

# Include superseded decisions
agents plan tree 01HXYZ1234567890ABCDEFGH --show-superseded

# Limit depth to 2 levels
agents plan tree 01HXYZ1234567890ABCDEFGH --depth 2

# JSON output for scripting
agents plan tree 01HXYZ1234567890ABCDEFGH --format json