marketplace/bundles/plan-marshall/skills/manage-execution-manifest/SKILL.md
Compose, read, and validate the per-plan execution manifest that drives Phase 5 verification and Phase 6 finalize step selection
npx skillsauth add cuioss/plan-marshall manage-execution-manifestInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Compose, read, and validate the per-plan execution manifest — a small declarative artifact emitted at the end of phase-4-plan that names the exact Phase 5 verification steps and Phase 6 finalize steps for this plan. Phases 5 and 6 become dumb manifest executors; per-doc skip logic in their standards is removed in favor of this single source of truth.
This skill is script-only: it has no user-invocable command and is not loaded into LLM context via Skill: directives. It is invoked exclusively through the 3-part script notation plan-marshall:manage-execution-manifest:manage-execution-manifest. Per the project memory's plugin.json registration rules, it MUST NOT be registered in plugin.json.
Base contract: See manage-contract.md for shared enforcement rules, TOON output format, and error response patterns.
Skill-specific constraints:
manage-logging decision.decision.log.compose is idempotent: re-invocation overwrites the previous manifest. Callers responsible for re-entry semantics.The manifest is stored in the plan directory:
.plan/local/plans/{plan_id}/execution.toon
TOON format. Manifest schema:
manifest_version: 1
plan_id: {plan_id}
phase_5:
early_terminate: false
verification_steps[N]:
- quality-gate
- module-tests
- coverage
phase_6:
steps[M]:
- commit-push
- create-pr
- automated-review
- sonar-roundtrip
- lessons-capture
- branch-cleanup
- archive-plan
execution_log[K]{step_id,phase,outcome,total_tokens,tool_uses,duration_ms,timestamp}:
- quality_check,5-execute,executed,12000,8,4200,2026-06-08T10:15:00+00:00
- create-pr,6-finalize,skipped,0,0,0,2026-06-08T10:42:00+00:00
| Field | Type | Description |
|-------|------|-------------|
| manifest_version | int | Schema version (currently 1) |
| plan_id | string | Plan identifier (echo) |
| phase_5.early_terminate | bool | If true, Phase 5 transitions directly to Phase 6 without running tasks (analysis-only plans with empty affected_files) |
| phase_5.verification_steps | list[string] | Ordered list of Phase 5 verification step IDs (e.g., quality-gate, module-tests, coverage). Empty list means no verification needed (e.g., docs-only plans) |
| phase_6.steps | list[string] | Ordered list of Phase 6 finalize step IDs to dispatch. Subset of the canonical step set: commit-push, create-pr, automated-review, sonar-roundtrip, lessons-capture, branch-cleanup, archive-plan, record-metrics, lessons-integration. CI completion is a dispatcher-resolved precondition declared via requires: [ci-complete] on consumer step frontmatters (see phase-6-finalize/SKILL.md Step 3 § "Precondition resolution") — it is not itself a step in the canonical set. |
| execution_log | list[object] | Ordered append log of per-step execution records, written one row per record-step invocation. Each row carries step_id (the dispatched step), phase (5-execute or 6-finalize), outcome (executed/skipped/error), the token-attribution triple total_tokens/tool_uses/duration_ms (default 0), and an ISO-8601 timestamp. Absent until the first record-step call; the compose/read/validate/validate-loadable operations never read or write it. |
Script: plan-marshall:manage-execution-manifest:manage-execution-manifest
Compose and write the execution manifest from inputs gathered at the end of phase-4-plan.
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest \
compose \
--plan-id {plan_id} \
--change-type {change_type} \
--track {simple|complex} \
--scope-estimate {none|surgical|single_module|multi_module|broad} \
[--recipe-key {recipe_key}] \
[--affected-files-count {N}] \
[--phase-5-steps {step1,step2,...}] \
[--phase-6-steps {step1,step2,...}] \
[--commit-and-push {true|false}]
Parameters:
--plan-id (required): Plan identifier (kebab-case)--change-type (required): analysis|feature|enhancement|bug_fix|tech_debt|verification--track (required): simple|complex — outline track from phase-3-outline--scope-estimate (required): none|surgical|single_module|multi_module|broad — from solution outline metadata (deliverable 2)--recipe-key (optional override): Forces the recipe rule. When omitted, the composer reads the provenance itself from status.json::metadata.plan_source (falling back to metadata.recipe_key), so lesson- and recipe-derived plans select the recipe rule without the caller forwarding this flag.--affected-files-count (optional, default 0): Count of affected files surfaced by the outline; used by the early_terminate rule--phase-5-steps (optional): Comma-separated candidate Phase 5 verification step IDs from marshal.json (e.g., quality-gate,module-tests,coverage). The decision matrix selects a subset. If omitted, defaults to quality-gate,module-tests.--phase-6-steps (optional): Comma-separated candidate Phase 6 finalize step IDs from marshal.json (e.g., commit-push,create-pr,automated-review,sonar-roundtrip,lessons-capture,branch-cleanup,archive-plan). The decision matrix selects a subset. If omitted, defaults to the full canonical set.--commit-and-push (optional, default true): true|false — the resolved commit_and_push boolean from phase-5-execute config. When false, commit-push, pre-push-quality-gate, and pre-submission-self-review are all removed from the candidate set by the commit_push_disabled pre-filter before the matrix runs (a local-only run).Output (TOON):
status: success
plan_id: EXAMPLE-PLAN
file: execution.toon
created: true
manifest_version: 1
phase_5:
early_terminate: false
verification_steps_count: 2
phase_6:
steps_count: 6
rule_fired: surgical_tech_debt
commit_and_push: true
commit_push_omitted: false
pre_push_quality_gate_omitted: false
pre_submission_self_review_omitted: false
simplify_omitted: true
scope_gated_finalize_dropped[0]:
drop_review_on_scope_gate: false
ceremony_finalize_gates:
self_review: auto
qgate: auto
plugin_doctor: auto
simplify: auto
ceremony_finalize_forced_in[0]:
ceremony_finalize_forced_out[0]:
Read the manifest as TOON.
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest \
read --plan-id {plan_id}
Output (TOON): the full manifest content (see schema above), wrapped with status: success and echoed plan_id.
Append one per-step execution record (outcome + token attribution) to the manifest's execution_log[] section. The manifest MUST already exist (composed by phase-4-plan Step 8b); record-step returns file_not_found otherwise.
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest \
record-step \
--plan-id {plan_id} \
--step-id {step_id} \
--phase {5-execute|6-finalize} \
--outcome {executed|skipped|error} \
[--total-tokens {N}] \
[--tool-uses {N}] \
[--duration-ms {N}]
Parameters:
--plan-id (required): Plan identifier--step-id (required): Step identifier being recorded (e.g., a phase-5 verification step ID or a phase-6 finalize step ID)--phase (required): 5-execute|6-finalize — the phase the step ran in--outcome (required): executed|skipped|error — whether the step ran, was skipped, or errored--total-tokens (optional, default 0): Total tokens attributed to the step--tool-uses (optional, default 0): Tool-use count attributed to the step--duration-ms (optional, default 0): Wall-clock duration in millisecondsEach call appends exactly one row to execution_log[] (an ordered append log, not a keyed map) and emits one decision.log line via the in-process _emit_decision_log helper. Re-invocation appends another row deterministically, so every dispatch of a step is recorded. This makes per-step execution metadata loggable per-plan deterministically rather than relying on the fragile orchestrator <usage>-forwarding boundary call.
Output (TOON):
status: success
plan_id: EXAMPLE-PLAN
file: execution.toon
recorded: true
step_id: quality_check
phase: 5-execute
outcome: executed
total_tokens: 12000
tool_uses: 8
duration_ms: 4200
timestamp: 2026-06-08T10:15:00+00:00
execution_log_count: 1
On a missing manifest: status: error, error: file_not_found. On an invalid --phase / --outcome value: status: error, error: invalid_phase / invalid_outcome.
Verify the manifest schema and that all step IDs exist in the candidate marshal.json set.
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest \
validate --plan-id {plan_id} \
[--phase-5-steps {step1,step2,...}] \
[--phase-6-steps {step1,step2,...}]
Parameters:
--plan-id (required): Plan identifier--phase-5-steps (optional): Comma-separated allowed Phase 5 step IDs to validate against--phase-6-steps (optional): Comma-separated allowed Phase 6 step IDs to validate againstOutput (TOON):
status: success
plan_id: EXAMPLE-PLAN
valid: true
phase_5_unknown_steps_count: 0
phase_6_unknown_steps_count: 0
On failure: status: error, error: invalid_manifest, plus a message and per-section unknown-step list.
The execution manifest is a write-time snapshot, not a runtime view. Two halves, both load-bearing — the manifest's design depends on both:
compose reads the then-current plugin cache state (decision-rules tables, candidate step lists from marshal.json, recipe-key mappings, default Phase 5 / Phase 6 step sets) and writes a fixed list of step IDs into .plan/local/plans/{plan_id}/execution.toon. The composer is phase-4-plan Step 8b at plan-write time; phase-5-execute MAY re-invoke compose to amend during its own loop, but every invocation is idempotent — the file is overwritten in full from the inputs supplied to that call.read is a literal file load. phase-5-execute and phase-6-finalize consume phase_5.verification_steps and phase_6.steps verbatim from the persisted file — they do NOT re-derive the list from current decision rules, do NOT re-consult marshal.json for fresh candidate sets, and do NOT re-apply the decision matrix at consumption time. The manifest IS the contract for the running plan.Consequence — Phase 6 reads the pre-change snapshot: a plan that modifies a decision rule, a marshal.json default, the seven-row decision matrix, or any other manifest-composer input still sees the pre-change manifest shape when phase-6-finalize reads it back, even after /sync-plugin-cache has run and the Claude Code session has been restarted. The cache sync and session restart fix the manifest's future composition (subsequent plans that invoke compose), not the current plan's already-written execution.toon.
Meta-projects that author marketplace bundles maintain their own self-host fence to guard against this class of staleness in their own finalize phase; consumer projects of plan-marshall do not encounter the failure mode because their plans do not modify the manifest composer's own resolution roots. Plans that intend to use a newly-introduced step or a newly-changed decision rule in their own finalize phase MUST either (a) re-run compose after the cache sync and session restart (re-composition re-reads the now-current cache state) or (b) edit execution.toon directly with the intended step list. The validate and validate-loadable operations remain valid post-edit; both check the persisted file, not a re-derived view.
The write-time-snapshot model is a deliberate design choice — it makes the manifest diffable, auditable, and resumable across crashes. Re-resolving at read time would couple every Phase 6 step dispatch to the in-memory decision rules, which is precisely the coupling the manifest exists to break.
Verify that the standards file backing each phase_6.steps entry is present and readable. This is the loadability fail-fast guard consumed by phase-6-finalize Step 1.5 to catch self-modifying plans that delete a built-in step's standards file without sweeping marshal.json.
# Single-step form
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest \
validate-loadable --plan-id {plan_id} --step-id {step_id}
# Bulk form — validate every step in manifest.phase_6.steps
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest \
validate-loadable --plan-id {plan_id} --all
Parameters:
--plan-id (required): Plan identifier--step-id (mutually exclusive with --all): A single step id to check (bare name commit-push or prefixed default:commit-push; both forms accepted)--all (mutually exclusive with --step-id): Walk every entry in manifest.phase_6.steps and report per-step resultsScope: built-in steps only (bare names that resolve to marketplace/bundles/plan-marshall/skills/phase-6-finalize/standards/{name}.md). External steps (project: / bundle:skill) are out of scope — validate-loadable returns loadable: true for them with no further check, on the rationale that their loadability is the host plugin cache's responsibility and a missing skill surfaces at Skill: {ref} dispatch time as a different failure mode.
Output (single-step form):
status: success
plan_id: EXAMPLE-PLAN
step_id: commit-push
standards_path: marketplace/bundles/plan-marshall/skills/phase-6-finalize/standards/commit-push.md
loadable: true
When the standards file is missing or unreadable, loadable: false and a message field carries the canonical actionable phrasing:
status: success
plan_id: EXAMPLE-PLAN
step_id: missing-step
standards_path: marketplace/bundles/plan-marshall/skills/phase-6-finalize/standards/missing-step.md
loadable: false
message: "step `missing-step` referenced by `marshal.json` is missing standards file `marketplace/bundles/plan-marshall/skills/phase-6-finalize/standards/missing-step.md` — the plan likely deleted the file without sweeping `marshal.json`"
Output (bulk form): a results[N] table with one row per manifest step plus an unloadable_count summary, e.g.:
status: success
plan_id: EXAMPLE-PLAN
unloadable_count: 1
results[3]{step_id,standards_path,loadable,message}:
commit-push,marketplace/bundles/plan-marshall/skills/phase-6-finalize/standards/commit-push.md,true,
create-pr,marketplace/bundles/plan-marshall/skills/phase-6-finalize/workflow/create-pr.md,true,
ghost-step,marketplace/bundles/plan-marshall/skills/phase-6-finalize/standards/ghost-step.md,false,"step `ghost-step` referenced by `marshal.json` is missing standards file `…ghost-step.md` — the plan likely deleted the file without sweeping `marshal.json`"
The bulk form requires the manifest to exist on disk; if it does not, the script returns the standard file_not_found error.
Script: plan-marshall:manage-execution-manifest:manage-execution-manifest
| Command | Parameters | Description |
|---------|------------|-------------|
| compose | --plan-id --change-type --track --scope-estimate [--recipe-key] [--affected-files-count] [--phase-5-steps] [--phase-6-steps] | Compose and write execution.toon |
| read | --plan-id | Read manifest as TOON |
| record-step | --plan-id --step-id --phase {5-execute\|6-finalize} --outcome {executed\|skipped\|error} [--total-tokens] [--tool-uses] [--duration-ms] | Append a per-step execution-log row (outcome + token attribution) to execution.toon |
| validate | --plan-id [--phase-5-steps] [--phase-6-steps] | Validate manifest schema + step IDs |
| validate-loadable | --plan-id (--step-id ID \| --all) | Verify standards file presence for built-in phase_6.steps entries |
See manage-contract.md for the standard error response format.
| Error Code | Cause |
|------------|-------|
| invalid_plan_id | plan_id format invalid |
| file_not_found | execution.toon doesn't exist (read/validate) |
| invalid_change_type | --change-type not in the valid enum |
| invalid_scope_estimate | --scope-estimate not in the valid enum |
| invalid_track | --track not simple or complex |
| invalid_phase | record-step --phase not 5-execute or 6-finalize |
| invalid_outcome | record-step --outcome not executed, skipped, or error |
| invalid_manifest | Manifest schema invalid or step IDs unknown |
| invalid_arguments | validate-loadable invoked without exactly one of --step-id / --all |
The canonical argparse surface for manage-execution-manifest.py. The D4 plugin-doctor
analyzer (_analyze_manage_invocation.py) reads this section as source-of-truth for
markdown notation occurrences across the marketplace. Consuming skills xref this
section by name (e.g., "see manage-execution-manifest Canonical invocations →
compose") instead of restating the command inline.
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest compose \
--plan-id PLAN_ID \
--change-type {analysis|feature|enhancement|bug_fix|tech_debt|verification} \
--track {simple|complex} \
--scope-estimate {none|surgical|single_module|multi_module|broad} \
[--recipe-key KEY] [--affected-files-count N] \
[--phase-5-steps LIST] [--phase-6-steps LIST] \
[--commit-and-push {true|false}]
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest read \
--plan-id PLAN_ID
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest record-step \
--plan-id PLAN_ID \
--step-id STEP_ID \
--phase {5-execute|6-finalize} \
--outcome {executed|skipped|error} \
[--total-tokens N] [--tool-uses N] [--duration-ms N]
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest validate \
--plan-id PLAN_ID \
[--phase-5-steps LIST] [--phase-6-steps LIST]
python3 .plan/execute-script.py plan-marshall:manage-execution-manifest:manage-execution-manifest validate-loadable \
--plan-id PLAN_ID \
(--step-id STEP_ID | --all)
--step-id and --all are mutually exclusive; exactly one is required.
The seven-row decision matrix is documented in standards/decision-rules.md. The matrix maps the inputs (change_type, track, scope_estimate, recipe_key, affected_files_count) to:
phase_5.early_terminate (true/false)phase_5.verification_steps chosen from the candidate setphase_6.steps chosen from the candidate setFor each rule fired, compose emits one decision.log entry — written in-process via plan_logging.log_entry (NOT by shelling back out to the executor) — with the canonical prefix (plan-marshall:manage-execution-manifest:compose) and the rule name. The in-process write resolves the plan dir the same way the manifest write does, so the line always lands in the plan's own logs/decision.log; the prior executor-subprocess path silently dropped every line because the composer runs from the plugin cache, outside the project tree where .plan/execute-script.py lives. This satisfies the request example "one entry per decision".
scope_gated_finalize)Before the seven-row matrix and the bot-enforcement guard, the composer applies a scope-gated pre-filter that drops heavyweight phase-6 review/audit steps based on scope_estimate:
surgical — drops plan-marshall:plan-retrospective, project:finalize-step-pre-submission-self-review, and project:finalize-step-plugin-doctor (both bare and prefixed forms are matched).single_module — drops only plan-marshall:plan-retrospective.multi_module / broad / none — no implicit subtraction; the full candidate set is retained.automated-review is NEVER dropped by the implicit scope gate: the bot-enforcement guard re-adds it on GitHub/GitLab plans, so an implicit drop would be a silently-undone no-op. The only path that suppresses automated-review is the explicit drop_review_on_scope_gate escape hatch.
drop_review_on_scope_gate — read from marshal.json at plan.phase-6-finalize.drop_review_on_scope_gate (default false). When true and the plan is itself scope-gated (scope_estimate ∈ {surgical, single_module}), the scope gate additionally drops automated-review — the single deliberate path that suppresses the bot-review gate, explicitly opted into. The override is scoped, not global: on multi_module / broad / none plans it is inert, so flipping the project-wide knob can never silently disable bot review on a large plan. The default keeps the bot-review invariant intact.
The composer emits one decision.log line per scope-gated subtraction (canonical prefix (plan-marshall:manage-execution-manifest:compose) scope_gated_finalize subtraction) and surfaces scope_gated_finalize_dropped and drop_review_on_scope_gate in the compose result for observability.
ceremony_finalize_selection)After the seven-row matrix produces the final phase_6.steps (and after execution_tier routing), and before the bot-enforcement guard, the composer applies the four plan.phase-6-finalize run-at-all gates — each always|never|auto — to force their finalize steps in or out:
| Gate | Finalize step | never → drop · always → force-include · auto → defer |
|------|---------------|------------------------------------------------------------|
| self_review | finalize-step-pre-submission-self-review | force the pre-submission structural + cognitive self-review |
| qgate | pre-push-quality-gate | force the finalize blocking-findings re-capture |
| plugin_doctor | finalize-step-plugin-doctor | force the structural marketplace lint before push |
| simplify | finalize-step-simplify | force the holistic post-implementation simplification sweep |
always is the only path that re-adds a step the scope_gated_finalize pre-filter dropped — an operator-set always overrides the implicit scope gate. Gate values are read directly from the flat phase-local knobs marshal.json::plan.phase-6-finalize.<gate>. The transform NEVER touches automated-review, so the bot-review invariant (bot_enforcement_guard) is preserved verbatim regardless of any gate value.
The composer emits one decision.log line per forced change (canonical prefix (plan-marshall:manage-execution-manifest:compose) ceremony_finalize selection) and surfaces ceremony_finalize_gates, ceremony_finalize_forced_in, and ceremony_finalize_forced_out in the compose result for observability. The full rule (gate→step map, automated-review carve-out, post-matrix-transform rationale) is documented in standards/decision-rules.md § "plan.phase-6-finalize Selection". The gate schema itself (run-at-all enum, defaults) is owned by manage-config/standards/data-model.md § phase-6-finalize.
| Client | Operation | Purpose |
|--------|-----------|---------|
| phase-4-plan | compose | Emit manifest as terminal step before phase transition (Step 8b) |
| phase-5-execute | record-step | Append a per-step execution-log row (outcome + token attribution) after each verification step dispatches |
| phase-6-finalize | record-step | Append a per-step execution-log row (outcome + token attribution) after each finalize step dispatches |
| Client | Operation | Purpose |
|--------|-----------|---------|
| phase-5-execute | read | Read phase_5.early_terminate and phase_5.verification_steps to drive verification dispatch |
| phase-6-finalize | read | Read phase_6.steps to drive finalize-step dispatch loop |
| plan-retrospective | read | Cross-check manifest assumptions against end-of-execute diff |
manage-references — Plan-scoped references including affected_files and scope_estimate consumed by the composermanage-logging — Decision-log target for the per-rule reasoning entries emitted by composemanage-config — Source of marshal.json candidate Phase 5/6 step listsdevelopment
The single append-only change-ledger — one worktree_sha-stamped substrate for kind=build and kind=change entries — plus the first-class worktree-sha freshness API
development
Authoring standards for ASCII box diagrams in skill and doc source — box-drawing conventions, right-border alignment, and a deterministic check/fix validator over fenced/literal code blocks in .md and .adoc files
testing
Recipe for verifying and fixing alignment of ASCII box diagrams across .md skill source and .adoc documentation, one deliverable per offending file
development
Pure platform-agnostic terminal-title composition consumed by platform-runtime via PYTHONPATH