mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-18 18:48:48 +08:00
feat: add MCP server for semantic code search with FastMCP integration
This commit is contained in:
153
.claude/skills/wf-composer/SKILL.md
Normal file
153
.claude/skills/wf-composer/SKILL.md
Normal file
@@ -0,0 +1,153 @@
|
||||
---
|
||||
name: wf-composer
|
||||
description: Semantic workflow composer — parse natural language workflow description into a DAG of skill/CLI/agent nodes, auto-inject checkpoint save nodes, confirm with user, persist as reusable JSON template. Triggers on "wf-composer " or "/wf-composer".
|
||||
argument-hint: "[workflow description]"
|
||||
allowed-tools: Agent(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
|
||||
---
|
||||
|
||||
# Workflow Design
|
||||
|
||||
Parse user's semantic workflow description → decompose into nodes → map to executors → auto-inject checkpoints → confirm pipeline → save as reusable `workflow-template.json`.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
User describes workflow in natural language
|
||||
-> Phase 1: Parse — extract intent steps + variables
|
||||
-> Phase 2: Resolve — map each step to executor (skill/cli/agent/command)
|
||||
-> Phase 3: Enrich — inject checkpoint nodes, set DAG edges
|
||||
-> Phase 4: Confirm — visualize pipeline, user approval/edit
|
||||
-> Phase 5: Persist — save .workflow/templates/<name>.json
|
||||
```
|
||||
|
||||
## Shared Constants
|
||||
|
||||
| Constant | Value |
|
||||
|----------|-------|
|
||||
| Session prefix | `WFD` |
|
||||
| Template dir | `.workflow/templates/` |
|
||||
| Template ID format | `wft-<slug>-<date>` |
|
||||
| Node ID format | `N-<seq>` (e.g. N-001), `CP-<seq>` for checkpoints |
|
||||
| Max nodes | 20 |
|
||||
|
||||
## Entry Router
|
||||
|
||||
Parse `$ARGUMENTS`.
|
||||
|
||||
| Detection | Condition | Handler |
|
||||
|-----------|-----------|---------|
|
||||
| Resume design | `--resume` flag or existing WFD session | -> Phase 0: Resume |
|
||||
| Edit template | `--edit <template-id>` flag | -> Phase 0: Load + Edit |
|
||||
| New design | Default | -> Phase 1: Parse |
|
||||
|
||||
## Phase 0: Resume / Edit (optional)
|
||||
|
||||
**Resume design session**:
|
||||
1. Scan `.workflow/templates/design-drafts/WFD-*.json` for in-progress designs
|
||||
2. Multiple found → AskUserQuestion for selection
|
||||
3. Load draft → skip to last incomplete phase
|
||||
|
||||
**Edit existing template**:
|
||||
1. Load template from `--edit` path
|
||||
2. Show current pipeline visualization
|
||||
3. AskUserQuestion: which nodes to modify/add/remove
|
||||
4. Re-enter at Phase 3 (Enrich) with edits applied
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Parse
|
||||
|
||||
Read `phases/01-parse.md` and execute.
|
||||
|
||||
**Objective**: Extract structured semantic steps + context variables from natural language.
|
||||
|
||||
**Success**: `design-session/intent.json` written with: steps[], variables[], task_type, complexity.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Resolve
|
||||
|
||||
Read `phases/02-resolve.md` and execute.
|
||||
|
||||
**Objective**: Map each intent step to a concrete executor node.
|
||||
|
||||
**Executor types**:
|
||||
- `skill` — invoke via `Skill(skill=..., args=...)`
|
||||
- `cli` — invoke via `ccw cli -p "..." --tool ... --mode ...`
|
||||
- `command` — invoke via `Skill(skill="<namespace:command>", args=...)`
|
||||
- `agent` — invoke via `Agent(subagent_type=..., prompt=...)`
|
||||
- `checkpoint` — state save + optional user pause
|
||||
|
||||
**Success**: `design-session/nodes.json` written with resolved executor for each step.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Enrich
|
||||
|
||||
Read `phases/03-enrich.md` and execute.
|
||||
|
||||
**Objective**: Build DAG edges, auto-inject checkpoints at phase boundaries, validate port compatibility.
|
||||
|
||||
**Checkpoint injection rules**:
|
||||
- After every `skill` → `skill` transition that crosses a semantic phase boundary
|
||||
- Before any long-running `agent` spawn
|
||||
- After any node that produces a persistent artifact (plan, spec, analysis)
|
||||
- At user-defined breakpoints (if any)
|
||||
|
||||
**Success**: `design-session/dag.json` with nodes[], edges[], checkpoints[], context_schema{}.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Confirm
|
||||
|
||||
Read `phases/04-confirm.md` and execute.
|
||||
|
||||
**Objective**: Visualize the pipeline, present to user, incorporate edits.
|
||||
|
||||
**Display format**:
|
||||
```
|
||||
Pipeline: <template-name>
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
N-001 [skill] workflow-lite-plan "{goal}"
|
||||
|
|
||||
CP-01 [checkpoint] After Plan auto-continue
|
||||
|
|
||||
N-002 [skill] workflow-test-fix "--session N-001"
|
||||
|
|
||||
CP-02 [checkpoint] After Tests pause-for-user
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Variables: goal (required)
|
||||
Checkpoints: 2 (1 auto, 1 pause)
|
||||
```
|
||||
|
||||
AskUserQuestion:
|
||||
- Confirm & Save
|
||||
- Edit node (select node ID)
|
||||
- Add node after (select position)
|
||||
- Remove node (select node ID)
|
||||
- Rename template
|
||||
|
||||
**Success**: User confirmed pipeline. Final dag.json ready.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Persist
|
||||
|
||||
Read `phases/05-persist.md` and execute.
|
||||
|
||||
**Objective**: Assemble final template JSON, write to template library, output summary.
|
||||
|
||||
**Output**:
|
||||
- `.workflow/templates/<slug>.json` — the reusable template
|
||||
- Console summary with template path + usage command
|
||||
|
||||
**Success**: Template saved. User shown: `Skill(skill="wf-player", args="<template-path>")`
|
||||
|
||||
---
|
||||
|
||||
## Specs Reference
|
||||
|
||||
| Spec | Purpose |
|
||||
|------|---------|
|
||||
| [specs/node-catalog.md](specs/node-catalog.md) | Available executors, port definitions, arg templates |
|
||||
| [specs/template-schema.md](specs/template-schema.md) | Full JSON template schema |
|
||||
93
.claude/skills/wf-composer/phases/01-parse.md
Normal file
93
.claude/skills/wf-composer/phases/01-parse.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Phase 1: Parse — Semantic Intent Extraction
|
||||
|
||||
## Objective
|
||||
|
||||
Extract structured semantic steps and context variables from the user's natural language workflow description.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1.1 — Read Input
|
||||
|
||||
Parse `$ARGUMENTS` as the workflow description. If empty or ambiguous, AskUserQuestion:
|
||||
- "Describe the workflow you want to automate. Include: what steps to run, in what order, and what varies each time (inputs)."
|
||||
|
||||
### Step 1.2 — Extract Steps
|
||||
|
||||
Scan the description for sequential actions. Each action becomes a candidate node.
|
||||
|
||||
**Signal patterns** (not exhaustive — apply NL understanding):
|
||||
|
||||
| Signal | Candidate Node Type |
|
||||
|--------|---------------------|
|
||||
| "analyze", "review", "explore" | analysis step (cli --mode analysis) |
|
||||
| "plan", "design", "spec" | planning step (skill: workflow-lite-plan / workflow-plan) |
|
||||
| "implement", "build", "code", "fix", "refactor" | execution step (skill: workflow-execute) |
|
||||
| "test", "validate", "verify" | testing step (skill: workflow-test-fix) |
|
||||
| "brainstorm", "ideate" | brainstorm step (skill: brainstorm / brainstorm-with-file) |
|
||||
| "review code", "code review" | review step (skill: review-cycle) |
|
||||
| "save", "checkpoint", "pause" | explicit checkpoint node |
|
||||
| "spawn agent", "delegate", "subagent" | agent node |
|
||||
| "then", "next", "after", "finally" | sequential edge signal |
|
||||
| "parallel", "simultaneously", "at the same time" | parallel edge signal |
|
||||
|
||||
### Step 1.3 — Extract Variables
|
||||
|
||||
Identify inputs that vary per run. These become `context_schema` entries.
|
||||
|
||||
**Variable detection**:
|
||||
- Direct mentions: "the goal", "the target", "my task", "user-provided X"
|
||||
- Parameterized slots: `{goal}`, `[feature]`, `<scope>` patterns in the description
|
||||
- Implicit from task type: any "feature/bugfix/topic" is `goal`
|
||||
|
||||
For each variable: assign name, type (string|path|boolean), required flag, description.
|
||||
|
||||
### Step 1.4 — Detect Task Type
|
||||
|
||||
Use ccw-coordinator task detection logic to classify the overall workflow:
|
||||
|
||||
```
|
||||
bugfix | feature | tdd | review | brainstorm | spec-driven | roadmap |
|
||||
refactor | integration-test | greenfield | quick-task | custom
|
||||
```
|
||||
|
||||
`custom` = user describes a non-standard combination.
|
||||
|
||||
### Step 1.5 — Complexity Assessment
|
||||
|
||||
Count nodes, detect parallel tracks, identify dependencies:
|
||||
- `simple` = 1-3 nodes, linear
|
||||
- `medium` = 4-7 nodes, at most 1 parallel track
|
||||
- `complex` = 8+ nodes or multiple parallel tracks
|
||||
|
||||
### Step 1.6 — Write Output
|
||||
|
||||
Create session dir: `.workflow/templates/design-drafts/WFD-<slug>-<date>/`
|
||||
|
||||
Write `intent.json`:
|
||||
```json
|
||||
{
|
||||
"session_id": "WFD-<slug>-<date>",
|
||||
"raw_description": "<original user input>",
|
||||
"task_type": "<detected type>",
|
||||
"complexity": "simple|medium|complex",
|
||||
"steps": [
|
||||
{
|
||||
"seq": 1,
|
||||
"description": "<extracted step description>",
|
||||
"type_hint": "analysis|planning|execution|testing|review|checkpoint|agent|cli",
|
||||
"parallel_with": null,
|
||||
"variables": ["goal"]
|
||||
}
|
||||
],
|
||||
"variables": {
|
||||
"goal": { "type": "string", "required": true, "description": "<inferred description>" }
|
||||
},
|
||||
"created_at": "<ISO timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- `intent.json` exists with at least 1 step
|
||||
- All referenced variables extracted to `variables` map
|
||||
- task_type and complexity assigned
|
||||
89
.claude/skills/wf-composer/phases/02-resolve.md
Normal file
89
.claude/skills/wf-composer/phases/02-resolve.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Phase 2: Resolve — Map Steps to Executor Nodes
|
||||
|
||||
## Objective
|
||||
|
||||
Map each intent step from `intent.json` into a concrete executor node with assigned type, executor, and arg template.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 2.1 — Load Intent
|
||||
|
||||
Read `design-session/intent.json`. Load steps[], variables{}.
|
||||
|
||||
### Step 2.2 — Map Each Step to Executor
|
||||
|
||||
For each step, determine the executor node using the Node Catalog (`specs/node-catalog.md`).
|
||||
|
||||
**Resolution algorithm**:
|
||||
1. Match `type_hint` to executor candidates in catalog
|
||||
2. If multiple candidates, select by semantic fit to step description
|
||||
3. If no catalog match, emit `cli` node with inferred `--rule` and `--mode`
|
||||
|
||||
**Node type assignment**:
|
||||
|
||||
| Step type_hint | Default executor type | Default executor |
|
||||
|----------------|----------------------|------------------|
|
||||
| `planning` | skill | `workflow-lite-plan` (simple/medium) or `workflow-plan` (complex) |
|
||||
| `execution` | skill | `workflow-execute` |
|
||||
| `testing` | skill | `workflow-test-fix` |
|
||||
| `review` | skill | `review-cycle` |
|
||||
| `brainstorm` | skill | `brainstorm` |
|
||||
| `analysis` | cli | `ccw cli --tool gemini --mode analysis` |
|
||||
| `spec` | skill | `spec-generator` |
|
||||
| `tdd` | skill | `workflow-tdd-plan` |
|
||||
| `refactor` | command | `workflow:refactor-cycle` |
|
||||
| `integration-test` | command | `workflow:integration-test-cycle` |
|
||||
| `agent` | agent | (infer subagent_type from description) |
|
||||
| `checkpoint` | checkpoint | — |
|
||||
|
||||
### Step 2.3 — Build Arg Templates
|
||||
|
||||
For each node, build `args_template` by substituting variable references:
|
||||
|
||||
```
|
||||
skill node: args_template = `{goal}` (or `--session {prev_session}`)
|
||||
cli node: args_template = `PURPOSE: {goal}\nTASK: ...\nMODE: analysis\nCONTEXT: @**/*`
|
||||
agent node: args_template = `{goal}\nContext: {prev_output}`
|
||||
```
|
||||
|
||||
**Context injection rules**:
|
||||
- Planning nodes that follow analysis: inject `--context {prev_output_path}`
|
||||
- Execution nodes that follow planning: inject `--resume-session {prev_session_id}`
|
||||
- Testing nodes that follow execution: inject `--session {prev_session_id}`
|
||||
|
||||
Use `{prev_session_id}` and `{prev_output_path}` as runtime-resolved references — the executor will substitute these from node state at run time.
|
||||
|
||||
### Step 2.4 — Assign Parallel Groups
|
||||
|
||||
For steps with `parallel_with` set:
|
||||
- Assign same `parallel_group` string to both nodes
|
||||
- Parallel nodes share no data dependency (each gets same input)
|
||||
|
||||
### Step 2.5 — Write Output
|
||||
|
||||
Write `design-session/nodes.json`:
|
||||
```json
|
||||
{
|
||||
"session_id": "<WFD-id>",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "N-001",
|
||||
"seq": 1,
|
||||
"name": "<step description shortened>",
|
||||
"type": "skill|cli|command|agent|checkpoint",
|
||||
"executor": "<skill name | cli command | agent subagent_type>",
|
||||
"args_template": "<template string with {variable} placeholders>",
|
||||
"input_ports": ["<port>"],
|
||||
"output_ports": ["<port>"],
|
||||
"parallel_group": null,
|
||||
"on_fail": "abort"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- Every intent step has a corresponding node in nodes.json
|
||||
- Every node has a non-empty executor and args_template
|
||||
- Parallel groups correctly assigned where step.parallel_with is set
|
||||
104
.claude/skills/wf-composer/phases/03-enrich.md
Normal file
104
.claude/skills/wf-composer/phases/03-enrich.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Phase 3: Enrich — Inject Checkpoints + Build DAG
|
||||
|
||||
## Objective
|
||||
|
||||
Build the directed acyclic graph (DAG) with proper edges, auto-inject checkpoint nodes at phase boundaries, and finalize the context_schema.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 3.1 — Load Nodes
|
||||
|
||||
Read `design-session/nodes.json`. Get nodes[] list.
|
||||
|
||||
### Step 3.2 — Build Sequential Edges
|
||||
|
||||
Start with a linear chain: N-001 → N-002 → N-003 → ...
|
||||
|
||||
For nodes with the same `parallel_group`:
|
||||
- Remove edges between them
|
||||
- Add fan-out from the last non-parallel node to all group members
|
||||
- Add fan-in from all group members to the next non-parallel node
|
||||
|
||||
### Step 3.3 — Auto-Inject Checkpoint Nodes
|
||||
|
||||
Scan the edge list and inject a `checkpoint` node between edges that cross a phase boundary.
|
||||
|
||||
**Phase boundary detection rules** (inject checkpoint if ANY rule triggers):
|
||||
|
||||
| Rule | Condition |
|
||||
|------|-----------|
|
||||
| **Artifact boundary** | Source node has output_ports containing `plan`, `spec`, `analysis`, `review-findings` |
|
||||
| **Execution gate** | Target node type is `skill` with executor containing `execute` |
|
||||
| **Agent spawn** | Target node type is `agent` |
|
||||
| **Long-running** | Target node executor is `workflow-plan`, `spec-generator`, `collaborative-plan-with-file` |
|
||||
| **User-defined** | Intent step had `type_hint: checkpoint` |
|
||||
| **Post-testing** | Source node executor contains `test-fix` or `integration-test` |
|
||||
|
||||
**Checkpoint node template**:
|
||||
```json
|
||||
{
|
||||
"id": "CP-<seq>",
|
||||
"name": "Checkpoint: <description>",
|
||||
"type": "checkpoint",
|
||||
"description": "<what was just completed>",
|
||||
"auto_continue": true,
|
||||
"save_fields": ["session_id", "artifacts", "output_path"]
|
||||
}
|
||||
```
|
||||
|
||||
Set `auto_continue: false` for checkpoints that:
|
||||
- Precede a user-facing deliverable (spec, plan, review report)
|
||||
- Are explicitly requested by the user ("pause and show me")
|
||||
|
||||
### Step 3.4 — Insert Checkpoint Edges
|
||||
|
||||
For each injected checkpoint CP-X between edge (A → B):
|
||||
- Remove edge A → B
|
||||
- Add edges: A → CP-X, CP-X → B
|
||||
|
||||
### Step 3.5 — Finalize context_schema
|
||||
|
||||
Aggregate all `{variable}` references found in nodes' args_template strings.
|
||||
|
||||
For each unique variable name found:
|
||||
- Look up from `intent.json#variables` if already defined
|
||||
- Otherwise infer: type=string, required=true, description="<variable name>"
|
||||
|
||||
Produce final `context_schema{}` map.
|
||||
|
||||
### Step 3.6 — Validate DAG
|
||||
|
||||
Check:
|
||||
- No cycles (topological sort must succeed)
|
||||
- No orphan nodes (every node reachable from start)
|
||||
- Every non-start node has at least one incoming edge
|
||||
- Every non-terminal node has at least one outgoing edge
|
||||
|
||||
On cycle detection: report error, ask user to resolve.
|
||||
|
||||
### Step 3.7 — Write Output
|
||||
|
||||
Write `design-session/dag.json`:
|
||||
```json
|
||||
{
|
||||
"session_id": "<WFD-id>",
|
||||
"nodes": [ /* all nodes including injected checkpoints */ ],
|
||||
"edges": [
|
||||
{ "from": "N-001", "to": "CP-01" },
|
||||
{ "from": "CP-01", "to": "N-002" }
|
||||
],
|
||||
"checkpoints": ["CP-01", "CP-02"],
|
||||
"parallel_groups": { "<group-name>": ["N-003", "N-004"] },
|
||||
"context_schema": {
|
||||
"goal": { "type": "string", "required": true, "description": "..." }
|
||||
},
|
||||
"topological_order": ["N-001", "CP-01", "N-002"]
|
||||
}
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- dag.json exists and is valid (no cycles)
|
||||
- At least one checkpoint exists (or user explicitly opted out)
|
||||
- context_schema contains all variables referenced in args_templates
|
||||
- topological_order covers all nodes
|
||||
97
.claude/skills/wf-composer/phases/04-confirm.md
Normal file
97
.claude/skills/wf-composer/phases/04-confirm.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Phase 4: Confirm — Visualize + User Approval
|
||||
|
||||
## Objective
|
||||
|
||||
Render the pipeline as an ASCII diagram, present to user for confirmation and optional edits.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 4.1 — Render Pipeline
|
||||
|
||||
Load `design-session/dag.json`. Render in topological order:
|
||||
|
||||
```
|
||||
Pipeline: <template-name>
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
N-001 [skill] workflow-lite-plan "{goal}"
|
||||
|
|
||||
CP-01 [checkpoint] After Plan auto-continue
|
||||
|
|
||||
N-002 [skill] workflow-execute --resume {N-001.session_id}
|
||||
|
|
||||
CP-02 [checkpoint] Before Review pause-for-user
|
||||
|
|
||||
N-003 [skill] review-cycle --session {N-002.session_id}
|
||||
|
|
||||
N-004 [skill] workflow-test-fix --session {N-002.session_id}
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Variables (required): goal
|
||||
Checkpoints: 2 (1 auto-continue, 1 pause-for-user)
|
||||
Nodes: 4 work + 2 checkpoints
|
||||
```
|
||||
|
||||
For parallel groups, show fan-out/fan-in:
|
||||
```
|
||||
N-003a [skill] review-cycle ─┐
|
||||
├─ N-004 [skill] workflow-test-fix
|
||||
N-003b [cli] gemini analysis ─┘
|
||||
```
|
||||
|
||||
### Step 4.2 — Ask User
|
||||
|
||||
```
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "Review the workflow pipeline above.",
|
||||
header: "Confirm Pipeline",
|
||||
options: [
|
||||
{ label: "Confirm & Save", description: "Save as reusable template" },
|
||||
{ label: "Edit a node", description: "Modify executor or args of a specific node" },
|
||||
{ label: "Add a node", description: "Insert a new step at a position" },
|
||||
{ label: "Remove a node", description: "Delete a step from the pipeline" },
|
||||
{ label: "Rename template", description: "Change the template name" },
|
||||
{ label: "Re-run checkpoint injection", description: "Reset and re-inject checkpoints" },
|
||||
{ label: "Cancel", description: "Discard and exit" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
```
|
||||
|
||||
### Step 4.3 — Handle Edit Actions
|
||||
|
||||
**Edit a node**:
|
||||
- AskUserQuestion: "Which node ID to edit?" → show fields → apply change
|
||||
- Re-render pipeline and re-ask
|
||||
|
||||
**Add a node**:
|
||||
- AskUserQuestion: "Insert after which node ID?" + "Describe the new step"
|
||||
- Re-run Phase 2 (resolve) for the new step description
|
||||
- Insert new node + update edges
|
||||
- Re-run Phase 3 (enrich) for checkpoint injection
|
||||
- Re-render and re-ask
|
||||
|
||||
**Remove a node**:
|
||||
- AskUserQuestion: "Which node ID to remove?"
|
||||
- If node is a checkpoint: also remove it, re-wire edges
|
||||
- If node is a work node: re-wire edges, re-run checkpoint injection
|
||||
- Re-render and re-ask
|
||||
|
||||
**Rename template**:
|
||||
- AskUserQuestion: "New template name?"
|
||||
- Update slug for template_id
|
||||
|
||||
### Step 4.4 — Finalize
|
||||
|
||||
On "Confirm & Save":
|
||||
- Freeze dag.json (mark as confirmed)
|
||||
- Proceed to Phase 5
|
||||
|
||||
On "Cancel":
|
||||
- Save draft to `design-session/dag-draft.json`
|
||||
- Output: "Draft saved. Resume with: Skill(skill='wf-composer', args='--resume <session-id>')"
|
||||
- Exit
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- User selected "Confirm & Save"
|
||||
- dag.json frozen with all user edits applied
|
||||
107
.claude/skills/wf-composer/phases/05-persist.md
Normal file
107
.claude/skills/wf-composer/phases/05-persist.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Phase 5: Persist — Assemble + Save Template
|
||||
|
||||
## Objective
|
||||
|
||||
Assemble the final workflow template JSON from design session data, write to template library, output usage instructions.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 5.1 — Load Design Session
|
||||
|
||||
Read:
|
||||
- `design-session/intent.json` → template metadata
|
||||
- `design-session/dag.json` → nodes, edges, checkpoints, context_schema
|
||||
|
||||
### Step 5.2 — Determine Template Name + Path
|
||||
|
||||
**Name**: Use user's confirmed name from Phase 4. If not set, derive from intent.task_type + first 3 meaningful words of raw_description.
|
||||
|
||||
**Slug**: kebab-case from name (e.g. "Feature TDD with Review" → "feature-tdd-with-review")
|
||||
|
||||
**Path**: `.workflow/templates/<slug>.json`
|
||||
|
||||
**template_id**: `wft-<slug>-<YYYYMMDD>`
|
||||
|
||||
Check for existing file:
|
||||
- If exists and different content: append `-v2`, `-v3`, etc.
|
||||
- If exists and identical: skip write, output "Template already exists"
|
||||
|
||||
### Step 5.3 — Assemble Template JSON
|
||||
|
||||
See `specs/template-schema.md` for full schema. Assemble:
|
||||
|
||||
```json
|
||||
{
|
||||
"template_id": "wft-<slug>-<date>",
|
||||
"name": "<human name>",
|
||||
"description": "<raw_description truncated to 120 chars>",
|
||||
"version": "1.0",
|
||||
"created_at": "<ISO timestamp>",
|
||||
"source_session": "<WFD-id>",
|
||||
"tags": ["<task_type>", "<complexity>"],
|
||||
"context_schema": { /* from dag.json */ },
|
||||
"nodes": [ /* from dag.json, full node objects */ ],
|
||||
"edges": [ /* from dag.json */ ],
|
||||
"checkpoints": [ /* checkpoint node IDs */ ],
|
||||
"atomic_groups": [ /* from intent.json parallel groups */ ],
|
||||
"execution_mode": "serial",
|
||||
"metadata": {
|
||||
"node_count": <n>,
|
||||
"checkpoint_count": <n>,
|
||||
"estimated_duration": "<rough estimate based on node types>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5.4 — Write Template
|
||||
|
||||
Write assembled JSON to `.workflow/templates/<slug>.json`.
|
||||
|
||||
Ensure `.workflow/templates/` directory exists (create if not).
|
||||
|
||||
### Step 5.5 — Update Template Index
|
||||
|
||||
Read/create `.workflow/templates/index.json`:
|
||||
```json
|
||||
{
|
||||
"templates": [
|
||||
{
|
||||
"template_id": "wft-<slug>-<date>",
|
||||
"name": "<name>",
|
||||
"path": ".workflow/templates/<slug>.json",
|
||||
"tags": ["<task_type>"],
|
||||
"created_at": "<ISO>",
|
||||
"node_count": <n>
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Append or update entry for this template. Write back.
|
||||
|
||||
### Step 5.6 — Output Summary
|
||||
|
||||
```
|
||||
Template saved: .workflow/templates/<slug>.json
|
||||
ID: wft-<slug>-<date>
|
||||
Nodes: <n> work nodes + <n> checkpoints
|
||||
Variables: <comma-separated required vars>
|
||||
|
||||
To execute:
|
||||
Skill(skill="wf-player", args="<slug> --context goal='<your goal>'")
|
||||
|
||||
To edit later:
|
||||
Skill(skill="wf-composer", args="--edit .workflow/templates/<slug>.json")
|
||||
|
||||
To list all templates:
|
||||
Skill(skill="wf-player", args="--list")
|
||||
```
|
||||
|
||||
### Step 5.7 — Clean Up Draft
|
||||
|
||||
Delete `design-session/` directory (or move to `.workflow/templates/design-drafts/archive/`).
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- `.workflow/templates/<slug>.json` exists and is valid JSON
|
||||
- `index.json` updated with new entry
|
||||
- Console shows template path + usage command
|
||||
96
.claude/skills/wf-composer/specs/node-catalog.md
Normal file
96
.claude/skills/wf-composer/specs/node-catalog.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Node Catalog — Available Executors
|
||||
|
||||
All executors available for node resolution in Phase 2.
|
||||
|
||||
## Skill Nodes
|
||||
|
||||
| Executor | Type | Input Ports | Output Ports | Typical Args Template |
|
||||
|----------|------|-------------|--------------|----------------------|
|
||||
| `workflow-lite-plan` | skill | requirement | plan | `"{goal}"` |
|
||||
| `workflow-plan` | skill | requirement, specification | detailed-plan | `"{goal}"` |
|
||||
| `workflow-execute` | skill | detailed-plan, verified-plan | code | `--resume-session {prev_session_id}` |
|
||||
| `workflow-test-fix` | skill | failing-tests, code | test-passed | `--session {prev_session_id}` |
|
||||
| `workflow-tdd-plan` | skill | requirement | tdd-tasks | `"{goal}"` |
|
||||
| `workflow-multi-cli-plan` | skill | requirement | multi-cli-plan | `"{goal}"` |
|
||||
| `review-cycle` | skill | code, session | review-findings | `--session {prev_session_id}` |
|
||||
| `brainstorm` | skill | exploration-topic | brainstorm-analysis | `"{goal}"` |
|
||||
| `spec-generator` | skill | requirement | specification | `"{goal}"` |
|
||||
|
||||
## Command Nodes (namespace skills)
|
||||
|
||||
| Executor | Type | Input Ports | Output Ports | Typical Args Template |
|
||||
|----------|------|-------------|--------------|----------------------|
|
||||
| `workflow:refactor-cycle` | command | codebase | refactored-code | `"{goal}"` |
|
||||
| `workflow:integration-test-cycle` | command | requirement | test-passed | `"{goal}"` |
|
||||
| `workflow:brainstorm-with-file` | command | exploration-topic | brainstorm-document | `"{goal}"` |
|
||||
| `workflow:analyze-with-file` | command | analysis-topic | discussion-document | `"{goal}"` |
|
||||
| `workflow:debug-with-file` | command | bug-report | understanding-document | `"{goal}"` |
|
||||
| `workflow:collaborative-plan-with-file` | command | requirement | plan-note | `"{goal}"` |
|
||||
| `workflow:roadmap-with-file` | command | requirement | execution-plan | `"{goal}"` |
|
||||
| `workflow:unified-execute-with-file` | command | plan-note, discussion-document | code | (no args — reads from session) |
|
||||
| `issue:discover` | command | codebase | pending-issues | (no args) |
|
||||
| `issue:plan` | command | pending-issues | issue-plans | `--all-pending` |
|
||||
| `issue:queue` | command | issue-plans | execution-queue | (no args) |
|
||||
| `issue:execute` | command | execution-queue | completed-issues | `--queue auto` |
|
||||
| `issue:convert-to-plan` | command | plan | converted-plan | `--latest-lite-plan` |
|
||||
| `team-planex` | skill | requirement, execution-plan | code | `"{goal}"` |
|
||||
|
||||
## CLI Nodes
|
||||
|
||||
CLI nodes use `ccw cli` with a tool + mode + rule.
|
||||
|
||||
| Use Case | cli_tool | cli_mode | cli_rule |
|
||||
|----------|----------|----------|----------|
|
||||
| Architecture analysis | gemini | analysis | analysis-review-architecture |
|
||||
| Code quality review | gemini | analysis | analysis-review-code-quality |
|
||||
| Bug root cause | gemini | analysis | analysis-diagnose-bug-root-cause |
|
||||
| Security assessment | gemini | analysis | analysis-assess-security-risks |
|
||||
| Performance analysis | gemini | analysis | analysis-analyze-performance |
|
||||
| Code patterns | gemini | analysis | analysis-analyze-code-patterns |
|
||||
| Task breakdown | gemini | analysis | planning-breakdown-task-steps |
|
||||
| Architecture design | gemini | analysis | planning-plan-architecture-design |
|
||||
| Feature implementation | gemini | write | development-implement-feature |
|
||||
| Refactoring | gemini | write | development-refactor-codebase |
|
||||
| Test generation | gemini | write | development-generate-tests |
|
||||
|
||||
**CLI node args_template format**:
|
||||
```
|
||||
PURPOSE: {goal}
|
||||
TASK: • [derived from step description]
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Memory: {memory_context}
|
||||
EXPECTED: [derived from step output_ports]
|
||||
CONSTRAINTS: {scope}
|
||||
```
|
||||
|
||||
## Agent Nodes
|
||||
|
||||
| subagent_type | Use Case | run_in_background |
|
||||
|---------------|----------|-------------------|
|
||||
| `general-purpose` | Freeform analysis or implementation | false |
|
||||
| `team-worker` | Worker in team-coordinate pipeline | true |
|
||||
| `code-reviewer` | Focused code review | false |
|
||||
|
||||
**Agent node args_template format**:
|
||||
```
|
||||
Task: {goal}
|
||||
|
||||
Context from previous step:
|
||||
{prev_output}
|
||||
|
||||
Deliver: [specify expected output format]
|
||||
```
|
||||
|
||||
## Checkpoint Nodes
|
||||
|
||||
Checkpoints are auto-generated — not selected from catalog.
|
||||
|
||||
| auto_continue | When to Use |
|
||||
|---------------|-------------|
|
||||
| `true` | Background save, execution continues automatically |
|
||||
| `false` | Pause for user review before proceeding |
|
||||
|
||||
Set `auto_continue: false` when:
|
||||
- The next node is user-facing (plan display, spec review)
|
||||
- The user requested an explicit pause in their workflow description
|
||||
- The next node spawns a background agent (give user chance to cancel)
|
||||
202
.claude/skills/wf-composer/specs/template-schema.md
Normal file
202
.claude/skills/wf-composer/specs/template-schema.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# Workflow Template Schema
|
||||
|
||||
## File Location
|
||||
|
||||
`.workflow/templates/<slug>.json`
|
||||
|
||||
## Full Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"template_id": "wft-<slug>-<YYYYMMDD>",
|
||||
"name": "Human readable template name",
|
||||
"description": "Brief description of what this workflow achieves",
|
||||
"version": "1.0",
|
||||
"created_at": "2026-03-17T10:00:00Z",
|
||||
"source_session": "WFD-<slug>-<date>",
|
||||
"tags": ["feature", "medium"],
|
||||
|
||||
"context_schema": {
|
||||
"goal": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"description": "Main task goal or feature to implement"
|
||||
},
|
||||
"scope": {
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"description": "Target file or module scope",
|
||||
"default": "src/**/*"
|
||||
}
|
||||
},
|
||||
|
||||
"nodes": [
|
||||
{
|
||||
"id": "N-001",
|
||||
"name": "Plan Feature",
|
||||
"type": "skill",
|
||||
"executor": "workflow-lite-plan",
|
||||
"args_template": "{goal}",
|
||||
"input_ports": ["requirement"],
|
||||
"output_ports": ["plan"],
|
||||
"parallel_group": null,
|
||||
"on_fail": "abort"
|
||||
},
|
||||
{
|
||||
"id": "CP-01",
|
||||
"name": "Checkpoint: After Plan",
|
||||
"type": "checkpoint",
|
||||
"description": "Plan artifact saved before execution proceeds",
|
||||
"auto_continue": true,
|
||||
"save_fields": ["session_id", "artifacts", "output_path"]
|
||||
},
|
||||
{
|
||||
"id": "N-002",
|
||||
"name": "Execute Implementation",
|
||||
"type": "skill",
|
||||
"executor": "workflow-execute",
|
||||
"args_template": "--resume-session {N-001.session_id}",
|
||||
"input_ports": ["plan"],
|
||||
"output_ports": ["code"],
|
||||
"parallel_group": null,
|
||||
"on_fail": "abort"
|
||||
},
|
||||
{
|
||||
"id": "CP-02",
|
||||
"name": "Checkpoint: Before Testing",
|
||||
"type": "checkpoint",
|
||||
"description": "Implementation complete, ready for test validation",
|
||||
"auto_continue": true,
|
||||
"save_fields": ["session_id", "artifacts"]
|
||||
},
|
||||
{
|
||||
"id": "N-003",
|
||||
"name": "Run Tests",
|
||||
"type": "skill",
|
||||
"executor": "workflow-test-fix",
|
||||
"args_template": "--session {N-002.session_id}",
|
||||
"input_ports": ["code"],
|
||||
"output_ports": ["test-passed"],
|
||||
"parallel_group": null,
|
||||
"on_fail": "abort"
|
||||
}
|
||||
],
|
||||
|
||||
"edges": [
|
||||
{ "from": "N-001", "to": "CP-01" },
|
||||
{ "from": "CP-01", "to": "N-002" },
|
||||
{ "from": "N-002", "to": "CP-02" },
|
||||
{ "from": "CP-02", "to": "N-003" }
|
||||
],
|
||||
|
||||
"checkpoints": ["CP-01", "CP-02"],
|
||||
|
||||
"atomic_groups": [
|
||||
{
|
||||
"name": "planning-execution",
|
||||
"nodes": ["N-001", "CP-01", "N-002"],
|
||||
"description": "Plan must be followed by execution"
|
||||
}
|
||||
],
|
||||
|
||||
"execution_mode": "serial",
|
||||
|
||||
"metadata": {
|
||||
"node_count": 3,
|
||||
"checkpoint_count": 2,
|
||||
"estimated_duration": "20-40 min"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Node Type Definitions
|
||||
|
||||
### `skill` node
|
||||
```json
|
||||
{
|
||||
"id": "N-<seq>",
|
||||
"name": "<descriptive name>",
|
||||
"type": "skill",
|
||||
"executor": "<skill-name>",
|
||||
"args_template": "<string with {variable} and {prev-node-id.field} refs>",
|
||||
"input_ports": ["<port-name>"],
|
||||
"output_ports": ["<port-name>"],
|
||||
"parallel_group": "<group-name> | null",
|
||||
"on_fail": "abort | skip | retry"
|
||||
}
|
||||
```
|
||||
|
||||
### `cli` node
|
||||
```json
|
||||
{
|
||||
"id": "N-<seq>",
|
||||
"name": "<descriptive name>",
|
||||
"type": "cli",
|
||||
"executor": "ccw cli",
|
||||
"cli_tool": "gemini | qwen | codex",
|
||||
"cli_mode": "analysis | write",
|
||||
"cli_rule": "<rule-template-name>",
|
||||
"args_template": "PURPOSE: {goal}\nTASK: ...\nMODE: analysis\nCONTEXT: @**/*\nEXPECTED: ...\nCONSTRAINTS: ...",
|
||||
"input_ports": ["analysis-topic"],
|
||||
"output_ports": ["analysis"],
|
||||
"parallel_group": null,
|
||||
"on_fail": "abort"
|
||||
}
|
||||
```
|
||||
|
||||
### `command` node
|
||||
```json
|
||||
{
|
||||
"id": "N-<seq>",
|
||||
"name": "<descriptive name>",
|
||||
"type": "command",
|
||||
"executor": "workflow:refactor-cycle",
|
||||
"args_template": "{goal}",
|
||||
"input_ports": ["codebase"],
|
||||
"output_ports": ["refactored-code"],
|
||||
"parallel_group": null,
|
||||
"on_fail": "abort"
|
||||
}
|
||||
```
|
||||
|
||||
### `agent` node
|
||||
```json
|
||||
{
|
||||
"id": "N-<seq>",
|
||||
"name": "<descriptive name>",
|
||||
"type": "agent",
|
||||
"executor": "general-purpose",
|
||||
"args_template": "Task: {goal}\n\nContext from previous step:\n{prev_output}",
|
||||
"input_ports": ["requirement"],
|
||||
"output_ports": ["analysis"],
|
||||
"parallel_group": "<group-name> | null",
|
||||
"run_in_background": false,
|
||||
"on_fail": "abort"
|
||||
}
|
||||
```
|
||||
|
||||
### `checkpoint` node
|
||||
```json
|
||||
{
|
||||
"id": "CP-<seq>",
|
||||
"name": "Checkpoint: <description>",
|
||||
"type": "checkpoint",
|
||||
"description": "<what was just completed, what comes next>",
|
||||
"auto_continue": true,
|
||||
"save_fields": ["session_id", "artifacts", "output_path"]
|
||||
}
|
||||
```
|
||||
|
||||
## Runtime Reference Syntax
|
||||
|
||||
In `args_template` strings, these references are resolved at execution time by `wf-player`:
|
||||
|
||||
| Reference | Resolves To |
|
||||
|-----------|-------------|
|
||||
| `{variable}` | Value from context (bound at run start) |
|
||||
| `{N-001.session_id}` | `node_states["N-001"].session_id` |
|
||||
| `{N-001.output_path}` | `node_states["N-001"].output_path` |
|
||||
| `{N-001.artifacts[0]}` | First artifact from N-001 |
|
||||
| `{prev_session_id}` | session_id of the immediately preceding work node |
|
||||
| `{prev_output}` | Full output text of the immediately preceding node |
|
||||
| `{prev_output_path}` | Output file path of the immediately preceding node |
|
||||
151
.claude/skills/wf-player/SKILL.md
Normal file
151
.claude/skills/wf-player/SKILL.md
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
name: wf-player
|
||||
description: Workflow template player — load a JSON template produced by wf-composer, bind context variables, execute nodes in DAG order (serial/parallel), persist state at checkpoints, support resume from any checkpoint. Uses ccw-coordinator serial-blocking for CLI nodes and team-coordinate worker pattern for parallel agent nodes. Triggers on "wf-player " or "/wf-player".
|
||||
argument-hint: "<template-slug|path> [--context key=value...] [--resume <session-id>] [--list] [--dry-run]"
|
||||
allowed-tools: Agent(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*), Skill(*)
|
||||
---
|
||||
|
||||
# Workflow Run
|
||||
|
||||
Load a workflow template → bind variables → execute DAG → persist checkpoints → resume capable.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Skill(skill="wf-player", args="<template> --context goal='...'")
|
||||
|
|
||||
+-- Phase 0: Entry Router
|
||||
|-- --list -> list available templates, exit
|
||||
|-- --resume -> load session, skip to Phase 3 (Execute)
|
||||
|-- --dry-run -> load + show execution plan, no execution
|
||||
|-- default -> Phase 1 (Load)
|
||||
|
|
||||
+-- Phase 1: Load & Bind
|
||||
| Load template JSON, bind {variables} from --context, validate required vars
|
||||
|
|
||||
+-- Phase 2: Instantiate
|
||||
| Init session state, topological sort, write WFR session file
|
||||
|
|
||||
+-- Phase 3: Execute Loop
|
||||
| For each node in order:
|
||||
| skill node -> Skill(skill=...) [synchronous]
|
||||
| cli node -> ccw cli [background + stop, hook callback]
|
||||
| command node -> Skill(skill="namespace:cmd") [synchronous]
|
||||
| agent node -> Agent(...) [run_in_background per node config]
|
||||
| checkpoint -> save state, optionally pause
|
||||
|
|
||||
+-- Phase 4: Complete
|
||||
Archive session, output summary
|
||||
```
|
||||
|
||||
## Shared Constants
|
||||
|
||||
| Constant | Value |
|
||||
|----------|-------|
|
||||
| Session prefix | `WFR` |
|
||||
| Session dir | `.workflow/sessions/WFR-<slug>-<date>/` |
|
||||
| State file | `session-state.json` |
|
||||
| Template dir | `.workflow/templates/` |
|
||||
| Template index | `.workflow/templates/index.json` |
|
||||
|
||||
## Entry Router
|
||||
|
||||
Parse `$ARGUMENTS`:
|
||||
|
||||
| Detection | Condition | Handler |
|
||||
|-----------|-----------|---------|
|
||||
| List templates | `--list` in args | -> handleList |
|
||||
| Resume session | `--resume <session-id>` in args | -> Phase 2 (resume) |
|
||||
| Dry run | `--dry-run` in args | -> Phase 1 + 2, print plan, exit |
|
||||
| Normal | Template slug/path provided | -> Phase 1 |
|
||||
| No args | Empty args | -> handleList + AskUserQuestion |
|
||||
|
||||
### handleList
|
||||
|
||||
Scan `.workflow/templates/index.json`. Display:
|
||||
```
|
||||
Available workflow templates:
|
||||
feature-tdd-review [feature, complex] 3 work nodes, 2 checkpoints
|
||||
quick-bugfix [bugfix, simple] 2 work nodes, 1 checkpoint
|
||||
...
|
||||
|
||||
Run: Skill(skill="wf-player", args="<slug> --context goal='...'")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 0 (Resume): Session Reconciliation
|
||||
|
||||
**Trigger**: `--resume <session-id>` or active WFR session found in `.workflow/sessions/WFR-*/`
|
||||
|
||||
1. Scan `.workflow/sessions/WFR-*/session-state.json` for status = "running" | "paused"
|
||||
2. Multiple found → AskUserQuestion for selection
|
||||
3. Load session-state.json
|
||||
4. Identify `last_checkpoint` and `node_states`
|
||||
5. Reset any `running` nodes back to `pending` (they were interrupted)
|
||||
6. Determine next executable node from `topological_order` after last checkpoint
|
||||
7. Resume at Phase 3 (Execute Loop) from that node
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Load & Bind
|
||||
|
||||
Read `phases/01-load.md` and execute.
|
||||
|
||||
**Objective**: Load template, collect missing variables, bind all {variable} references.
|
||||
|
||||
**Success**: Template loaded, all required variables bound, `bound_context{}` ready.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Instantiate
|
||||
|
||||
Read `phases/02-instantiate.md` and execute.
|
||||
|
||||
**Objective**: Create WFR session directory, init state, compute execution plan.
|
||||
|
||||
**Success**: `session-state.json` written, topological_order ready.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Execute Loop
|
||||
|
||||
Read `phases/03-execute.md` and execute.
|
||||
|
||||
**Objective**: Execute each node in topological_order using appropriate mechanism.
|
||||
|
||||
**CRITICAL — CLI node blocking**:
|
||||
- CLI nodes launch `ccw cli` in background and immediately STOP
|
||||
- Wait for hook callback — DO NOT poll with TaskOutput
|
||||
- Hook callback resumes execution at next node
|
||||
|
||||
**Success**: All nodes completed, all checkpoints saved.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Complete
|
||||
|
||||
Read `phases/04-complete.md` and execute.
|
||||
|
||||
**Objective**: Archive session, output execution summary and artifact paths.
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Required variable missing | AskUserQuestion to collect it |
|
||||
| Template not found | Show `--list` and suggest closest match |
|
||||
| Node failed (on_fail=abort) | AskUserQuestion: Retry / Skip / Abort |
|
||||
| Node failed (on_fail=skip) | Log warning, continue to next node |
|
||||
| Node failed (on_fail=retry) | Retry once, then abort |
|
||||
| Interrupted mid-execution | State saved at last checkpoint; resume with `--resume <session-id>` |
|
||||
| Cycle in DAG | Error immediately, point to template for fix |
|
||||
|
||||
## Specs Reference
|
||||
|
||||
| Spec | Purpose |
|
||||
|------|---------|
|
||||
| [specs/node-executor.md](specs/node-executor.md) | Execution mechanism per node type |
|
||||
| [specs/state-schema.md](specs/state-schema.md) | session-state.json schema |
|
||||
92
.claude/skills/wf-player/phases/01-load.md
Normal file
92
.claude/skills/wf-player/phases/01-load.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Phase 1: Load & Bind
|
||||
|
||||
## Objective
|
||||
|
||||
Locate and load the workflow template, collect any missing context variables from the user, bind all `{variable}` references.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1.1 — Resolve Template Path
|
||||
|
||||
Parse `$ARGUMENTS` for template identifier:
|
||||
|
||||
**Path resolution order**:
|
||||
1. Absolute path: use as-is
|
||||
2. Relative path (starts with `.`): resolve from cwd
|
||||
3. Slug only (e.g. `feature-tdd-review`): look up in `.workflow/templates/index.json` → get path
|
||||
4. Partial slug match: scan index for closest match → confirm with user
|
||||
|
||||
If not found:
|
||||
- Show available templates from index
|
||||
- AskUserQuestion: "Which template to run?"
|
||||
|
||||
### Step 1.2 — Parse --context Arguments
|
||||
|
||||
Extract `--context key=value` pairs from `$ARGUMENTS`.
|
||||
|
||||
Examples:
|
||||
```
|
||||
--context goal="Implement user auth" --context scope="src/auth"
|
||||
--context goal='Fix login bug' scope=src/auth
|
||||
```
|
||||
|
||||
Build `bound_context = { goal: "...", scope: "..." }`.
|
||||
|
||||
### Step 1.3 — Load Template
|
||||
|
||||
Read template JSON from resolved path.
|
||||
|
||||
Validate:
|
||||
- `template_id`, `nodes`, `edges`, `context_schema` all present
|
||||
- `nodes` array non-empty
|
||||
|
||||
### Step 1.4 — Collect Missing Required Variables
|
||||
|
||||
For each variable in `context_schema` where `required: true`:
|
||||
- If not in `bound_context`: collect via AskUserQuestion
|
||||
- If has `default` value: use default if not provided
|
||||
|
||||
```
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "Provide values for required workflow inputs:",
|
||||
header: "Workflow: <template.name>",
|
||||
// one question per missing required variable
|
||||
}]
|
||||
})
|
||||
```
|
||||
|
||||
For optional variables not provided: use `default` value or leave as empty string.
|
||||
|
||||
### Step 1.5 — Bind Variables
|
||||
|
||||
Apply substitution throughout all `args_template` strings:
|
||||
- Replace `{variable_name}` with `bound_context[variable_name]`
|
||||
- Leave `{N-001.session_id}` and `{prev_*}` references unresolved — these are runtime-resolved in Phase 3
|
||||
|
||||
Write bound context to memory for Phase 3 use.
|
||||
|
||||
### Step 1.6 — Dry Run Output (if --dry-run)
|
||||
|
||||
Print execution plan and exit:
|
||||
```
|
||||
Workflow: <template.name>
|
||||
Context:
|
||||
goal = "<value>"
|
||||
scope = "<value>"
|
||||
|
||||
Execution Plan:
|
||||
[1] N-001 [skill] workflow-lite-plan "<goal>"
|
||||
[2] CP-01 [checkpoint] After Plan auto-continue
|
||||
[3] N-002 [skill] workflow-execute --resume-session {N-001.session_id}
|
||||
[4] CP-02 [checkpoint] Before Tests pause-for-user
|
||||
[5] N-003 [skill] workflow-test-fix --session {N-002.session_id}
|
||||
|
||||
To execute: Skill(skill="wf-player", args="<slug> --context goal='...'")
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- Template loaded and validated
|
||||
- All required context variables bound
|
||||
- bound_context{} available for Phase 2
|
||||
110
.claude/skills/wf-player/phases/02-instantiate.md
Normal file
110
.claude/skills/wf-player/phases/02-instantiate.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Phase 2: Instantiate — Init Session State
|
||||
|
||||
## Objective
|
||||
|
||||
Create the WFR session directory, initialize `session-state.json` with all nodes marked pending, compute topological execution order.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 2.1 — Generate Session ID
|
||||
|
||||
```
|
||||
session_id = "WFR-<template-slug>-<YYYYMMDD>-<HHmmss>"
|
||||
session_dir = ".workflow/sessions/<session_id>/"
|
||||
```
|
||||
|
||||
Create session directory.
|
||||
|
||||
### Step 2.2 — Topological Sort
|
||||
|
||||
Run topological sort on `template.nodes` + `template.edges`:
|
||||
|
||||
```
|
||||
function topoSort(nodes, edges):
|
||||
build adjacency list from edges
|
||||
Kahn's algorithm (BFS from nodes with no incoming edges)
|
||||
return ordered node IDs
|
||||
```
|
||||
|
||||
**Parallel group handling**: Nodes in the same `parallel_group` can execute concurrently. In topological order, keep them adjacent and mark them as a parallel batch.
|
||||
|
||||
Store `execution_plan`:
|
||||
```json
|
||||
[
|
||||
{ "batch": 1, "nodes": ["N-001"], "parallel": false },
|
||||
{ "batch": 2, "nodes": ["CP-01"], "parallel": false },
|
||||
{ "batch": 3, "nodes": ["N-002a", "N-002b"], "parallel": true },
|
||||
{ "batch": 4, "nodes": ["N-003"], "parallel": false }
|
||||
]
|
||||
```
|
||||
|
||||
### Step 2.3 — Init Node States
|
||||
|
||||
For each node in template:
|
||||
```json
|
||||
{
|
||||
"N-001": {
|
||||
"status": "pending",
|
||||
"started_at": null,
|
||||
"completed_at": null,
|
||||
"session_id": null,
|
||||
"output_path": null,
|
||||
"artifacts": [],
|
||||
"error": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Checkpoint nodes:
|
||||
```json
|
||||
{
|
||||
"CP-01": {
|
||||
"status": "pending",
|
||||
"saved_at": null,
|
||||
"snapshot_path": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2.4 — Write session-state.json
|
||||
|
||||
See `specs/state-schema.md` for full schema. Write to `<session_dir>/session-state.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "<WFR-id>",
|
||||
"template_id": "<template.template_id>",
|
||||
"template_path": "<path to template>",
|
||||
"template_name": "<template.name>",
|
||||
"status": "running",
|
||||
"context": { /* bound_context from Phase 1 */ },
|
||||
"execution_plan": [ /* batches */ ],
|
||||
"current_batch": 1,
|
||||
"current_node": "N-001",
|
||||
"last_checkpoint": null,
|
||||
"node_states": { /* all nodes as pending */ },
|
||||
"created_at": "<ISO>",
|
||||
"updated_at": "<ISO>"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2.5 — Show Execution Start Banner
|
||||
|
||||
```
|
||||
[wf-player] ============================================
|
||||
[wf-player] Starting: <template.name>
|
||||
[wf-player] Session: <session_id>
|
||||
[wf-player] Context: goal="<value>"
|
||||
[wf-player]
|
||||
[wf-player] Plan: <N> nodes, <C> checkpoints
|
||||
[wf-player] N-001 [skill] workflow-lite-plan
|
||||
[wf-player] CP-01 [checkpoint] After Plan
|
||||
[wf-player] N-002 [skill] workflow-execute
|
||||
[wf-player] ============================================
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- `<session_dir>/session-state.json` written
|
||||
- `execution_plan` has valid topological order
|
||||
- Status = "running"
|
||||
211
.claude/skills/wf-player/phases/03-execute.md
Normal file
211
.claude/skills/wf-player/phases/03-execute.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# Phase 3: Execute Loop
|
||||
|
||||
## Objective
|
||||
|
||||
Execute each node batch in topological order. Use the correct mechanism per node type. Save state after every checkpoint. Support CLI serial-blocking with hook callback resume.
|
||||
|
||||
## Pre-execution: Runtime Reference Resolution
|
||||
|
||||
Before executing each node, resolve any `{N-xxx.field}` and `{prev_*}` references in `args_template`:
|
||||
|
||||
```
|
||||
function resolveArgs(args_template, node_id, session_state):
|
||||
for each {ref} in args_template:
|
||||
if ref matches {variable}:
|
||||
replace with session_state.context[variable]
|
||||
if ref matches {N-001.session_id}:
|
||||
replace with session_state.node_states["N-001"].session_id
|
||||
if ref matches {N-001.output_path}:
|
||||
replace with session_state.node_states["N-001"].output_path
|
||||
if ref matches {prev_session_id}:
|
||||
find previous non-checkpoint node -> replace with its session_id
|
||||
if ref matches {prev_output}:
|
||||
find previous non-checkpoint node -> replace with its output_text
|
||||
if ref matches {prev_output_path}:
|
||||
find previous non-checkpoint node -> replace with its output_path
|
||||
return resolved_args
|
||||
```
|
||||
|
||||
## Node Execution by Type
|
||||
|
||||
Read `specs/node-executor.md` for full details. Summary:
|
||||
|
||||
### skill node
|
||||
|
||||
```
|
||||
resolved_args = resolveArgs(node.args_template, ...)
|
||||
mark node status = "running", write session-state.json
|
||||
|
||||
result = Skill(skill=node.executor, args=resolved_args)
|
||||
|
||||
extract from result: session_id, output_path, artifacts[]
|
||||
update node_states[node.id]:
|
||||
status = "completed"
|
||||
session_id = extracted_session_id
|
||||
output_path = extracted_output_path
|
||||
artifacts = extracted_artifacts
|
||||
completed_at = now()
|
||||
|
||||
write session-state.json
|
||||
advance to next node
|
||||
```
|
||||
|
||||
### command node
|
||||
|
||||
Same as skill node but executor is a namespaced command:
|
||||
```
|
||||
Skill(skill=node.executor, args=resolved_args)
|
||||
```
|
||||
|
||||
### cli node — CRITICAL: serial blocking
|
||||
|
||||
```
|
||||
resolved_args = resolveArgs(node.args_template, ...)
|
||||
mark node status = "running", write session-state.json
|
||||
|
||||
Bash({
|
||||
command: `ccw cli -p "${resolved_args}" --tool ${node.cli_tool} --mode ${node.cli_mode} --rule ${node.cli_rule}`,
|
||||
run_in_background: true
|
||||
})
|
||||
|
||||
write session-state.json // persist "running" state
|
||||
STOP — wait for hook callback
|
||||
```
|
||||
|
||||
**Hook callback resumes here**:
|
||||
```
|
||||
// Called when ccw cli completes
|
||||
load session-state.json
|
||||
find node with status "running"
|
||||
extract result: exec_id, output_path, cli_output
|
||||
update node_states[node.id]:
|
||||
status = "completed"
|
||||
output_path = extracted_output_path
|
||||
completed_at = now()
|
||||
write session-state.json
|
||||
advance to next node
|
||||
```
|
||||
|
||||
### agent node
|
||||
|
||||
```
|
||||
resolved_args = resolveArgs(node.args_template, ...)
|
||||
mark node status = "running", write session-state.json
|
||||
|
||||
result = Agent({
|
||||
subagent_type: node.executor,
|
||||
prompt: resolved_args,
|
||||
run_in_background: node.run_in_background ?? false,
|
||||
description: node.name
|
||||
})
|
||||
|
||||
update node_states[node.id]:
|
||||
status = "completed"
|
||||
output_path = result.output_path or session_dir + "/artifacts/" + node.id + ".md"
|
||||
completed_at = now()
|
||||
write session-state.json
|
||||
advance to next node
|
||||
```
|
||||
|
||||
**Parallel agent nodes** (same parallel_group):
|
||||
```
|
||||
// Launch all agents in parallel
|
||||
for each node in parallel_batch:
|
||||
mark node status = "running"
|
||||
|
||||
Agent({
|
||||
subagent_type: node.executor,
|
||||
prompt: resolveArgs(node.args_template, ...),
|
||||
run_in_background: true, // parallel
|
||||
description: node.name
|
||||
})
|
||||
|
||||
// Wait for all to complete (Agent with run_in_background=false blocks — use team-coordinate pattern)
|
||||
// team-coordinate: spawn as team-workers with callbacks if complex
|
||||
// For simple parallel: use multiple Agent calls synchronously or use team-coordinate's spawn-and-stop
|
||||
```
|
||||
|
||||
### checkpoint node
|
||||
|
||||
```
|
||||
// Save snapshot
|
||||
snapshot = {
|
||||
session_id: session_state.session_id,
|
||||
checkpoint_id: node.id,
|
||||
checkpoint_name: node.name,
|
||||
saved_at: now(),
|
||||
node_states_snapshot: session_state.node_states,
|
||||
last_completed_node: previous_node_id
|
||||
}
|
||||
|
||||
write session-state.json (last_checkpoint = node.id)
|
||||
write <session_dir>/checkpoints/<node.id>.json
|
||||
|
||||
if node.auto_continue == false:
|
||||
// Pause for user
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: node.description + "\n\nReview checkpoint state and confirm to continue.",
|
||||
header: "Checkpoint: " + node.name,
|
||||
options: [
|
||||
{ label: "Continue", description: "Proceed to next node" },
|
||||
{ label: "Pause", description: "Save state and exit (resume later)" },
|
||||
{ label: "Abort", description: "Stop execution" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
|
||||
on "Pause":
|
||||
session_state.status = "paused"
|
||||
write session-state.json
|
||||
output "Session paused. Resume with: Skill(skill='wf-player', args='--resume <session_id>')"
|
||||
EXIT
|
||||
|
||||
on "Abort":
|
||||
session_state.status = "aborted"
|
||||
write session-state.json
|
||||
EXIT
|
||||
|
||||
// auto_continue or user chose Continue
|
||||
mark checkpoint status = "completed"
|
||||
write session-state.json
|
||||
advance to next node
|
||||
```
|
||||
|
||||
## Progress Display
|
||||
|
||||
After each node completes, print progress:
|
||||
```
|
||||
[wf-player] [2/5] CP-01 checkpoint saved ✓
|
||||
[wf-player] [3/5] N-002 workflow-execute ... running
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
On node failure (exception or skill returning error state):
|
||||
|
||||
```
|
||||
on_fail = node.on_fail || "abort"
|
||||
|
||||
if on_fail == "skip":
|
||||
mark node status = "skipped"
|
||||
log warning
|
||||
advance to next node
|
||||
|
||||
if on_fail == "retry":
|
||||
retry once
|
||||
if still fails: fall through to abort
|
||||
|
||||
if on_fail == "abort":
|
||||
AskUserQuestion:
|
||||
- Retry
|
||||
- Skip this node
|
||||
- Abort workflow
|
||||
handle choice accordingly
|
||||
```
|
||||
|
||||
## Loop Termination
|
||||
|
||||
After last node in execution_plan completes:
|
||||
- All node_states should be "completed" or "skipped"
|
||||
- Proceed to Phase 4 (Complete)
|
||||
93
.claude/skills/wf-player/phases/04-complete.md
Normal file
93
.claude/skills/wf-player/phases/04-complete.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Phase 4: Complete — Archive + Summary
|
||||
|
||||
## Objective
|
||||
|
||||
Mark session complete, output execution summary with artifact paths, offer archive/keep options.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 4.1 — Mark Session Complete
|
||||
|
||||
Load `session-state.json`.
|
||||
|
||||
Set:
|
||||
```json
|
||||
{
|
||||
"status": "completed",
|
||||
"completed_at": "<ISO timestamp>"
|
||||
}
|
||||
```
|
||||
|
||||
Write back to `session-state.json`.
|
||||
|
||||
### Step 4.2 — Collect Artifacts
|
||||
|
||||
Aggregate all artifacts from node_states:
|
||||
```javascript
|
||||
const artifacts = Object.values(node_states)
|
||||
.filter(s => s.artifacts && s.artifacts.length > 0)
|
||||
.flatMap(s => s.artifacts.map(a => ({ node: s.node_id, path: a })));
|
||||
|
||||
const outputPaths = Object.values(node_states)
|
||||
.filter(s => s.output_path)
|
||||
.map(s => ({ node: s.node_id, path: s.output_path }));
|
||||
```
|
||||
|
||||
### Step 4.3 — Execution Summary
|
||||
|
||||
```
|
||||
[wf-player] ============================================
|
||||
[wf-player] COMPLETE: <template_name>
|
||||
[wf-player]
|
||||
[wf-player] Session: <session_id>
|
||||
[wf-player] Context: goal="<value>"
|
||||
[wf-player]
|
||||
[wf-player] Nodes: <completed>/<total> completed
|
||||
[wf-player] N-001 workflow-lite-plan ✓ (WFS-plan-xxx)
|
||||
[wf-player] CP-01 After Plan ✓ (checkpoint saved)
|
||||
[wf-player] N-002 workflow-execute ✓ (WFS-exec-xxx)
|
||||
[wf-player] CP-02 Before Tests ✓ (checkpoint saved)
|
||||
[wf-player] N-003 workflow-test-fix ✓ (WFS-test-xxx)
|
||||
[wf-player]
|
||||
[wf-player] Artifacts:
|
||||
[wf-player] - IMPL_PLAN.md (N-001)
|
||||
[wf-player] - src/auth/index.ts (N-002)
|
||||
[wf-player] - test/auth.test.ts (N-003)
|
||||
[wf-player]
|
||||
[wf-player] Session dir: .workflow/sessions/<session_id>/
|
||||
[wf-player] ============================================
|
||||
```
|
||||
|
||||
### Step 4.4 — Completion Action
|
||||
|
||||
```
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "Workflow complete. What would you like to do?",
|
||||
header: "Completion Action",
|
||||
options: [
|
||||
{ label: "Archive session", description: "Move session to .workflow/sessions/archive/" },
|
||||
{ label: "Keep session", description: "Leave session active for follow-up" },
|
||||
{ label: "Run again", description: "Re-run template with same or new context" },
|
||||
{ label: "Nothing", description: "Done" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
```
|
||||
|
||||
**Archive**:
|
||||
- Move `<session_dir>` to `.workflow/sessions/archive/<session_id>/`
|
||||
- Update `session-state.json` status = "archived"
|
||||
|
||||
**Keep**: No action, session stays at `.workflow/sessions/<session_id>/`
|
||||
|
||||
**Run again**:
|
||||
- AskUserQuestion: "Same context or new?" → new context → re-enter Phase 1
|
||||
|
||||
**Nothing**: Output final artifact paths list, done.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- session-state.json status = "completed" or "archived"
|
||||
- All artifact paths listed in console output
|
||||
- User presented completion action options
|
||||
187
.claude/skills/wf-player/specs/node-executor.md
Normal file
187
.claude/skills/wf-player/specs/node-executor.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# Node Executor — Execution Mechanisms per Node Type
|
||||
|
||||
## Overview
|
||||
|
||||
Each node type uses a specific execution mechanism. This spec defines the exact invocation pattern.
|
||||
|
||||
## 1. skill node
|
||||
|
||||
**Mechanism**: `Skill()` tool — synchronous, blocks until complete.
|
||||
|
||||
```
|
||||
Skill({
|
||||
skill: "<node.executor>",
|
||||
args: "<resolved_args>"
|
||||
})
|
||||
```
|
||||
|
||||
**Output extraction**: Parse Skill() result for:
|
||||
- Session ID pattern: `WFS-[a-z]+-\d{8}` or `TC-[a-z]+-\d{8}`
|
||||
- Output path: last `.md` or `.json` file path mentioned
|
||||
- Artifacts: all file paths in output
|
||||
|
||||
**Session ID sources**:
|
||||
- Explicit: "Session: WFS-plan-20260317" in output
|
||||
- Implicit: first session-like ID in output
|
||||
|
||||
**Examples**:
|
||||
```
|
||||
// Planning skill
|
||||
Skill({ skill: "workflow-lite-plan", args: "Implement user authentication" })
|
||||
|
||||
// Execute skill (with prior session)
|
||||
Skill({ skill: "workflow-execute", args: "--resume-session WFS-plan-20260317" })
|
||||
|
||||
// Test skill (with prior session)
|
||||
Skill({ skill: "workflow-test-fix", args: "--session WFS-exec-20260317" })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. command node
|
||||
|
||||
**Mechanism**: `Skill()` tool with namespace command name — synchronous.
|
||||
|
||||
```
|
||||
Skill({
|
||||
skill: "<node.executor>", // e.g. "workflow:refactor-cycle"
|
||||
args: "<resolved_args>"
|
||||
})
|
||||
```
|
||||
|
||||
**Examples**:
|
||||
```
|
||||
Skill({ skill: "workflow:refactor-cycle", args: "Reduce coupling in auth module" })
|
||||
Skill({ skill: "workflow:debug-with-file", args: "Login fails with 401 on valid tokens" })
|
||||
Skill({ skill: "issue:discover", args: "" })
|
||||
Skill({ skill: "issue:queue", args: "" })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. cli node
|
||||
|
||||
**Mechanism**: `Bash()` with `run_in_background: true` — STOP after launch, resume via hook callback.
|
||||
|
||||
```
|
||||
// Build command
|
||||
const prompt = resolveArgs(node.args_template, ...)
|
||||
const cmd = `ccw cli -p "${escapeForShell(prompt)}" --tool ${node.cli_tool} --mode ${node.cli_mode} --rule ${node.cli_rule}`
|
||||
|
||||
// Launch background
|
||||
Bash({ command: cmd, run_in_background: true })
|
||||
|
||||
// Save CLI task ID to node state for hook matching
|
||||
node_state.cli_task_id = <captured from stderr CCW_EXEC_ID>
|
||||
|
||||
// Write session-state.json
|
||||
// STOP — do not proceed until hook callback fires
|
||||
```
|
||||
|
||||
**Hook callback** (triggered when ccw cli completes):
|
||||
```
|
||||
// Identify which node was running (status = "running" with cli_task_id set)
|
||||
// Extract from CLI output:
|
||||
// - output_path: file written by CLI
|
||||
// - cli_exec_id: from CCW_EXEC_ID
|
||||
// Mark node completed
|
||||
// Advance to next node
|
||||
```
|
||||
|
||||
**CLI output escaping**:
|
||||
```javascript
|
||||
function escapeForShell(s) {
|
||||
// Use single quotes with escaped single quotes inside
|
||||
return "'" + s.replace(/'/g, "'\\''") + "'"
|
||||
}
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Bash({
|
||||
command: `ccw cli -p 'PURPOSE: Analyze auth module architecture\nTASK: • Review class structure • Check dependencies\nMODE: analysis\nCONTEXT: @src/auth/**/*\nEXPECTED: Architecture report with issues list\nCONSTRAINTS: Read only' --tool gemini --mode analysis --rule analysis-review-architecture`,
|
||||
run_in_background: true
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. agent node
|
||||
|
||||
**Mechanism**: `Agent()` tool.
|
||||
|
||||
Single agent (serial):
|
||||
```
|
||||
Agent({
|
||||
subagent_type: node.executor, // "general-purpose" or "code-reviewer"
|
||||
prompt: resolveArgs(node.args_template, ...),
|
||||
run_in_background: false, // blocks until complete
|
||||
description: node.name
|
||||
})
|
||||
```
|
||||
|
||||
Parallel agents (same parallel_group — use team-coordinate pattern):
|
||||
```
|
||||
// For 2-3 parallel agents: launch all with run_in_background: true
|
||||
// Use SendMessage/callback or wait with sequential Skill() calls
|
||||
// For complex parallel pipelines: delegate to team-coordinate
|
||||
|
||||
Skill({
|
||||
skill: "team-coordinate",
|
||||
args: "<description of parallel work>"
|
||||
})
|
||||
```
|
||||
|
||||
**Output extraction**:
|
||||
- Agent output is usually the full response text
|
||||
- Look for file paths in output for `output_path`
|
||||
|
||||
---
|
||||
|
||||
## 5. checkpoint node
|
||||
|
||||
**Mechanism**: Pure state management — no external calls unless `auto_continue: false`.
|
||||
|
||||
```
|
||||
// 1. Write checkpoint snapshot
|
||||
Write({
|
||||
file_path: "<session_dir>/checkpoints/<node.id>.json",
|
||||
content: JSON.stringify({
|
||||
session_id, checkpoint_id: node.id, checkpoint_name: node.name,
|
||||
saved_at: now(), context_snapshot: session_state.context,
|
||||
node_states_snapshot: session_state.node_states,
|
||||
last_completed_node: prev_node_id,
|
||||
next_node: next_node_id
|
||||
}, null, 2)
|
||||
})
|
||||
|
||||
// 2. Update session state
|
||||
session_state.last_checkpoint = node.id
|
||||
node_states[node.id].status = "completed"
|
||||
node_states[node.id].saved_at = now()
|
||||
node_states[node.id].snapshot_path = checkpointPath
|
||||
|
||||
Write({ file_path: session_state_path, content: JSON.stringify(session_state, null, 2) })
|
||||
|
||||
// 3. If auto_continue = false: pause for user (see 03-execute.md)
|
||||
// 4. If auto_continue = true: proceed immediately
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Context Passing Between Nodes
|
||||
|
||||
The runtime reference resolver in `03-execute.md` handles `{N-xxx.field}` substitution.
|
||||
|
||||
**Key resolved fields by node type**:
|
||||
|
||||
| Node type | Exposes | Referenced as |
|
||||
|-----------|---------|---------------|
|
||||
| skill | session_id | `{N-001.session_id}` |
|
||||
| skill | output_path | `{N-001.output_path}` |
|
||||
| skill | artifacts[0] | `{N-001.artifacts[0]}` |
|
||||
| cli | output_path | `{N-001.output_path}` |
|
||||
| agent | output_path | `{N-001.output_path}` |
|
||||
| any | shorthand prev | `{prev_session_id}`, `{prev_output_path}` |
|
||||
|
||||
**Fallback**: If referenced field is null/empty, the args_template substitution results in empty string. The executor should handle gracefully (most skills default to latest session).
|
||||
136
.claude/skills/wf-player/specs/state-schema.md
Normal file
136
.claude/skills/wf-player/specs/state-schema.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Session State Schema
|
||||
|
||||
## File Location
|
||||
|
||||
`.workflow/sessions/WFR-<slug>-<date>-<time>/session-state.json`
|
||||
|
||||
## Full Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "WFR-feature-tdd-review-20260317-143022",
|
||||
"template_id": "wft-feature-tdd-review-20260310",
|
||||
"template_path": ".workflow/templates/feature-tdd-review.json",
|
||||
"template_name": "Feature TDD with Review",
|
||||
|
||||
"status": "running | paused | completed | failed | aborted | archived",
|
||||
|
||||
"context": {
|
||||
"goal": "Implement user authentication",
|
||||
"scope": "src/auth"
|
||||
},
|
||||
|
||||
"execution_plan": [
|
||||
{ "batch": 1, "nodes": ["N-001"], "parallel": false },
|
||||
{ "batch": 2, "nodes": ["CP-01"], "parallel": false },
|
||||
{ "batch": 3, "nodes": ["N-002"], "parallel": false },
|
||||
{ "batch": 4, "nodes": ["CP-02"], "parallel": false },
|
||||
{ "batch": 5, "nodes": ["N-003a", "N-003b"], "parallel": true },
|
||||
{ "batch": 6, "nodes": ["N-004"], "parallel": false }
|
||||
],
|
||||
|
||||
"current_batch": 3,
|
||||
"current_node": "N-002",
|
||||
"last_checkpoint": "CP-01",
|
||||
|
||||
"node_states": {
|
||||
"N-001": {
|
||||
"status": "completed",
|
||||
"started_at": "2026-03-17T14:30:25Z",
|
||||
"completed_at": "2026-03-17T14:35:10Z",
|
||||
"session_id": "WFS-plan-20260317",
|
||||
"output_path": ".workflow/sessions/WFS-plan-20260317/IMPL_PLAN.md",
|
||||
"artifacts": [
|
||||
".workflow/sessions/WFS-plan-20260317/IMPL_PLAN.md"
|
||||
],
|
||||
"error": null
|
||||
},
|
||||
"CP-01": {
|
||||
"status": "completed",
|
||||
"saved_at": "2026-03-17T14:35:12Z",
|
||||
"snapshot_path": ".workflow/sessions/WFR-feature-tdd-review-20260317-143022/checkpoints/CP-01.json",
|
||||
"auto_continue": true
|
||||
},
|
||||
"N-002": {
|
||||
"status": "running",
|
||||
"started_at": "2026-03-17T14:35:14Z",
|
||||
"completed_at": null,
|
||||
"session_id": null,
|
||||
"output_path": null,
|
||||
"artifacts": [],
|
||||
"error": null,
|
||||
"cli_task_id": "gem-143514-x7k2"
|
||||
},
|
||||
"CP-02": {
|
||||
"status": "pending",
|
||||
"saved_at": null,
|
||||
"snapshot_path": null
|
||||
},
|
||||
"N-003a": {
|
||||
"status": "pending",
|
||||
"started_at": null,
|
||||
"completed_at": null,
|
||||
"session_id": null,
|
||||
"output_path": null,
|
||||
"artifacts": [],
|
||||
"error": null
|
||||
},
|
||||
"N-003b": { "status": "pending", "..." : "..." },
|
||||
"N-004": { "status": "pending", "..." : "..." }
|
||||
},
|
||||
|
||||
"created_at": "2026-03-17T14:30:22Z",
|
||||
"updated_at": "2026-03-17T14:35:14Z",
|
||||
"completed_at": null
|
||||
}
|
||||
```
|
||||
|
||||
## Status Values
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| `running` | Active execution in progress |
|
||||
| `paused` | User paused at checkpoint — resume with `--resume` |
|
||||
| `completed` | All nodes executed successfully |
|
||||
| `failed` | A node failed and abort was chosen |
|
||||
| `aborted` | User aborted at checkpoint |
|
||||
| `archived` | Completed and moved to archive/ |
|
||||
|
||||
## Node State Status Values
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| `pending` | Not yet started |
|
||||
| `running` | Currently executing (may be waiting for CLI callback) |
|
||||
| `completed` | Successfully finished |
|
||||
| `skipped` | Skipped due to `on_fail: skip` |
|
||||
| `failed` | Execution error |
|
||||
|
||||
## Checkpoint Snapshot Schema
|
||||
|
||||
`.workflow/sessions/<wfr-id>/checkpoints/<CP-id>.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "WFR-<id>",
|
||||
"checkpoint_id": "CP-01",
|
||||
"checkpoint_name": "After Plan",
|
||||
"saved_at": "2026-03-17T14:35:12Z",
|
||||
"context_snapshot": { "goal": "...", "scope": "..." },
|
||||
"node_states_snapshot": { /* full node_states at this point */ },
|
||||
"last_completed_node": "N-001",
|
||||
"next_node": "N-002"
|
||||
}
|
||||
```
|
||||
|
||||
## Session Directory Structure
|
||||
|
||||
```
|
||||
.workflow/sessions/WFR-<slug>-<date>-<time>/
|
||||
+-- session-state.json # Main state file, updated after every node
|
||||
+-- checkpoints/ # Checkpoint snapshots
|
||||
| +-- CP-01.json
|
||||
| +-- CP-02.json
|
||||
+-- artifacts/ # Optional: copies of key artifacts
|
||||
+-- N-001-output.md
|
||||
```
|
||||
Reference in New Issue
Block a user