skills/claude/workflow-state/SKILL.md
Checkpoint and resume workflow state for context persistence across sessions. Use when the user says 'save progress', 'checkpoint', 'I need to stop', or runs /checkpoint or /rehydrate. Saves current workflow phase, task progress, and artifacts for later resumption. Do NOT use for workflow initialization (handled by ideate/debug/refactor commands).
npx skillsauth add lvlup-sw/exarchos workflow-stateInstall 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.
Manage persistent workflow state that survives context auto-summarization.
State files store: task details, worktree locations, PR URLs, and review status.
Activate this skill when:
/exarchos:ideate)/exarchos:rehydrate <featureId>)/exarchos:checkpoint)Valid transitions, guards, and prerequisites for all workflow types are documented in references/phase-transitions.md. CRITICAL: Phase mutation is a separate action from field mutation. When a transition has a guard, action: "update" the prerequisite fields first, then action: "transition" — guards read the most recent state, so updates land before guards evaluate. Attempting to mutate phase via action: "update" returns a RESERVED_FIELD error pointing at transition (see "Reserved fields" below).
Use exarchos_workflow({ action: "describe", actions: ["update", "init", "get"] }) for
parameter schemas and exarchos_workflow({ action: "describe", playbook: "feature" })
for phase transitions, guards, and playbook guidance. For the lightweight
oneshot variant (with its implementing → synthesize|completed choice state
driven by synthesisPolicy), call exarchos_workflow({ action: "describe", playbook: "oneshot" })
— oneshot is a first-class playbook alongside feature/debug/refactor. Use
exarchos_event({ action: "describe", eventTypes: ["workflow.transition", "task.completed"] })
for event data schemas.
Workflow state lives in the MCP event store, not the filesystem. Use exarchos_workflow get to read state and exarchos_view pipeline to discover active workflows. Do not scan ~/.claude/workflow-state/*.state.json — that path is legacy and may be stale or empty.
For full MCP tool signatures, error handling, and anti-patterns, see references/mcp-tool-reference.md.
At the start of /exarchos:ideate, use mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "init" with:
featureId: the workflow identifier (e.g., "user-authentication")workflowType: one of "feature", "debug", "refactor", "oneshot"synthesisPolicy (optional, oneshot only): one of "always", "never", "on-request" (default "on-request") — silently ignored for non-oneshot typesThis creates a new workflow state entry. The initial phase depends on
workflowType:
feature → starts in ideatedebug → starts in triagerefactor → starts in exploreoneshot → starts in plan (skips ideate entirely)feature — full ideate → plan → delegate → review → synthesize for real features with subagent dispatch and two-stage reviewdebug — triage → investigate → (thorough | hotfix) for bug workflows with track selectionrefactor — explore → brief → (polish | overhaul) for code improvements, polish for small and overhaul for multi-taskoneshot — plan → implementing → (completed | synthesize) for trivial changes; direct-commit by default with an opt-in PR path resolved via a choice-state guard driven by synthesisPolicy and the synthesize.requested eventSee @skills/oneshot-workflow/SKILL.md for the lightweight variant's full prose, including the choice-state mechanics and finalize_oneshot trigger.
Use mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "get" and featureId:
featureIdquery for dot-path lookup (e.g., query: "phase", query: "tasks")fields array for projection (e.g., fields: ["phase", "featureId", "tasks"])Field projection via fields returns only the requested top-level keys, reducing token cost.
Use mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "update" with featureId and updates. This action mutates non-phase fields only — phase, workflowType, featureId, createdAt, and version are reserved (see "Reserved fields" below).
updates: { "artifacts.design": "docs/designs/2026-01-05-feature.md" }updates: { "tasks[0].status": "complete", "tasks[0].completedAt": "<timestamp>" }updates: { "worktrees.wt-001": { "branch": "feature/001-types", "taskId": "001", "status": "active" } }Worktree status values: 'active' | 'merged' | 'removed'
Use mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "transition" with featureId and target:
target: "delegate"Transitions are HSM-validated and emit a workflow.transition event. Guarded transitions read state after the most recent update, so any updates: {...} that the guard depends on must land first.
tasks arrayThe dot-path parser used by set updates recognizes only numeric array brackets (tasks[0], tasks[1], …). Keyed forms like tasks[id=T-001] are NOT supported and now throw an INVALID_INPUT error with a clear message — earlier versions silently wrote to a bogus top-level key, returning success: true while the actual task was untouched. Three patterns are supported:
Replace the whole array (use this when the plan is being revised wholesale; matches the issue #1003 contract):
exarchos_workflow({
action: "update",
featureId: "<id>",
updates: { tasks: [
{ id: "T-001", title: "...", status: "pending" },
{ id: "T-002", title: "...", status: "pending" },
]},
})
Edit one task by its array index:
exarchos_workflow({
action: "update",
featureId: "<id>",
updates: { "tasks[0].status": "complete", "tasks[0].completedAt": "<ts>" },
})
First read tasks (action: "get", query: "tasks") to find the index of the task you want to edit, then set by that index.
Append a new task by writing to the next-free index. If the array currently has length N, write to tasks[N]:
// Suppose tasks already contains T-001 and T-002 (length 2). To append:
exarchos_workflow({
action: "update",
featureId: "<id>",
updates: { "tasks[2]": { id: "T-003", title: "Follow-up", status: "pending" } },
})
The parser allows writing one slot past the current length (MAX_ARRAY_GAP = 1); writing further out (tasks[5] against a length-2 array) throws INVALID_INPUT. Read the current tasks length before appending.
For context restoration after summarization, use mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "get" and featureId. This outputs a minimal summary suitable for rebuilding orchestrator context.
To verify state matches git reality, run /exarchos:rehydrate <featureId> — the rehydration projection folds events newer than the last snapshot and surfaces drift in the returned envelope. For deeper manual verification, run the reconciliation script:
exarchos_orchestrate({
action: "reconcile_state",
stateFile: "<state-file>",
repoRoot: "<repo-root>"
})
On passed: true: State is consistent.
On passed: false: Discrepancies found — review output and resolve.
| Event | State Update |
|-------|--------------|
| /exarchos:ideate starts | Create state file |
| Design saved | update: { "artifacts.design": "<path>" }, then transition target: "plan" |
| Plan saved | update: { "artifacts.plan": "<path>", "tasks": [...] }, then transition target: "plan-review" |
| Plan-review gaps found | update: { "planReview.gaps": [...] }, auto-loop to plan |
| Plan-review approved | update: { "planReview.approved": true }, then transition target: "delegate" |
| Task dispatched | Set task status = "in_progress", startedAt |
| Task complete | Set task status = "complete", completedAt |
| Worktree created | Add to worktrees object |
| Review complete | Update reviews object |
| PR created | Set artifacts.pr, synthesis.prUrl |
| PR feedback | Append to synthesis.prFeedback |
Oneshot is a first-class workflow type with a compressed lifecycle and an opt-in PR path. The rows below mirror the feature-workflow table above.
| Phase | State updates | Events emitted |
|-------|---------------|----------------|
| plan (oneshot) | oneshot.planSummary, artifacts.plan, optional oneshot.synthesisPolicy | workflow.transition |
| implementing (oneshot) | tasks[].status, artifacts.tests | task.*, optional synthesize.requested (via request_synthesize) |
| synthesize (oneshot) | synthesis.prUrl, artifacts.pr | workflow.transition, stack.submitted |
| completed (oneshot) | — | workflow.transition (to completed) |
The implementing → synthesize | completed fork is a choice state resolved
by finalize_oneshot, which reads the synthesisOptedIn guard
(synthesisPolicy + synthesize.requested events). See
@skills/oneshot-workflow/SKILL.md for the full opt-in mechanics.
Skills should update state at key moments:
brainstorming/SKILL.md:
After saving design:
1. `action: "update"` — `updates: { "artifacts.design": "<path>" }`
2. `action: "transition"` — `target: "plan"`
implementation-planning/SKILL.md:
After saving plan:
1. `action: "update"` — `updates: { "artifacts.plan": "<path>", "tasks": [...] }`
2. `action: "transition"` — `target: "plan-review"`
delegation/SKILL.md:
On task dispatch:
- Update task status to "in_progress"
- Add worktree to state if created
On task complete:
- Update task status to "complete"
- Check if all tasks done, suggest checkpoint
See docs/schemas/workflow-state.schema.json for full schema.
Key sections:
version: Schema version (currently "1.1")featureId: Unique workflow identifierworkflowType: Required. One of "feature", "debug", "refactor", or "oneshot"phase: Current workflow phaseartifacts: Paths to design, plan, PRtasks: Task list with statusworktrees: Active git worktreesplanReview: Plan-review delta analysis results (gaps, approved)reviews: Review resultssynthesis: Merge/PR statemcp__plugin_exarchos_exarchos__exarchos_workflow with action: "update" rejects two classes of paths with RESERVED_FIELD:
phase, workflowType, featureId, createdAt, version. Set once at init; never mutated directly._ (e.g. _version, _checkpoint.summary, _eventHints). These are projection or event-store metadata.Alternate write paths:
phase → mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "transition" and target: "<phase>". Transitions are HSM-validated and emit transition events.mcp__plugin_exarchos_exarchos__exarchos_event with action: "append" (e.g. checkpoint, state.patched). The projection folds the event into the field on the next read.workflowType, featureId, createdAt, version → not migratable. If you need a different workflow type, init a new workflow.A RESERVED_FIELD error envelope now carries a typed data block:
{
"success": false,
"error": {
"code": "RESERVED_FIELD",
"message": "Cannot update reserved field: phase",
"data": {
"rejectedPath": "phase",
"rule": "`phase` is top-level immutable — set once at init, never directly mutated thereafter.",
"alternateWritePath": "Use `mcp__plugin_exarchos_exarchos__exarchos_workflow` with `action: \"transition\"` and `target: \"<phase>\"` — phase changes are HSM-validated and emit transition events."
}
}
}
Read the full descriptor — including the regex catch-all for underscore paths — via mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "describe" and actions: ["update"]. The returned reservedFields block is the single source of truth.
If an Exarchos MCP tool returns an error:
mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "get" and the featureIdmcp__plugin_exarchos_exarchos__exarchos_workflow with action: "cancel" and dryRun: trueIf workflow state doesn't match git reality:
/exarchos:rehydrate <featureId> — the rehydration projection folds in events newer than the last snapshotworkflowState / artifacts with git log and branch statemcp__plugin_exarchos_exarchos__exarchos_workflow with action: "update" to match git truthIf /exarchos:checkpoint is invoked with no active workflow:
mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "list" to enumerate active workflows; if the list is empty the checkpoint command's "no active workflow" report is correct — exit cleanlylist returns a candidate, verify it: call mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "get" and that featureIdIf state references branches or worktrees that no longer exist:
/exarchos:rehydrate <featureId> — the rehydration document surfaces stale referencesgit branch -a / git worktree list to identify driftexarchos_workflow update to match git truthIf multiple workflow state files exist:
mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "cancel" and dryRun: true on stale workflows to preview cleanupStart new workflow: Use mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "init" with featureId: "user-authentication", workflowType: "feature"
After design phase: First persist the artifact, then advance the phase.
action: "update", featureId: "user-authentication", updates: { "artifacts.design": "docs/designs/2026-01-05-user-auth.md" }action: "transition", featureId: "user-authentication", target: "plan"Check state: Use mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "get" with featureId: "user-authentication"
Resume after context loss: Use mcp__plugin_exarchos_exarchos__exarchos_workflow with action: "get" with featureId: "user-authentication" to get context restoration output
tools
Land a subagent worktree branch onto an integration branch with preflight + recorded rollback. Triggers: operator (or `next_actions`) surfaces verb `merge_orchestrate` via Exarchos MCP. Local git operation — NOT remote PR merging (that is `merge_pr`).
tools
Land a subagent worktree branch onto an integration branch with preflight + recorded rollback. Triggers: operator (or `next_actions`) surfaces verb `merge_orchestrate` via Exarchos MCP. Local git operation — NOT remote PR merging (that is `merge_pr`).
tools
Land a subagent worktree branch onto an integration branch with preflight + recorded rollback. Triggers: operator (or `next_actions`) surfaces verb `merge_orchestrate` via Exarchos MCP. Local git operation — NOT remote PR merging (that is `merge_pr`).
tools
Land a subagent worktree branch onto an integration branch with preflight + recorded rollback. Triggers: operator (or `next_actions`) surfaces verb `merge_orchestrate` via Exarchos MCP. Local git operation — NOT remote PR merging (that is `merge_pr`).