Plan Lifecycle Controls
Users can intervene in running plans with three lifecycle actions: pause, resume, and stop. These controls appear in the plan details view header and broadcast state changes in real time via WebSocket.
States
Section titled “States”Two states support lifecycle controls:
| State | Type | Meaning |
|---|---|---|
Paused | Non-terminal | Execution suspended. The plan stays paused until a user resumes or stops it. |
Stopped | Terminal | Permanently cancelled. The plan cannot be restarted. |
Both states serialize as simple tags in the PlanState JSONB enum — no additional fields:
{"status": "paused"}{"status": "stopped"}No database migration is needed. The existing plan.state JSONB column stores the new variants directly.
API Endpoints
Section titled “API Endpoints”All three endpoints require PlanInstanceAction::Approve permission on the target plan.
PUT /api/plans/{id}/pauseTransitions a plan from StandBy or AwaitingInput to Paused.
- Path param:
id— plan UUID - Success:
204 No Content - Errors:
400(invalid state),403(no permission),404(not found) - Handler:
src/mods/plan/api/pause_plan_api.rs
The executor skips paused plans — only StandBy plans are picked up by the background job.
Resume
Section titled “Resume”PUT /api/plans/{id}/resumeTransitions a plan from Paused to StandBy { next_execution_at: now() }.
- Path param:
id— plan UUID - Success:
204 No Content - Errors:
400(not paused),403,404 - Handler:
src/mods/plan/api/resume_plan_api.rs
Setting next_execution_at to now() makes the plan immediately eligible for the next executor cycle (runs every 30 seconds).
PUT /api/plans/{id}/stopTransitions any non-terminal plan to Stopped.
- Path param:
id— plan UUID - Success:
204 No Content - Errors:
400(already terminal),403,404 - Handler:
src/mods/plan/api/stop_plan_api.rs
Rejects plans already in Completed, Failed, or Stopped. If a plan is mid-execution, the executor re-reads state after the LLM call completes and skips post-execution logic when the state is no longer Executing.
Audit Trail
Section titled “Audit Trail”Each action creates a system log entry in the plan timeline:
pub enum PlanLogEntrySystem { // ...existing variants... PlanPaused { by: String }, PlanResumed { by: String }, PlanStopped { by: String },}The by field stores session.user.name — the display name of the user who triggered the action.
Real-Time Broadcasting
Section titled “Real-Time Broadcasting”All three endpoints call publish_plan_state(org_id, plan_id, state) after updating the database. This sends an EVT_PLAN_STATE_CHANGED WebSocket event to all organization subscribers. The use_realtime_plan hook in the plan details view merges live state updates with server-fetched data:
let effective_state = live_state .read() .clone() .unwrap_or_else(|| data.plan.state.clone());UI Behavior
Section titled “UI Behavior”Plan Details View
Section titled “Plan Details View”Button visibility in the header depends on the current state:
| State | Pause | Resume | Stop |
|---|---|---|---|
StandBy | ✅ | — | ✅ |
AwaitingInput | ✅ | — | ✅ |
Executing | — | — | ✅ |
Paused | — | ✅ | ✅ |
| Terminal states | — | — | — |
The autopilot toggle hides when the plan is Paused.
Status Badges
Section titled “Status Badges”| Component | Paused | Stopped |
|---|---|---|
| Plan card | Orange badge | Gray badge |
| Plan graph | Orange pill with ⏸ icon (PausedBadge) | — |
| Timeline | Orange “Paused by username” | Red “Stopped by username” |
Timeline Rendering
Section titled “Timeline Rendering”The plan timeline component renders lifecycle events with color-coded text:
- Paused: Orange text
- Resumed: Blue text
- Stopped: Red destructive text (uses destructive variant)
See src/mods/plan/components/plan_timeline_component.rs (lines 833–856).
Re-enrollment
Section titled “Re-enrollment”Stopped is a terminal state for re-enrollment purposes:
| Policy | Behavior |
|---|---|
Once | Blocks re-enrollment if any plan exists (including Stopped) |
Multiple | Allows re-enrollment — only active plans block. Stopped counts as terminal alongside Completed and Failed. |
Active states: PendingReview, StandBy, AwaitingInput, Executing, Paused.
See src/mods/plan/services/check_re_enrollment_service.rs.
File Reference
Section titled “File Reference”| File | Purpose |
|---|---|
src/mods/plan/api/pause_plan_api.rs | Pause endpoint |
src/mods/plan/api/resume_plan_api.rs | Resume endpoint |
src/mods/plan/api/stop_plan_api.rs | Stop endpoint |
src/mods/plan/types/plan_state_type.rs | Paused and Stopped variants |
src/mods/plan/types/plan_log_entry_type.rs | Audit log event variants |
src/mods/plan/views/plan_details_view.rs | Lifecycle buttons and state-dependent UI |
src/mods/plan/components/plan_graph_component.rs | PausedBadge component |
src/mods/plan/components/plan_timeline_component.rs | Timeline event rendering |
src/mods/plan/services/check_re_enrollment_service.rs | Terminal state handling |