with one click
manage-status
// Manage status.json files with phase tracking, metadata, and lifecycle operations
// Manage status.json files with phase tracking, metadata, and lifecycle operations
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | manage-status |
| description | Manage status.json files with phase tracking, metadata, and lifecycle operations |
| user-invocable | false |
| scope | plan |
Manage status.json files with phase tracking, metadata, and lifecycle operations. Handles plan status storage (JSON), phase operations, metadata management, plan discovery, phase transitions, archiving, and routing.
Base contract: See manage-contract.md for shared enforcement rules, TOON output format, and error response patterns.
Skill-specific constraints:
pending, in_progress, donemanage_status) because it is imported as a Python module by other scriptsset-phase, update-phase, or transition commands--get or --set flagsStandards: See status-lifecycle.md for the phase state machine, plan lifecycle, and metadata conventions.
get-routing-context for combined stateStatus is stored in the plan directory:
.plan/plans/{plan_id}/status.json
JSON format for storage:
{
"title": "Plan Title",
"current_phase": "1-init",
"phases": [
{"name": "1-init", "status": "in_progress"},
{"name": "2-refine", "status": "pending"},
{"name": "3-outline", "status": "pending"},
{"name": "4-plan", "status": "pending"},
{"name": "5-execute", "status": "pending"},
{"name": "6-finalize", "status": "pending"}
],
"metadata": {
"change_type": "feature",
"use_worktree": true,
"worktree_path": "/abs/path/.plan/local/worktrees/my-feature",
"worktree_branch": "feature/my-feature"
},
"created": "2025-01-15T10:00:00Z",
"updated": "2025-01-15T14:30:00Z"
}
| Field | Type | Description |
|---|---|---|
title | string | Plan title |
current_phase | string | Current active phase |
phases | list | Phase objects with name and status |
metadata | table | Key-value metadata (common fields: change_type, confidence, domain, use_worktree, worktree_path, worktree_branch) |
created | string | ISO timestamp of creation |
updated | string | ISO timestamp of last update |
| Status | Description |
|---|---|
pending | Phase not yet started |
in_progress | Phase currently active |
done | Phase completed |
status.metadata is the canonical source of truth for whether a plan
runs in an isolated git worktree. Three fields work together; create
seeds them atomically and get-worktree-path reads them:
| Field | Type | When set | Description |
|---|---|---|---|
use_worktree | bool | Always (seeded by create) | true when the plan runs in an isolated worktree, false when it runs against the main checkout. Never absent on plans created via create. |
worktree_path | string | Only when use_worktree==true | Absolute path to the worktree root. Used by get-worktree-path, build wrappers (--plan-id resolution), and phase-entry assertions. |
worktree_branch | string | Only when use_worktree==true | Feature branch ref checked out in the worktree. Recorded for the audit trail and consumed by workflow-integration-git worktree subcommands. |
Downstream consumers MUST read these fields via get-worktree-path
rather than re-deriving the path from filesystem layout. Re-derivation
breaks if the platform-neutral worktree root constant ever changes
again, and it duplicates logic that manage-status already owns.
Script: plan-marshall:manage-status:manage_status
Create status.json with initial phases. Optionally seeds the worktree
trio (use_worktree, worktree_path, worktree_branch) into
status.metadata so downstream consumers can resolve the active
worktree from the plan id alone.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status create \
--plan-id {plan_id} \
--title {title} \
--phases {comma-separated-phases} \
[--force] \
[--use-worktree --worktree-path {abs_path} --worktree-branch {ref}]
Parameters:
--plan-id (required): Plan identifier (kebab-case)--title (required): Plan title--phases (required): Comma-separated phase names in execution order (e.g., 1-init,2-refine,3-outline,4-plan,5-execute,6-finalize). Order matters — it determines progress calculation and transition sequence.--force: Overwrite existing status.json--use-worktree (optional): Mark the plan as running in an isolated git worktree. When set, both --worktree-path and --worktree-branch are required. Seeds status.metadata.use_worktree=true and persists the path and branch alongside it. When omitted, status.metadata.use_worktree=false is seeded explicitly so downstream resolvers never have to treat absence-of-metadata as "main-checkout".--worktree-path (required with --use-worktree): Absolute path to the worktree root. Persisted as status.metadata.worktree_path.--worktree-branch (required with --use-worktree): Feature branch ref checked out in the worktree. Persisted as status.metadata.worktree_branch.Output — main-checkout (TOON):
status: success
plan_id: my-feature
file: status.json
created: true
plan:
title: My Feature
current_phase: 1-init
use_worktree: false
Output — worktree (TOON):
status: success
plan_id: my-feature
file: status.json
created: true
plan:
title: My Feature
current_phase: 1-init
use_worktree: true
worktree_path: /abs/path/.plan/local/worktrees/my-feature
worktree_branch: feature/my-feature
Error — partial worktree args (TOON):
status: error
plan_id: my-feature
error: invalid_worktree_args
message: --use-worktree requires both --worktree-path and --worktree-branch
Read entire status.json content.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status read \
--plan-id {plan_id}
Output (TOON):
status: success
plan_id: my-feature
plan:
title: My Feature
current_phase: 2-refine
phases: [...]
metadata: {...}
Set current phase (marks phase as in_progress).
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status set-phase \
--plan-id {plan_id} \
--phase {phase_name}
Output (TOON):
status: success
plan_id: my-feature
current_phase: 2-refine
previous_phase: 1-init
Update a specific phase's status.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status update-phase \
--plan-id {plan_id} \
--phase {phase_name} \
--status {pending|in_progress|done}
Output (TOON):
status: success
plan_id: my-feature
phase: 1-init
phase_status: done
Calculate plan progress percentage.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status progress \
--plan-id {plan_id}
Output (TOON):
status: success
plan_id: my-feature
progress:
total_phases: 6
completed_phases: 3
current_phase: 4-plan
percent: 50
Progress formula: percent = floor(completed_phases / total_phases * 100). A phase counts as "completed" only when its status is done. Phases with status in_progress or pending are not counted.
Get or set metadata fields.
Set metadata:
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status metadata \
--plan-id {plan_id} \
--set \
--field {field_name} \
--value {value}
Get metadata:
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status metadata \
--plan-id {plan_id} \
--get \
--field {field_name}
Output (set) (TOON):
status: success
plan_id: my-feature
field: change_type
value: feature
previous_value: bug_fix
Output (get) (TOON):
status: success
plan_id: my-feature
field: change_type
value: feature
Record the outcome of a phase step inside status.metadata.phase_steps. Phase skills use this to persist intra-phase progress (e.g., discovery, drift-detection) so that resuming a phase can skip completed steps. Outcomes are restricted to done or skipped. An optional --display-detail one-line string is persisted alongside the outcome so downstream renderers (phase-6-finalize vertical-steps block, etc.) can surface user-facing step summaries.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status mark-step-done \
--plan-id {plan_id} \
--phase {phase_name} \
--step {step_id} \
--outcome {done|skipped} \
[--display-detail "one-line user-facing detail"] \
[--force]
Parameters:
--plan-id (required): Plan identifier--phase (required): Phase name (e.g., 5-execute)--step (required): Step identifier within the phase (free-form string chosen by the phase skill)--outcome (required): done or skipped--display-detail (optional at CLI level, required-by-convention for phase-6-finalize steps per the phase-6-finalize interface contract): One-line user-facing detail string. Persisted as null when omitted.--force (optional): Overwrite an existing differing outcomeStorage shape (breaking — replaces the old bare-string shape):
status.metadata.phase_steps[{phase}][{step}] = {
"outcome": "done" | "skipped",
"display_detail": <string> | null
}
Both the metadata and phase_steps containers are created on demand. Bare-string entries from prior versions are treated as drift — see conflict semantics below.
Semantics:
display_detail, no file write occurs and changed: false is returned.display_detail differs, the command updates the detail in place and returns changed: true.--force is not supplied, the command returns error: conflict with the existing outcome surfaced in the response. Supplying --force overwrites the existing value (and detail).error: legacy_string_entry and refuses to write. The caller must migrate status.metadata.phase_steps to the dict shape before retrying — there is no automatic migration.Forward reference —
phase_steps_completeinvariant: Downstream phase skills and verification helpers treatstatus.metadata.phase_steps[{phase}]as the authoritative record of which intra-phase steps have been markeddoneorskipped. A phase is consideredphase_steps_completewhen every step in the phase's declared step list has a dict entry withoutcome == 'done'. The invariant reader rejects bare-string entries as legacy drift. Consumers must not fabricate entries by other means — always go throughmark-step-done.
Output — idempotent no-op (TOON):
status: success
plan_id: my-feature
phase: 5-execute
step: discovery
outcome: done
display_detail: null
changed: false
Output — state changed (TOON):
status: success
plan_id: my-feature
phase: 5-execute
step: discovery
outcome: done
display_detail: Discovered 3 drift candidates across deliverables 2 and 4
changed: true
previous_outcome: null
previous_display_detail: null
Output — conflict (TOON):
status: error
plan_id: my-feature
error: conflict
phase: 5-execute
step: discovery
existing_outcome: skipped
requested_outcome: done
message: Step 'discovery' in phase '5-execute' already marked as 'skipped'; use --force to overwrite with 'done'
Output — legacy drift (TOON):
status: error
plan_id: my-feature
error: legacy_string_entry
phase: 5-execute
step: discovery
existing_outcome: done
requested_outcome: done
message: Step 'discovery' in phase '5-execute' has legacy bare-string storage ('done'); migrate status.metadata.phase_steps to the dict shape {"outcome": ..., "display_detail": ...} before retrying.
Get combined status context (phase, progress, metadata) in one call.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status get-context \
--plan-id {plan_id}
Output (TOON):
status: success
plan_id: my-feature
title: My Feature
current_phase: 2-refine
total_phases: 6
completed_phases: 1
change_type: feature
Note: All metadata fields are promoted to top level for convenience (flattened from metadata object). The fields shown depend on what has been set via metadata --set.
Resolve the persisted worktree path for a plan from status.metadata.
Allows callers (build wrappers, git_workflow, phase-entry assertions)
to look up the active worktree by --plan-id alone — without
re-deriving the path from filesystem layout, and without taking a
--project-dir argument.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status get-worktree-path \
--plan-id {plan_id}
Parameters:
--plan-id (required): Plan identifierBehavior:
metadata.use_worktree == true and metadata.worktree_path is set → returns the absolute path.metadata.use_worktree == false (or metadata is absent) → returns worktree_path: '' (empty string). Callers interpret this as "plan runs against the main checkout".metadata.use_worktree == true but metadata.worktree_path is missing → returns error: worktree_unresolved (data integrity failure: the seed at create time is missing).Output — worktree resolved (TOON):
status: success
plan_id: my-feature
use_worktree: true
worktree_path: /abs/path/.plan/local/worktrees/my-feature
worktree_branch: feature/my-feature
Output — main checkout (TOON):
status: success
plan_id: my-feature
use_worktree: false
worktree_path: ""
Output — unresolved (TOON):
status: error
plan_id: my-feature
error: worktree_unresolved
message: metadata.use_worktree is true but metadata.worktree_path is missing — plan was created without seeding the worktree path.
Discover all plans, optionally filtered by current phase.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status list \
[--filter PHASE]
Parameters:
--filter (optional): Comma-separated phase names to filter byOutput (TOON):
status: success
total: 2
plans[2]{id,current_phase,status}:
my-feature,3-outline,in_progress
bugfix-123,5-execute,in_progress
Mark a phase as done and advance to next phase. Validates phase ordering.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status transition \
--plan-id {plan_id} \
--completed {phase_name}
Output (TOON):
status: success
plan_id: my-feature
completed_phase: 3-outline
next_phase: 4-plan
Archive a completed plan (moves to .plan/archived-plans/YYYY-MM-DD-{plan_id}).
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status archive \
--plan-id {plan_id} \
[--dry-run]
Output (TOON):
status: success
plan_id: my-feature
archived_to: .plan/archived-plans/2026-04-02-my-feature
Delete an entire plan directory. Used when user selects "Replace" for an existing plan during plan-init.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status delete-plan \
--plan-id {plan_id}
Output (TOON format):
On success:
status: success
plan_id: my-feature
action: deleted
path: /path/to/.plan/plans/my-feature
files_removed: 5
On error (plan not found):
status: error
plan_id: my-feature
error: plan_not_found
message: Plan directory does not exist: /path/to/.plan/plans/my-feature
Use case: Called by plan-init when user selects "Replace" to delete existing plan before creating new one. See plan-marshall:phase-1-init/standards/plan-overwrite.md for the full workflow.
Warning: This recursively deletes the entire plan directory including all subdirectories (logs, tasks, work artifacts). There is no undo.
Get skill name for a phase.
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status route \
--phase {phase_name}
Output (TOON):
status: success
phase: 3-outline
skill: solution-outline
description: Create solution outline with deliverables
Get combined routing context (phase + skill + progress in one call).
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status get-routing-context \
--plan-id {plan_id}
Output (TOON):
status: success
plan_id: my-feature
title: Add caching layer
current_phase: 3-outline
skill: solution-outline
skill_description: Create solution outline with deliverables
total_phases: 6
completed_phases: 2
Verify manage-status health (checks imports, phase routing table, directory access).
python3 .plan/execute-script.py plan-marshall:manage-status:manage_status self-test
Output (TOON):
status: success
passed: 4
failed: 0
Phase set, transition rules, and phase-to-skill routing are defined in standards/status-lifecycle.md. The standard 6-phase model (1-init through 6-finalize) is sequential — the transition command enforces ordering.
Script: plan-marshall:manage-status:manage_status
| Command | Parameters | Description |
|---|---|---|
create | --plan-id --title --phases [--force] [--use-worktree --worktree-path --worktree-branch] | Create status.json (seeds worktree metadata when --use-worktree is present) |
read | --plan-id | Read full status |
set-phase | --plan-id --phase | Set current phase (marks as in_progress) |
update-phase | --plan-id --phase --status | Update specific phase status |
progress | --plan-id | Calculate progress percentage |
metadata | --plan-id --get/--set --field [--value] | Get/set metadata fields |
mark-step-done | --plan-id --phase --step --outcome [--display-detail] [--force] | Record phase step outcome (+ optional display detail) in metadata.phase_steps |
get-context | --plan-id | Get combined status context |
get-worktree-path | --plan-id | Resolve persisted worktree path (returns empty string when use_worktree==false) |
list | [--filter PHASE] | Discover all plans, optionally filtered by phase |
transition | --plan-id --completed | Mark phase done, advance to next |
archive | --plan-id [--dry-run] | Archive completed plan |
delete-plan | --plan-id | Delete entire plan directory |
route | --phase | Get skill name for phase |
get-routing-context | --plan-id | Get combined routing context |
self-test | (none) | Verify manage-status health |
See manage-contract.md for the standard error response format.
| Error Code | Exit Code | Cause |
|---|---|---|
invalid_plan_id | 1 | Plan ID not in kebab-case format |
file_not_found | 1 | status.json doesn't exist |
file_exists | 1 | status.json already exists (use --force) |
invalid_phase | 1 | Phase name not in the phases list (set-phase, update-phase, transition) |
phase_not_found | 1 | Phase doesn't exist in this plan's status.json phases array |
unknown_phase | 1 | Phase name not in the static valid phases set (1-init through 6-finalize); only used by route command |
plan_not_found | 1 | Plan directory does not exist (delete-plan command) |
not_found | 1 | Plan directory not found (archive command) |
not_found | 0 | Metadata field doesn't exist — valid query result (returns value: null), not an error |
conflict | 1 | mark-step-done: step already has a different outcome and --force was not supplied |
legacy_string_entry | 1 | mark-step-done: existing entry uses the pre-migration bare-string shape; caller must migrate to dict shape before retrying |
invalid_outcome | 1 | mark-step-done: outcome not in done/skipped |
invalid_argument | 1 | mark-step-done: empty --phase or --step |
invalid_worktree_args | 1 | create: --use-worktree set without both --worktree-path and --worktree-branch |
worktree_unresolved | 1 | get-worktree-path: metadata.use_worktree==true but metadata.worktree_path is missing (data integrity failure from a partial seed at create time) |
Called by: plan-marshall:plan-marshall orchestrator for phase transitions, phase-1-init for initial status creation, and phase-6-finalize for archiving.
Phase skills read/update status through manage-status:
createset-phase, metadata, get-context, transitionarchive for completed plansAgents use metadata to store change_type and other classification data.
plan-marshall — Orchestrator that drives phase transitionsphase-1-init through phase-6-finalize — Phase-specific skills routed to by manage-statusmanage-metrics — Augments phase tracking with timing and token datamanage-config — System configuration consumed by status operations