mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-30 20:21:09 +08:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4092c89ab5 | ||
|
|
b88bf5e0f6 | ||
|
|
2ca87087f1 | ||
|
|
da643e65b1 | ||
|
|
de7ec94a06 | ||
|
|
67ff3fe339 | ||
|
|
360a0316f7 | ||
|
|
cac126e7bf | ||
|
|
46d4d4b20f | ||
|
|
1803f2e791 | ||
|
|
56c0429412 | ||
|
|
885eb18d87 | ||
|
|
92dbde696e | ||
|
|
21a6d29701 | ||
|
|
bbceef3d36 | ||
|
|
bb0346e506 | ||
|
|
55a89d6444 | ||
|
|
e30fc3575a | ||
|
|
6be78cbe22 | ||
|
|
367466c1ef | ||
|
|
ffae6ddc19 | ||
|
|
4fb983c747 | ||
|
|
45212e14c9 | ||
|
|
662cff53d9 | ||
|
|
656550210e | ||
|
|
88ea7fc6d7 | ||
|
|
e7d59140c0 | ||
|
|
3d39ac6ac8 | ||
|
|
e83063bd29 | ||
|
|
25d4764d7f | ||
|
|
a45c672d30 | ||
|
|
b104cd9ffd | ||
|
|
3111bd23f4 | ||
|
|
36672bae39 | ||
|
|
aeaf54519e | ||
|
|
c1268cb6ce | ||
|
|
017fd9ea53 | ||
|
|
8cfc71139e | ||
|
|
4c03a92eb9 | ||
|
|
22c7d90d5a | ||
|
|
e293195ad0 | ||
|
|
c744a80ef9 | ||
|
|
c882eeee58 | ||
|
|
9043a0d453 | ||
|
|
2a6df97293 | ||
|
|
d693f05b69 | ||
|
|
a525db14c7 | ||
|
|
f112d4b9a2 | ||
|
|
45756aad83 | ||
|
|
1e560ab8e8 | ||
|
|
54283e5dbb | ||
|
|
bab3719ab1 | ||
|
|
fe7945eaa2 | ||
|
|
ccb5f1e615 | ||
|
|
bfad1d5eb6 | ||
|
|
d2409f0814 | ||
|
|
f2d9d55ea4 | ||
|
|
94e44ca7e6 | ||
|
|
b502ebcae1 | ||
|
|
97ed2ef213 | ||
|
|
fcd0b9a2c4 | ||
|
|
fab07c2e97 | ||
|
|
5d0000bcc5 | ||
|
|
c8840847d2 | ||
|
|
8953795c49 |
@@ -14,3 +14,8 @@ keywords: [architecture, constraint, schema, compatibility, portability, design,
|
||||
|
||||
- [compatibility] When enhancing existing schemas, use optional fields and additionalProperties rather than creating new schemas. Avoid breaking changes.
|
||||
- [portability] Use relative paths for cross-artifact navigation to ensure portability across different environments and installations.
|
||||
|
||||
## Skill Design
|
||||
|
||||
- [decision:skills] All skills must follow Completion Status Protocol (DONE/DONE_WITH_CONCERNS/BLOCKED/NEEDS_CONTEXT) defined in SKILL-DESIGN-SPEC.md sections 13-14. New skills created via skill-generator auto-include the protocol reference. (2026-03-29)
|
||||
- [decision:hooks] Hook safety guardrails use TypeScript HookTemplate pattern (not standalone bash scripts) for integration with CCW hook endpoint system. Templates: careful-destructive-guard, freeze-edit-boundary. (2026-03-29)
|
||||
|
||||
255
.ccw/workflows/cli-templates/schemas/team-tasks-schema.json
Normal file
255
.ccw/workflows/cli-templates/schemas/team-tasks-schema.json
Normal file
@@ -0,0 +1,255 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "team-tasks-schema",
|
||||
"title": "Team Tasks State",
|
||||
"description": "Universal tasks.json schema for all Codex team skills. Single source of truth for task state management, replacing Claude Code TaskCreate/TaskUpdate API.",
|
||||
|
||||
"type": "object",
|
||||
"required": ["session_id", "skill", "pipeline", "requirement", "created_at", "tasks"],
|
||||
"properties": {
|
||||
"session_id": {
|
||||
"type": "string",
|
||||
"description": "Unique session identifier. Format: <skill-prefix>-<slug>-<YYYYMMDD>",
|
||||
"pattern": "^[a-zA-Z0-9]+-[a-z0-9-]+-\\d{8}$",
|
||||
"examples": ["tlv4-auth-system-20260324", "brs-product-strategy-20260324", "ao-api-perf-20260324"]
|
||||
},
|
||||
"skill": {
|
||||
"type": "string",
|
||||
"description": "Source team skill name (e.g., team-lifecycle-v4, team-brainstorm, team-arch-opt)"
|
||||
},
|
||||
"pipeline": {
|
||||
"type": "string",
|
||||
"description": "Selected pipeline name from the skill's specs/pipelines.md or specs/team-config.json"
|
||||
},
|
||||
"requirement": {
|
||||
"type": "string",
|
||||
"description": "Original user requirement text, verbatim"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 creation timestamp with timezone"
|
||||
},
|
||||
"supervision": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether CHECKPOINT tasks are active"
|
||||
},
|
||||
"completed_waves": {
|
||||
"type": "array",
|
||||
"items": { "type": "integer", "minimum": 1 },
|
||||
"default": [],
|
||||
"description": "List of completed wave numbers"
|
||||
},
|
||||
"active_agents": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "type": "string" },
|
||||
"default": {},
|
||||
"description": "Runtime tracking: { task_id: agent_id } for currently running agents"
|
||||
},
|
||||
"gc_rounds": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"description": "Generator-Critic / Fix-Verify loop iteration count (skills with GC loops)"
|
||||
},
|
||||
"tasks": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "$ref": "#/$defs/TaskEntry" },
|
||||
"description": "Task registry: { TASK-ID: TaskEntry }"
|
||||
}
|
||||
},
|
||||
|
||||
"$defs": {
|
||||
"TaskEntry": {
|
||||
"type": "object",
|
||||
"required": ["title", "description", "role", "deps", "wave", "status"],
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Human-readable task name"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "What the task should accomplish"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "Role name matching roles/<role>/role.md in the skill directory"
|
||||
},
|
||||
"pipeline_phase": {
|
||||
"type": "string",
|
||||
"description": "Phase from the skill's pipelines.md Task Metadata Registry (skill-specific)"
|
||||
},
|
||||
"deps": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"default": [],
|
||||
"description": "Task IDs that must complete before this task starts. All must be 'completed'"
|
||||
},
|
||||
"context_from": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"default": [],
|
||||
"description": "Task IDs whose discoveries to load as upstream context"
|
||||
},
|
||||
"wave": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"description": "Execution wave number (1-based). Tasks in the same wave run in parallel"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["pending", "in_progress", "completed", "failed", "skipped"],
|
||||
"default": "pending",
|
||||
"description": "Current task state"
|
||||
},
|
||||
"findings": {
|
||||
"type": ["string", "null"],
|
||||
"maxLength": 500,
|
||||
"default": null,
|
||||
"description": "Summary of task output (max 500 chars). Required when status=completed"
|
||||
},
|
||||
"quality_score": {
|
||||
"type": ["number", "null"],
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"default": null,
|
||||
"description": "0-100, set by reviewer/evaluator roles only"
|
||||
},
|
||||
"supervision_verdict": {
|
||||
"type": ["string", "null"],
|
||||
"enum": ["pass", "warn", "block", null],
|
||||
"default": null,
|
||||
"description": "Set by CHECKPOINT/supervisor tasks only"
|
||||
},
|
||||
"error": {
|
||||
"type": ["string", "null"],
|
||||
"default": null,
|
||||
"description": "Error description. Required when status=failed or status=skipped"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"DiscoveryEntry": {
|
||||
"type": "object",
|
||||
"required": ["task_id", "timestamp", "status", "findings", "data"],
|
||||
"description": "Schema for discoveries/{task_id}.json — each task writes one on completion",
|
||||
"properties": {
|
||||
"task_id": {
|
||||
"type": "string",
|
||||
"description": "Matches the task key in tasks.json"
|
||||
},
|
||||
"worker": {
|
||||
"type": "string",
|
||||
"description": "Same as task_id (identifies the producing agent)"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 completion timestamp"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Same as pipeline_phase"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["completed", "failed"]
|
||||
},
|
||||
"findings": {
|
||||
"type": "string",
|
||||
"maxLength": 500
|
||||
},
|
||||
"quality_score": {
|
||||
"type": ["number", "null"]
|
||||
},
|
||||
"supervision_verdict": {
|
||||
"type": ["string", "null"],
|
||||
"enum": ["pass", "warn", "block", null]
|
||||
},
|
||||
"error": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key_findings": {
|
||||
"type": "array",
|
||||
"items": { "type": "string", "maxLength": 100 },
|
||||
"maxItems": 5
|
||||
},
|
||||
"decisions": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Include rationale, not just choice"
|
||||
},
|
||||
"files_modified": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Only for implementation tasks"
|
||||
},
|
||||
"verification": {
|
||||
"type": "string",
|
||||
"enum": ["self-validated", "peer-reviewed", "tested"]
|
||||
},
|
||||
"risks_logged": {
|
||||
"type": "integer",
|
||||
"description": "CHECKPOINT only: count of risks"
|
||||
},
|
||||
"blocks_detected": {
|
||||
"type": "integer",
|
||||
"description": "CHECKPOINT only: count of blocking issues"
|
||||
}
|
||||
}
|
||||
},
|
||||
"artifacts_produced": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Paths to generated artifact files"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"$comment_validation_rules": {
|
||||
"structural": [
|
||||
"Unique IDs: every key in tasks must be unique",
|
||||
"Valid deps: every entry in deps must reference an existing task ID",
|
||||
"Valid context_from: every entry in context_from must reference an existing task ID",
|
||||
"No cycles: dependency graph must be a DAG",
|
||||
"Wave ordering: if task A depends on task B, then A.wave > B.wave",
|
||||
"Role exists: role must match a directory in the skill's roles/"
|
||||
],
|
||||
"runtime": [
|
||||
"Status transitions: pending->in_progress, in_progress->completed|failed, pending->skipped",
|
||||
"Dependency check: task can only move to in_progress if all deps are completed",
|
||||
"Skip propagation: if any dep is failed|skipped, task is automatically skipped",
|
||||
"Discovery required: completed task MUST have discoveries/{task_id}.json",
|
||||
"Findings required: completed task MUST have non-null findings",
|
||||
"Error required: failed|skipped task MUST have non-null error",
|
||||
"Supervision fields: CHECKPOINT tasks MUST set supervision_verdict on completion"
|
||||
]
|
||||
},
|
||||
|
||||
"$comment_claude_code_mapping": {
|
||||
"TaskCreate": {
|
||||
"title": "tasks[id].title",
|
||||
"description": "tasks[id].description",
|
||||
"assignee": "tasks[id].role",
|
||||
"status_open": "tasks[id].status = pending",
|
||||
"metadata.deps": "tasks[id].deps",
|
||||
"metadata.wave": "tasks[id].wave"
|
||||
},
|
||||
"TaskUpdate": {
|
||||
"status_in_progress": "Write tasks[id].status = in_progress",
|
||||
"status_completed": "Write tasks[id].status = completed + Write discoveries/{id}.json",
|
||||
"status_failed": "Write tasks[id].status = failed + tasks[id].error"
|
||||
},
|
||||
"team_msg": {
|
||||
"get_state": "Read tasks.json + Read discoveries/{upstream_id}.json",
|
||||
"state_update": "Write discoveries/{task_id}.json",
|
||||
"broadcast": "Write to wisdom/*.md"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,601 +1,203 @@
|
||||
# CLI Tools Execution Specification
|
||||
|
||||
## Table of Contents
|
||||
1. [Configuration Reference](#configuration-reference)
|
||||
2. [Tool Selection](#tool-selection)
|
||||
3. [Prompt Template](#prompt-template)
|
||||
4. [CLI Execution](#cli-execution)
|
||||
5. [Auto-Invoke Triggers](#auto-invoke-triggers)
|
||||
6. [Best Practices](#best-practices)
|
||||
Unified reference for `ccw cli` — runs agent tools (gemini, qwen, codex, claude, opencode) with a shared interface for prompt, mode, model, directory, templates, and session resume.
|
||||
|
||||
**References**: `~/.claude/cli-tools.json` (tool config), `~/.ccw/templates/cli/` (protocol + prompt templates)
|
||||
|
||||
---
|
||||
|
||||
## Configuration Reference
|
||||
## 1. Quick Reference
|
||||
|
||||
### Configuration File
|
||||
### Command Syntax
|
||||
|
||||
**Path**: `~/.claude/cli-tools.json`
|
||||
```bash
|
||||
ccw cli -p "<PROMPT>" [options]
|
||||
```
|
||||
|
||||
All tool availability, model selection, and routing are defined in this configuration file.
|
||||
### Options
|
||||
|
||||
### Configuration Fields
|
||||
| Option | Description | Default |
|
||||
|--------|-------------|---------|
|
||||
| `-p, --prompt` | **Required**. Prompt text | — |
|
||||
| `--tool <name>` | Tool: gemini, qwen, codex, claude, opencode | First enabled in config |
|
||||
| `--mode <mode>` | `analysis` (read-only), `write` (create/modify/delete), `review` (codex-only) | `analysis` |
|
||||
| `--model <model>` | Model override | Tool's `primaryModel` |
|
||||
| `--cd <dir>` | Working directory | Current directory |
|
||||
| `--includeDirs <dirs>` | Additional directories (comma-separated) | — |
|
||||
| `--rule <template>` | Load protocol + prompt template | — (optional) |
|
||||
| `--id <id>` | Execution ID | Auto: `{prefix}-{HHmmss}-{rand4}` |
|
||||
| `--resume [id]` | Resume session (last if no id, comma-separated for merge) | — |
|
||||
|
||||
### Mode Definition (Authoritative)
|
||||
|
||||
| Mode | Permission | Auto-Invoke Safe | Use For |
|
||||
|------|-----------|------------------|---------|
|
||||
| `analysis` | Read-only | Yes | Review, exploration, diagnosis, architecture analysis |
|
||||
| `write` | Create/Modify/Delete | No — requires explicit intent | Implementation, bug fixes, refactoring |
|
||||
| `review` | Read-only (git-aware) | Yes | **Codex only**. Uncommitted changes, branch diffs, specific commits |
|
||||
|
||||
> `--mode` is the **authoritative** permission control for ccw cli. The `MODE:` field inside prompt text is a hint for the agent — both should be consistent, but `--mode` governs actual behavior.
|
||||
|
||||
**Codex review mode**: Target flags (`--uncommitted`, `--base`, `--commit`) are codex-only and mutually exclusive with `-p`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Configuration
|
||||
|
||||
### Config File: `~/.claude/cli-tools.json`
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `enabled` | Tool availability status |
|
||||
| `primaryModel` | Default model for the tool |
|
||||
| `enabled` | Tool availability |
|
||||
| `primaryModel` | Default model |
|
||||
| `secondaryModel` | Fallback model |
|
||||
| `tags` | Capability tags for routing |
|
||||
| `tags` | Capability tags (for caller-side routing) |
|
||||
|
||||
### Tool Types
|
||||
|
||||
| Type | Usage | Capabilities |
|
||||
|------|-------|--------------|
|
||||
| `builtin` | `--tool gemini` | Full (analysis + write tools) |
|
||||
| `cli-wrapper` | `--tool doubao` | Full (analysis + write tools) |
|
||||
| `api-endpoint` | `--tool g25` | **Analysis only** (no file write tools) |
|
||||
| `builtin` | `--tool gemini` | Full (analysis + write) |
|
||||
| `cli-wrapper` | `--tool doubao` | Full (analysis + write) |
|
||||
| `api-endpoint` | `--tool g25` | **Analysis only** (no file write) |
|
||||
|
||||
> **Note**: `api-endpoint` tools only support analysis and code generation responses. They cannot create, modify, or delete files.
|
||||
### Tool Selection
|
||||
|
||||
1. Explicit `--tool` specified → use it (validate enabled)
|
||||
2. No `--tool` → first enabled tool in config order
|
||||
|
||||
### Fallback Chain
|
||||
|
||||
Primary model fails → `secondaryModel` → next enabled tool → first enabled (default).
|
||||
|
||||
---
|
||||
|
||||
## Tool Selection
|
||||
## 3. Prompt Construction
|
||||
|
||||
### Tag-Based Routing
|
||||
### Assembly Order
|
||||
|
||||
Tools are selected based on **tags** defined in the configuration. Use tags to match task requirements to tool capabilities.
|
||||
`ccw cli` builds the final prompt as:
|
||||
|
||||
#### Common Tags
|
||||
1. **Mode protocol** — loaded based on `--mode` (analysis-protocol.md / write-protocol.md)
|
||||
2. **User prompt** — the `-p` value
|
||||
3. **Rule template** — loaded from `--rule` template name (if specified)
|
||||
|
||||
| Tag | Use Case |
|
||||
|-----|----------|
|
||||
| `analysis` | Code review, architecture analysis, exploration |
|
||||
| `implementation` | Feature development, bug fixes |
|
||||
| `documentation` | Doc generation, comments |
|
||||
| `testing` | Test creation, coverage analysis |
|
||||
| `refactoring` | Code restructuring |
|
||||
| `security` | Security audits, vulnerability scanning |
|
||||
|
||||
### Selection Algorithm
|
||||
### Prompt Template (6 Fields)
|
||||
|
||||
```
|
||||
1. Parse task intent → extract required capabilities
|
||||
2. Load cli-tools.json → get enabled tools with tags
|
||||
3. Match tags → filter tools supporting required capabilities
|
||||
4. Select tool → choose by priority (explicit > tag-match > default)
|
||||
5. Select model → use primaryModel, fallback to secondaryModel
|
||||
PURPOSE: [goal] + [why] + [success criteria]
|
||||
TASK: [step 1] | [step 2] | [step 3]
|
||||
MODE: analysis|write
|
||||
CONTEXT: @[file patterns] | Memory: [prior work context]
|
||||
EXPECTED: [output format] + [quality criteria]
|
||||
CONSTRAINTS: [scope limits] | [special requirements]
|
||||
```
|
||||
|
||||
### Selection Decision Tree
|
||||
- **PURPOSE**: What + Why + Success. Not "Analyze code" but "Identify auth vulnerabilities; success = OWASP Top 10 covered"
|
||||
- **TASK**: Specific verbs. Not "Review code" but "Scan for SQL injection | Check XSS | Verify CSRF"
|
||||
- **MODE**: Must match `--mode` flag
|
||||
- **CONTEXT**: File scope + memory from prior work
|
||||
- **EXPECTED**: Deliverable format, not just "Report"
|
||||
- **CONSTRAINTS**: Task-specific limits (vs `--rule` which loads generic templates)
|
||||
|
||||
```
|
||||
┌─ Explicit --tool specified?
|
||||
│ └─→ YES: Use specified tool (validate enabled)
|
||||
│
|
||||
└─ NO: Tag-based selection
|
||||
├─ Task requires tags?
|
||||
│ └─→ Match tools with matching tags
|
||||
│ └─→ Multiple matches? Use first enabled
|
||||
│
|
||||
└─ No tag match?
|
||||
└─→ Use default tool (first enabled in config)
|
||||
```
|
||||
### CONTEXT: File Patterns + Directory
|
||||
|
||||
### Command Structure
|
||||
- `@**/*` — all files in working directory (default)
|
||||
- `@src/**/*.ts` — scoped pattern
|
||||
- `@../shared/**/*` — sibling directory (**requires `--includeDirs`**)
|
||||
|
||||
**Rule**: If CONTEXT uses `@../dir/**/*`, must add `--includeDirs ../dir`.
|
||||
|
||||
```bash
|
||||
# Explicit tool selection
|
||||
ccw cli -p "<PROMPT>" --tool <tool-id> --mode <analysis|write>
|
||||
|
||||
# Model override
|
||||
ccw cli -p "<PROMPT>" --tool <tool-id> --model <model-id> --mode <analysis|write>
|
||||
|
||||
# Code review (codex only - review mode and target flags are invalid for other tools)
|
||||
ccw cli -p "<PROMPT>" --tool codex --mode review
|
||||
ccw cli --tool codex --mode review --commit <hash>
|
||||
|
||||
# Tag-based auto-selection (future)
|
||||
ccw cli -p "<PROMPT>" --tags <tag1,tag2> --mode <analysis|write>
|
||||
# Cross-directory example
|
||||
ccw cli -p "<PROMPT>" --tool gemini --mode analysis \
|
||||
--cd "src/auth" --includeDirs "../shared"
|
||||
```
|
||||
|
||||
### Tool Fallback Chain
|
||||
|
||||
When primary tool fails or is unavailable:
|
||||
1. Check `secondaryModel` for same tool
|
||||
2. Try next enabled tool with matching tags
|
||||
3. Fall back to default enabled tool
|
||||
|
||||
---
|
||||
|
||||
## Prompt Template
|
||||
|
||||
### Universal Prompt Template
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: [what] + [why] + [success criteria] + [constraints/scope]
|
||||
TASK: • [step 1: specific action] • [step 2: specific action] • [step 3: specific action]
|
||||
MODE: [analysis|write]
|
||||
CONTEXT: @[file patterns] | Memory: [session/tech/module context]
|
||||
EXPECTED: [deliverable format] + [quality criteria] + [structure requirements]
|
||||
CONSTRAINTS: [domain constraints]" --tool <tool-id> --mode <analysis|write> --rule <category-template>
|
||||
```
|
||||
|
||||
### Intent Capture Checklist (Before CLI Execution)
|
||||
|
||||
**⚠️ CRITICAL**: Before executing any CLI command, verify these intent dimensions:
|
||||
|
||||
**Intent Validation Questions**:
|
||||
- [ ] Is the objective specific and measurable?
|
||||
- [ ] Are success criteria defined?
|
||||
- [ ] Is the scope clearly bounded?
|
||||
- [ ] Are constraints and limitations stated?
|
||||
- [ ] Is the expected output format clear?
|
||||
- [ ] Is the action level (read/write) explicit?
|
||||
|
||||
### Template Structure
|
||||
|
||||
Every command MUST include these fields:
|
||||
|
||||
- **PURPOSE**
|
||||
- Purpose: Goal + motivation + success
|
||||
- Components: What + Why + Success Criteria + Constraints
|
||||
- Bad Example: "Analyze code"
|
||||
- Good Example: "Identify security vulnerabilities in auth module to pass compliance audit; success = all OWASP Top 10 addressed; scope = src/auth/** only"
|
||||
|
||||
- **TASK**
|
||||
- Purpose: Actionable steps
|
||||
- Components: Specific verbs + targets
|
||||
- Bad Example: "• Review code • Find issues"
|
||||
- Good Example: "• Scan for SQL injection in query builders • Check XSS in template rendering • Verify CSRF token validation"
|
||||
|
||||
- **MODE**
|
||||
- Purpose: Permission level
|
||||
- Components: analysis / write / auto
|
||||
- Bad Example: (missing)
|
||||
- Good Example: "analysis" or "write"
|
||||
|
||||
- **CONTEXT**
|
||||
- Purpose: File scope + history
|
||||
- Components: File patterns + Memory
|
||||
- Bad Example: "@**/*"
|
||||
- Good Example: "@src/auth/**/*.ts @shared/utils/security.ts \| Memory: Previous auth refactoring (WFS-001)"
|
||||
|
||||
- **EXPECTED**
|
||||
- Purpose: Output specification
|
||||
- Components: Format + Quality + Structure
|
||||
- Bad Example: "Report"
|
||||
- Good Example: "Markdown report with: severity levels (Critical/High/Medium/Low), file:line references, remediation code snippets, priority ranking"
|
||||
|
||||
- **CONSTRAINTS**
|
||||
- Purpose: Domain-specific constraints
|
||||
- Components: Scope limits, special requirements, focus areas
|
||||
- Bad Example: (missing or too vague)
|
||||
- Good Example: "Focus on authentication | Ignore test files | No breaking changes"
|
||||
|
||||
### CONTEXT Configuration
|
||||
|
||||
**Format**: `CONTEXT: [file patterns] | Memory: [memory context]`
|
||||
|
||||
#### File Patterns
|
||||
|
||||
- **`@**/*`**: All files (default)
|
||||
- **`@src/**/*.ts`**: TypeScript in src
|
||||
- **`@../shared/**/*`**: Sibling directory (requires `--includeDirs`)
|
||||
- **`@CLAUDE.md`**: Specific file
|
||||
|
||||
#### Memory Context
|
||||
### CONTEXT: Memory
|
||||
|
||||
Include when building on previous work:
|
||||
|
||||
```bash
|
||||
# Cross-task reference
|
||||
```
|
||||
Memory: Building on auth refactoring (commit abc123), implementing refresh tokens
|
||||
|
||||
# Cross-module integration
|
||||
Memory: Integration with auth module, using shared error patterns from @shared/utils/errors.ts
|
||||
Memory: Integration with auth module, using shared error patterns
|
||||
```
|
||||
|
||||
**Memory Sources**:
|
||||
- **Related Tasks**: Previous refactoring, extensions, conflict resolution
|
||||
- **Tech Stack Patterns**: Framework conventions, security guidelines
|
||||
- **Cross-Module References**: Integration points, shared utilities, type dependencies
|
||||
### --rule Templates
|
||||
|
||||
#### Pattern Discovery Workflow
|
||||
**Universal**: `universal-rigorous-style`, `universal-creative-style`
|
||||
|
||||
For complex requirements, discover files BEFORE CLI execution:
|
||||
**Analysis**: `analysis-trace-code-execution`, `analysis-diagnose-bug-root-cause`, `analysis-analyze-code-patterns`, `analysis-analyze-technical-document`, `analysis-review-architecture`, `analysis-review-code-quality`, `analysis-analyze-performance`, `analysis-assess-security-risks`
|
||||
|
||||
**Planning**: `planning-plan-architecture-design`, `planning-breakdown-task-steps`, `planning-design-component-spec`, `planning-plan-migration-strategy`
|
||||
|
||||
**Development**: `development-implement-feature`, `development-refactor-codebase`, `development-generate-tests`, `development-implement-component-ui`, `development-debug-runtime-issues`
|
||||
|
||||
### Complete Example
|
||||
|
||||
```bash
|
||||
# Step 1: Discover files (choose one method)
|
||||
# Method A: ACE semantic search (recommended)
|
||||
mcp__ace-tool__search_context(project_root_path="/path", query="React components with export")
|
||||
|
||||
# Method B: Ripgrep pattern search
|
||||
rg "export.*Component" --files-with-matches --type ts
|
||||
|
||||
# Step 2: Build CONTEXT
|
||||
CONTEXT: @components/Auth.tsx @types/auth.d.ts | Memory: Previous type refactoring
|
||||
|
||||
# Step 3: Execute CLI
|
||||
ccw cli -p "..." --tool <tool-id> --mode analysis --cd "src"
|
||||
```
|
||||
|
||||
### --rule Configuration
|
||||
|
||||
**Use `--rule` option to auto-load templates**:
|
||||
|
||||
```bash
|
||||
ccw cli -p "..." --tool gemini --mode analysis --rule analysis-review-architecture
|
||||
```
|
||||
|
||||
### Mode Protocol References
|
||||
|
||||
**`--rule` auto-loads Protocol based on mode**:
|
||||
- `--mode analysis` → analysis-protocol.md
|
||||
- `--mode write` → write-protocol.md
|
||||
|
||||
**Protocol Mapping**:
|
||||
|
||||
- **`analysis`** mode
|
||||
- Permission: Read-only
|
||||
- Constraint: No file create/modify/delete
|
||||
|
||||
- **`write`** mode
|
||||
- Permission: Create/Modify/Delete files
|
||||
- Constraint: Full workflow execution
|
||||
|
||||
### Template System
|
||||
|
||||
**Available `--rule` template names**:
|
||||
|
||||
**Universal**:
|
||||
- `universal-rigorous-style` - Precise tasks
|
||||
- `universal-creative-style` - Exploratory tasks
|
||||
|
||||
**Analysis**:
|
||||
- `analysis-trace-code-execution` - Execution tracing
|
||||
- `analysis-diagnose-bug-root-cause` - Bug diagnosis
|
||||
- `analysis-analyze-code-patterns` - Code patterns
|
||||
- `analysis-analyze-technical-document` - Document analysis
|
||||
- `analysis-review-architecture` - Architecture review
|
||||
- `analysis-review-code-quality` - Code review
|
||||
- `analysis-analyze-performance` - Performance analysis
|
||||
- `analysis-assess-security-risks` - Security assessment
|
||||
|
||||
**Planning**:
|
||||
- `planning-plan-architecture-design` - Architecture design
|
||||
- `planning-breakdown-task-steps` - Task breakdown
|
||||
- `planning-design-component-spec` - Component design
|
||||
- `planning-plan-migration-strategy` - Migration strategy
|
||||
|
||||
**Development**:
|
||||
- `development-implement-feature` - Feature implementation
|
||||
- `development-refactor-codebase` - Code refactoring
|
||||
- `development-generate-tests` - Test generation
|
||||
- `development-implement-component-ui` - UI component
|
||||
- `development-debug-runtime-issues` - Runtime debugging
|
||||
|
||||
---
|
||||
|
||||
## CLI Execution
|
||||
|
||||
### MODE Options
|
||||
|
||||
- **`analysis`**
|
||||
- Permission: Read-only
|
||||
- Use For: Code review, architecture analysis, pattern discovery, exploration
|
||||
- Specification: Safe for all tools
|
||||
|
||||
- **`write`**
|
||||
- Permission: Create/Modify/Delete
|
||||
- Use For: Feature implementation, bug fixes, documentation, code creation, file modifications
|
||||
- Specification: Requires explicit `--mode write`
|
||||
|
||||
- **`review`**
|
||||
- Permission: Read-only (code review output)
|
||||
- Use For: Git-aware code review of uncommitted changes, branch diffs, specific commits
|
||||
- Specification: **codex only** - uses `codex review` subcommand. Other tools MUST NOT use this mode
|
||||
- **Constraint**: Target flags (`--uncommitted`, `--base`, `--commit`) are **codex-only** and mutually exclusive with prompt
|
||||
- With prompt only: `ccw cli -p "Focus on security" --tool codex --mode review` (reviews uncommitted by default)
|
||||
- With target flag only: `ccw cli --tool codex --mode review --commit abc123` (no prompt allowed)
|
||||
|
||||
### Command Options
|
||||
|
||||
- **`--tool <tool>`**
|
||||
- Description: Tool from config (e.g., gemini, qwen, codex)
|
||||
- Default: First enabled tool in config
|
||||
|
||||
- **`--mode <mode>`**
|
||||
- Description: **REQUIRED**: analysis, write, review
|
||||
- Default: **NONE** (must specify)
|
||||
- Note: `review` mode is **codex-only**. Using `--mode review` with other tools (gemini/qwen/claude) is invalid and should be rejected
|
||||
|
||||
- **`--model <model>`**
|
||||
- Description: Model override
|
||||
- Default: Tool's primaryModel from config
|
||||
|
||||
- **`--cd "<path>"`**
|
||||
- Description: Working directory (quote if path contains spaces)
|
||||
- Default: current
|
||||
|
||||
- **`--includeDirs "<dirs>"`**
|
||||
- Description: Additional directories (comma-separated, quote if paths contain spaces)
|
||||
- Default: none
|
||||
|
||||
- **`--id <id>`**
|
||||
- Description: Execution ID (recommended, auto-generated if omitted)
|
||||
- Default: Auto-generated in format `{prefix}-{HHmmss}-{rand4}` (e.g., `gem-143022-x7k2`)
|
||||
- Prefix mapping: gemini→gem, qwen→qwn, codex→cdx, claude→cld, opencode→opc
|
||||
- Note: ID is always output to stderr as `[CCW_EXEC_ID=<id>]` for programmatic capture
|
||||
|
||||
- **`--resume [id]`**
|
||||
- Description: Resume previous session
|
||||
- Default: -
|
||||
|
||||
- **`--rule <template>`**
|
||||
- Description: Template name, auto-loads protocol + template appended to prompt
|
||||
- Default: universal-rigorous-style
|
||||
- Auto-selects protocol based on --mode
|
||||
|
||||
### Directory Configuration
|
||||
|
||||
#### Working Directory (`--cd`)
|
||||
|
||||
When using `--cd`:
|
||||
- `@**/*` = Files within working directory tree only
|
||||
- CANNOT reference parent/sibling via @ alone
|
||||
- Must use `--includeDirs` for external directories
|
||||
|
||||
#### Include Directories (`--includeDirs`)
|
||||
|
||||
**TWO-STEP requirement for external files**:
|
||||
1. Add `--includeDirs` parameter
|
||||
2. Reference in CONTEXT with @ patterns
|
||||
|
||||
```bash
|
||||
# Single directory
|
||||
ccw cli -p "CONTEXT: @**/* @../shared/**/*" --tool <tool-id> --mode analysis --cd "src/auth" --includeDirs "../shared"
|
||||
|
||||
# Multiple directories
|
||||
ccw cli -p "..." --tool <tool-id> --mode analysis --cd "src/auth" --includeDirs "../shared,../types,../utils"
|
||||
```
|
||||
|
||||
**Rule**: If CONTEXT contains `@../dir/**/*`, MUST include `--includeDirs ../dir`
|
||||
|
||||
**Benefits**: Excludes unrelated directories, reduces token usage
|
||||
|
||||
### Session Resume
|
||||
|
||||
**When to Use**:
|
||||
- Multi-round planning (analysis → planning → implementation)
|
||||
- Multi-model collaboration (tool A → tool B on same topic)
|
||||
- Topic continuity (building on previous findings)
|
||||
|
||||
**Usage**:
|
||||
|
||||
```bash
|
||||
ccw cli -p "Continue analyzing" --tool <tool-id> --mode analysis --resume # Resume last
|
||||
ccw cli -p "Fix issues found" --tool <tool-id> --mode write --resume <id> # Resume specific
|
||||
ccw cli -p "Merge findings" --tool <tool-id> --mode analysis --resume <id1>,<id2> # Merge multiple
|
||||
```
|
||||
|
||||
- **`--resume`**: Last session
|
||||
- **`--resume <id>`**: Specific session
|
||||
- **`--resume <id1>,<id2>`**: Merge sessions (comma-separated)
|
||||
|
||||
**Context Assembly** (automatic):
|
||||
```
|
||||
=== PREVIOUS CONVERSATION ===
|
||||
USER PROMPT: [Previous prompt]
|
||||
ASSISTANT RESPONSE: [Previous output]
|
||||
=== CONTINUATION ===
|
||||
[Your new prompt]
|
||||
```
|
||||
|
||||
### Subcommands
|
||||
|
||||
#### `show` — List All Executions
|
||||
|
||||
```bash
|
||||
ccw cli show # Active + recent completed executions
|
||||
ccw cli show --all # Include full history
|
||||
```
|
||||
|
||||
Displays a unified table of running and recent executions with: ID, Tool, Mode, Status, Duration, Prompt Preview.
|
||||
|
||||
#### `watch <id>` — Stream Execution Output
|
||||
|
||||
```bash
|
||||
ccw cli watch <id> # Stream until completion (output to stderr)
|
||||
ccw cli watch <id> --timeout 120 # Auto-exit after 120 seconds
|
||||
```
|
||||
|
||||
Behavior:
|
||||
- Output written to **stderr** (does not pollute stdout)
|
||||
- Exit code: 0 = success, 1 = error, 2 = timeout
|
||||
- Callers can `ccw cli watch <id> 2>/dev/null` to silently wait
|
||||
|
||||
#### `output <id>` — Get Execution Output
|
||||
|
||||
```bash
|
||||
ccw cli output <id> # Final result only (default)
|
||||
ccw cli output <id> --verbose # Full metadata + raw output
|
||||
ccw cli output <id> --raw # Raw stdout (for piping)
|
||||
```
|
||||
|
||||
Default returns `finalOutput > parsedOutput > stdout` — agent's final response text only.
|
||||
`--verbose` shows full metadata (ID, turn, status, project) plus raw stdout/stderr.
|
||||
|
||||
#### ID Workflow Example
|
||||
|
||||
```bash
|
||||
# Execute with auto-generated ID
|
||||
ccw cli -p "analyze code" --tool gemini --mode analysis
|
||||
# stderr outputs: [CCW_EXEC_ID=gem-143022-x7k2]
|
||||
|
||||
# Execute with custom ID
|
||||
ccw cli -p "implement feature" --tool gemini --mode write --id my-task-1
|
||||
# stderr outputs: [CCW_EXEC_ID=my-task-1]
|
||||
|
||||
# Check status
|
||||
ccw cli show
|
||||
|
||||
# Watch running execution
|
||||
ccw cli watch gem-143022-x7k2
|
||||
|
||||
# Get final result
|
||||
ccw cli output gem-143022-x7k2
|
||||
|
||||
# Capture ID programmatically
|
||||
EXEC_ID=$(ccw cli -p "test" --tool gemini --mode analysis 2>&1 | grep -oP 'CCW_EXEC_ID=\K[^\]]+')
|
||||
ccw cli output $EXEC_ID
|
||||
```
|
||||
|
||||
### Command Examples
|
||||
|
||||
#### Task-Type Specific Templates
|
||||
|
||||
**Analysis Task** (Security Audit):
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Identify OWASP Top 10 vulnerabilities in authentication module to pass security audit; success = all critical/high issues documented with remediation
|
||||
TASK: • Scan for injection flaws (SQL, command, LDAP) • Check authentication bypass vectors • Evaluate session management • Assess sensitive data exposure
|
||||
ccw cli -p "PURPOSE: Identify OWASP Top 10 vulnerabilities in auth module; success = all critical/high documented with remediation
|
||||
TASK: Scan for injection flaws | Check auth bypass vectors | Evaluate session management | Assess data exposure
|
||||
MODE: analysis
|
||||
CONTEXT: @src/auth/**/* @src/middleware/auth.ts | Memory: Using bcrypt for passwords, JWT for sessions
|
||||
EXPECTED: Security report with: severity matrix, file:line references, CVE mappings where applicable, remediation code snippets prioritized by risk
|
||||
CONTEXT: @src/auth/**/* @src/middleware/auth.ts | Memory: Using bcrypt + JWT
|
||||
EXPECTED: Severity matrix, file:line references, remediation snippets, priority ranking
|
||||
CONSTRAINTS: Focus on authentication | Ignore test files
|
||||
" --tool gemini --mode analysis --rule analysis-assess-security-risks --cd "src/auth"
|
||||
```
|
||||
|
||||
**Implementation Task** (New Feature):
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Implement rate limiting for API endpoints to prevent abuse; must be configurable per-endpoint; backward compatible with existing clients
|
||||
TASK: • Create rate limiter middleware with sliding window • Implement per-route configuration • Add Redis backend for distributed state • Include bypass for internal services
|
||||
MODE: write
|
||||
CONTEXT: @src/middleware/**/* @src/config/**/* | Memory: Using Express.js, Redis already configured, existing middleware pattern in auth.ts
|
||||
EXPECTED: Production-ready code with: TypeScript types, unit tests, integration test, configuration example, migration guide
|
||||
CONSTRAINTS: Follow existing middleware patterns | No breaking changes
|
||||
" --tool gemini --mode write --rule development-implement-feature
|
||||
```
|
||||
|
||||
**Bug Fix Task**:
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Fix memory leak in WebSocket connection handler causing server OOM after 24h; root cause must be identified before any fix
|
||||
TASK: • Trace connection lifecycle from open to close • Identify event listener accumulation • Check cleanup on disconnect • Verify garbage collection eligibility
|
||||
MODE: analysis
|
||||
CONTEXT: @src/websocket/**/* @src/services/connection-manager.ts | Memory: Using ws library, ~5000 concurrent connections in production
|
||||
EXPECTED: Root cause analysis with: memory profile, leak source (file:line), fix recommendation with code, verification steps
|
||||
CONSTRAINTS: Focus on resource cleanup
|
||||
" --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause --cd "src"
|
||||
```
|
||||
|
||||
**Refactoring Task**:
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Refactor payment processing to use strategy pattern for multi-gateway support; no functional changes; all existing tests must pass
|
||||
TASK: • Extract gateway interface from current implementation • Create strategy classes for Stripe, PayPal • Implement factory for gateway selection • Migrate existing code to use strategies
|
||||
MODE: write
|
||||
CONTEXT: @src/payments/**/* @src/types/payment.ts | Memory: Currently only Stripe, adding PayPal next sprint, must support future gateways
|
||||
EXPECTED: Refactored code with: strategy interface, concrete implementations, factory class, updated tests, migration checklist
|
||||
CONSTRAINTS: Preserve all existing behavior | Tests must pass
|
||||
" --tool gemini --mode write --rule development-refactor-codebase
|
||||
```
|
||||
|
||||
**Code Review Task** (codex review mode):
|
||||
```bash
|
||||
# Option 1: Custom prompt (reviews uncommitted changes by default)
|
||||
ccw cli -p "Focus on security vulnerabilities and error handling" --tool codex --mode review
|
||||
|
||||
# Option 2: Target flag only (no prompt allowed with target flags)
|
||||
ccw cli --tool codex --mode review --uncommitted
|
||||
ccw cli --tool codex --mode review --base main
|
||||
ccw cli --tool codex --mode review --commit abc123
|
||||
```
|
||||
|
||||
> **Note**: `--mode review` and target flags (`--uncommitted`, `--base`, `--commit`) are **codex-only**. Using them with other tools is invalid. When using codex, target flags and prompt are **mutually exclusive** - use one or the other, not both.
|
||||
|
||||
---
|
||||
|
||||
### Permission Framework
|
||||
## 4. Execution
|
||||
|
||||
**Single-Use Authorization**: Each execution requires explicit user instruction. Previous authorization does NOT carry over.
|
||||
### Execution ID
|
||||
|
||||
**Mode Hierarchy**:
|
||||
- `analysis`: Read-only, safe for auto-execution. Available for all tools
|
||||
- `write`: Create/Modify/Delete files, full operations - requires explicit `--mode write`. Available for all tools
|
||||
- `review`: **codex-only**. Git-aware code review, read-only output. Invalid for other tools (gemini/qwen/claude)
|
||||
- **Exception**: User provides clear instructions like "modify", "create", "implement"
|
||||
ID prefix: gemini→`gem`, qwen→`qwn`, codex→`cdx`, claude→`cld`, opencode→`opc`
|
||||
|
||||
---
|
||||
|
||||
## Auto-Invoke Triggers
|
||||
|
||||
**Proactive CLI invocation** - Auto-invoke `ccw cli` when encountering these scenarios:
|
||||
|
||||
| Trigger Condition | Suggested Rule | When to Use |
|
||||
|-------------------|----------------|-------------|
|
||||
| **Self-repair fails** | `analysis-diagnose-bug-root-cause` | After 1+ failed fix attempts |
|
||||
| **Ambiguous requirements** | `planning-breakdown-task-steps` | Task description lacks clarity |
|
||||
| **Architecture decisions** | `planning-plan-architecture-design` | Complex feature needs design |
|
||||
| **Pattern uncertainty** | `analysis-analyze-code-patterns` | Unsure of existing conventions |
|
||||
| **Critical code paths** | `analysis-assess-security-risks` | Security/performance sensitive |
|
||||
|
||||
### Execution Principles
|
||||
|
||||
- **Default mode**: `--mode analysis` (read-only, safe for auto-execution)
|
||||
- **No confirmation needed**: Invoke proactively when triggers match
|
||||
- **Wait for results**: Complete analysis before next action
|
||||
- **Tool selection**: Use context-appropriate tool or fallback chain (`gemini` → `qwen` → `codex`)
|
||||
- **Rule flexibility**: Suggested rules are guidelines, not requirements - choose the most appropriate template for the situation
|
||||
|
||||
### Example: Bug Fix with Auto-Invoke
|
||||
Output to stderr: `[CCW_EXEC_ID=<id>]`
|
||||
|
||||
```bash
|
||||
# After 1+ failed fix attempts, auto-invoke root cause analysis
|
||||
ccw cli -p "PURPOSE: Identify root cause of [bug description]; success = actionable fix strategy
|
||||
TASK: • Trace execution flow • Identify failure point • Analyze state at failure • Determine fix approach
|
||||
MODE: analysis
|
||||
CONTEXT: @src/module/**/* | Memory: Previous fix attempts failed at [location]
|
||||
EXPECTED: Root cause analysis with: failure mechanism, stack trace interpretation, fix recommendation with code
|
||||
CONSTRAINTS: Focus on [specific area]
|
||||
" --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause
|
||||
ccw cli -p "<PROMPT>" --tool gemini --mode analysis # auto-ID: gem-143022-a7f2
|
||||
ccw cli -p "<PROMPT>" --tool gemini --mode write --id my-task-1 # custom ID
|
||||
```
|
||||
|
||||
### Session Resume
|
||||
|
||||
```bash
|
||||
ccw cli -p "<PROMPT>" --tool gemini --resume # last session
|
||||
ccw cli -p "<PROMPT>" --tool gemini --mode write --resume <id> # specific
|
||||
ccw cli -p "<PROMPT>" --tool gemini --resume <id1>,<id2> # merge multiple
|
||||
```
|
||||
|
||||
Resume auto-assembles previous conversation context. Warning emitted when context exceeds 32KB.
|
||||
|
||||
### Subcommands
|
||||
|
||||
```bash
|
||||
ccw cli show # active + recent executions
|
||||
ccw cli show --all # full history
|
||||
ccw cli watch <id> # stream until completion (stderr)
|
||||
ccw cli output <id> # final assistant output
|
||||
ccw cli output <id> --verbose # full metadata + output
|
||||
ccw cli output <id> --raw # raw stdout (for piping)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
## 5. Auto-Invoke Triggers
|
||||
|
||||
### Core Principles
|
||||
Proactively invoke `ccw cli` when these conditions are met — no user confirmation needed for `analysis` mode:
|
||||
|
||||
- **Configuration-driven** - All tool selection from `cli-tools.json`
|
||||
- **Tag-based routing** - Match task requirements to tool capabilities
|
||||
- **Use tools early and often** - Tools are faster and more thorough
|
||||
- **Unified CLI** - Always use `ccw cli -p` for consistent parameter handling
|
||||
- **Default mode is analysis** - Omit `--mode` for read-only operations, explicitly use `--mode write` for file modifications
|
||||
- **Use `--rule` for templates** - Auto-loads protocol + template appended to prompt
|
||||
- **Write protection** - Require EXPLICIT `--mode write` for file operations
|
||||
| Trigger | Suggested Rule |
|
||||
|---------|---------------|
|
||||
| Self-repair fails (1+ attempts) | `analysis-diagnose-bug-root-cause` |
|
||||
| Ambiguous requirements | `planning-breakdown-task-steps` |
|
||||
| Architecture decisions needed | `planning-plan-architecture-design` |
|
||||
| Pattern uncertainty | `analysis-analyze-code-patterns` |
|
||||
| Critical/security code paths | `analysis-assess-security-risks` |
|
||||
|
||||
### Workflow Principles
|
||||
### Principles
|
||||
|
||||
- **Use CCW unified interface** for all executions
|
||||
- **Always include template** - Use `--rule <template-name>` to load templates
|
||||
- **Be specific** - Clear PURPOSE, TASK, EXPECTED fields
|
||||
- **Include constraints** - File patterns, scope in CONSTRAINTS
|
||||
- **Leverage memory context** when building on previous work
|
||||
- **Discover patterns first** - Use rg/MCP before CLI execution
|
||||
- **Default to full context** - Use `@**/*` unless specific files needed
|
||||
|
||||
### Planning Checklist
|
||||
|
||||
- [ ] **Purpose defined** - Clear goal and intent
|
||||
- [ ] **Mode selected** - `--mode analysis|write|review`
|
||||
- [ ] **Context gathered** - File references + memory (default `@**/*`)
|
||||
- [ ] **Directory navigation** - `--cd` and/or `--includeDirs`
|
||||
- [ ] **Tool selected** - Explicit `--tool` or tag-based auto-selection
|
||||
- [ ] **Rule template** - `--rule <template-name>` loads template
|
||||
- [ ] **Constraints** - Domain constraints in CONSTRAINTS field
|
||||
|
||||
### Execution Workflow
|
||||
|
||||
1. **Load configuration** - Read `cli-tools.json` for available tools
|
||||
2. **Match by tags** - Select tool based on task requirements
|
||||
3. **Validate enabled** - Ensure selected tool is enabled
|
||||
4. **Execute with mode** - Always specify `--mode analysis|write|review`
|
||||
5. **Fallback gracefully** - Use secondary model or next matching tool on failure
|
||||
- Default `--mode analysis` (safe, read-only)
|
||||
- Wait for results before next action
|
||||
- Tool fallback: `gemini` → `qwen` → `codex`
|
||||
- Rule suggestions are guidelines — choose the best fit
|
||||
|
||||
@@ -36,6 +36,26 @@ Available CLI endpoints are dynamically defined by the config file
|
||||
- **Key scenarios**: Self-repair fails, ambiguous requirements, architecture decisions, pattern uncertainty, critical code paths
|
||||
- **Principles**: Default `--mode analysis`, no confirmation needed, wait for completion, flexible rule selection
|
||||
|
||||
## Workflow Session Awareness
|
||||
|
||||
### Artifact Locations
|
||||
|
||||
| Workflow | Directory | Summary File |
|
||||
|----------|-----------|-------------|
|
||||
| `workflow-plan` | `.workflow/active/WFS-*/` | `workflow-session.json` |
|
||||
| `workflow-lite-plan` | `.workflow/.lite-plan/{slug}-{date}/` | `plan.json` |
|
||||
| `analyze-with-file` | `.workflow/.analysis/ANL-*/` | `conclusions.json` |
|
||||
| `multi-cli-plan` | `.workflow/.multi-cli-plan/*/` | `session-state.json` |
|
||||
| `lite-fix` | `.workflow/.lite-fix/*/` | `fix-plan.json` |
|
||||
| Other | `.workflow/.debug/`, `.workflow/.scratchpad/`, `.workflow/archives/` | — |
|
||||
|
||||
### Pre-Task Discovery
|
||||
|
||||
Before starting any workflow skill, scan recent sessions (7 days) to avoid conflicts and reuse prior work:
|
||||
- If overlapping file scope found: warn user, suggest `--continue` or reference prior session
|
||||
- If complementary: feed prior findings into new session context
|
||||
- `memory/MEMORY.md` for cross-session knowledge; `.workflow/` for session-specific artifacts — reference session IDs, don't duplicate
|
||||
|
||||
## Code Diagnostics
|
||||
|
||||
- **Prefer `mcp__ide__getDiagnostics`** for code error checking over shell-based TypeScript compilation
|
||||
|
||||
@@ -829,6 +829,12 @@ Generate at `.workflow/active/{session_id}/plan.json` following `plan-overview-b
|
||||
|
||||
**Generation Timing**: After all `.task/IMPL-*.json` files are generated, aggregate into plan.json.
|
||||
|
||||
**Validation**: After writing plan.json and task files, validate with json_builder:
|
||||
```bash
|
||||
ccw tool exec json_builder '{"cmd":"validate","target":"<session>/plan.json","schema":"plan"}'
|
||||
ccw tool exec json_builder '{"cmd":"validate","target":"<session>/.task/IMPL-001.json","schema":"task"}'
|
||||
```
|
||||
|
||||
### 2.3 IMPL_PLAN.md Structure
|
||||
|
||||
**Template-Based Generation**:
|
||||
|
||||
@@ -5,6 +5,7 @@ description: |
|
||||
Orchestrates 4-phase workflow: Task Understanding → Analysis Execution → Schema Validation → Output Generation.
|
||||
Spawned by /explore command orchestrator.
|
||||
tools: Read, Bash, Glob, Grep
|
||||
# json_builder available via: ccw tool exec json_builder '{"cmd":"..."}' (Bash)
|
||||
color: yellow
|
||||
---
|
||||
|
||||
@@ -66,9 +67,9 @@ Phase 4: Output Generation
|
||||
Store result as `project_structure` for module-aware file discovery in Phase 2.
|
||||
|
||||
2. **Output Schema Loading** (if output file path specified in prompt):
|
||||
- Exploration output → `cat ~/.ccw/workflows/cli-templates/schemas/explore-json-schema.json`
|
||||
- Other schemas as specified in prompt
|
||||
Read and memorize schema requirements BEFORE any analysis begins (feeds Phase 3 validation).
|
||||
- Get schema summary: `ccw tool exec json_builder '{"cmd":"info","schema":"explore"}'` (or "diagnosis" for bug analysis)
|
||||
- Initialize output file: `ccw tool exec json_builder '{"cmd":"init","schema":"explore","output":"<output_path>"}'`
|
||||
- The tool returns requiredFields, arrayFields, and enumFields — memorize these for Phase 2.
|
||||
|
||||
3. **Project Context Loading** (from spec system):
|
||||
- Load exploration specs using: `ccw spec load --category exploration`
|
||||
@@ -150,55 +151,56 @@ RULES: {from prompt, if template specified} | analysis=READ-ONLY
|
||||
---
|
||||
|
||||
<schema_validation>
|
||||
## Phase 3: Schema Validation
|
||||
## Phase 3: Incremental Build & Validation (via json_builder)
|
||||
|
||||
### CRITICAL: Schema Compliance Protocol
|
||||
**This phase replaces manual JSON writing + self-validation with tool-assisted construction.**
|
||||
|
||||
**This phase is MANDATORY when schema file is specified in prompt.**
|
||||
|
||||
**Step 1: Read Schema FIRST**
|
||||
```
|
||||
Read(schema_file_path)
|
||||
**Step 1: Set text fields** (discovered during Phase 2 analysis)
|
||||
```bash
|
||||
ccw tool exec json_builder '{"cmd":"set","target":"<output_path>","ops":[
|
||||
{"path":"project_structure","value":"..."},
|
||||
{"path":"patterns","value":"..."},
|
||||
{"path":"dependencies","value":"..."},
|
||||
{"path":"integration_points","value":"..."},
|
||||
{"path":"constraints","value":"..."}
|
||||
]}'
|
||||
```
|
||||
|
||||
**Step 2: Extract Schema Requirements**
|
||||
**Step 2: Append file entries** (as discovered — one `set` per batch)
|
||||
```bash
|
||||
ccw tool exec json_builder '{"cmd":"set","target":"<output_path>","ops":[
|
||||
{"path":"relevant_files[+]","value":{"path":"src/auth.ts","relevance":0.9,"rationale":"Contains AuthService.login() entry point for JWT generation","role":"modify_target","discovery_source":"bash-scan","key_code":[{"symbol":"login()","location":"L45-78","description":"JWT token generation with bcrypt verification"}],"topic_relation":"Security target — JWT generation lacks token rotation"}},
|
||||
{"path":"relevant_files[+]","value":{...}}
|
||||
]}'
|
||||
```
|
||||
|
||||
Parse and memorize:
|
||||
1. **Root structure** - Is it array `[...]` or object `{...}`?
|
||||
2. **Required fields** - List all `"required": [...]` arrays
|
||||
3. **Field names EXACTLY** - Copy character-by-character (case-sensitive)
|
||||
4. **Enum values** - Copy exact strings (e.g., `"critical"` not `"Critical"`)
|
||||
5. **Nested structures** - Note flat vs nested requirements
|
||||
The tool **automatically validates** each operation:
|
||||
- enum values (role, discovery_source) → rejects invalid
|
||||
- minLength (rationale >= 10) → rejects too short
|
||||
- type checking → rejects wrong types
|
||||
|
||||
**Step 3: File Rationale Validation** (MANDATORY for relevant_files / affected_files)
|
||||
**Step 3: Set metadata**
|
||||
```bash
|
||||
ccw tool exec json_builder '{"cmd":"set","target":"<output_path>","ops":[
|
||||
{"path":"_metadata.timestamp","value":"auto"},
|
||||
{"path":"_metadata.task_description","value":"..."},
|
||||
{"path":"_metadata.source","value":"cli-explore-agent"},
|
||||
{"path":"_metadata.exploration_angle","value":"..."},
|
||||
{"path":"_metadata.exploration_index","value":1},
|
||||
{"path":"_metadata.total_explorations","value":2}
|
||||
]}'
|
||||
```
|
||||
|
||||
Every file entry MUST have:
|
||||
- `rationale` (required, minLength 10): Specific reason tied to the exploration topic, NOT generic
|
||||
- GOOD: "Contains AuthService.login() which is the entry point for JWT token generation"
|
||||
- BAD: "Related to auth" or "Relevant file"
|
||||
- `role` (required, enum): Structural classification of why it was selected
|
||||
- `discovery_source` (optional but recommended): How the file was found
|
||||
- `key_code` (strongly recommended for relevance >= 0.7): Array of {symbol, location?, description}
|
||||
- GOOD: [{"symbol": "AuthService.login()", "location": "L45-L78", "description": "JWT token generation with bcrypt verification, returns token pair"}]
|
||||
- BAD: [{"symbol": "login", "description": "login function"}]
|
||||
- `topic_relation` (strongly recommended for relevance >= 0.7): Connection from exploration angle perspective
|
||||
- GOOD: "Security exploration targets this file because JWT generation lacks token rotation"
|
||||
- BAD: "Related to security"
|
||||
**Step 4: Final validation**
|
||||
```bash
|
||||
ccw tool exec json_builder '{"cmd":"validate","target":"<output_path>"}'
|
||||
```
|
||||
Returns `{valid, errors, warnings, stats}`. If errors exist → fix with `set` → re-validate.
|
||||
|
||||
**Step 4: Pre-Output Validation Checklist**
|
||||
|
||||
Before writing ANY JSON output, verify:
|
||||
|
||||
- [ ] Root structure matches schema (array vs object)
|
||||
- [ ] ALL required fields present at each level
|
||||
- [ ] Field names EXACTLY match schema (character-by-character)
|
||||
- [ ] Enum values EXACTLY match schema (case-sensitive)
|
||||
- [ ] Nested structures follow schema pattern (flat vs nested)
|
||||
- [ ] Data types correct (string, integer, array, object)
|
||||
- [ ] Every file in relevant_files has: path + relevance + rationale + role
|
||||
- [ ] Every rationale is specific (>10 chars, not generic)
|
||||
- [ ] Files with relevance >= 0.7 have key_code with symbol + description (minLength 10)
|
||||
- [ ] Files with relevance >= 0.7 have topic_relation explaining connection to angle (minLength 15)
|
||||
**Quality reminders** (enforced by tool, but be aware):
|
||||
- `rationale`: Must be specific, not generic ("Related to auth" → rejected by semantic check)
|
||||
- `key_code`: Strongly recommended for relevance >= 0.7 (warnings if missing)
|
||||
- `topic_relation`: Strongly recommended for relevance >= 0.7 (warnings if missing)
|
||||
</schema_validation>
|
||||
|
||||
---
|
||||
@@ -212,16 +214,12 @@ Brief summary:
|
||||
- Task completion status
|
||||
- Key findings summary
|
||||
- Generated file paths (if any)
|
||||
- Validation result (from Phase 3 Step 4)
|
||||
|
||||
### File Output (as specified in prompt)
|
||||
### File Output
|
||||
|
||||
**MANDATORY WORKFLOW**:
|
||||
|
||||
1. `Read()` schema file BEFORE generating output
|
||||
2. Extract ALL field names from schema
|
||||
3. Build JSON using ONLY schema field names
|
||||
4. Validate against checklist before writing
|
||||
5. Write file with validated content
|
||||
File is already written by json_builder during Phase 3 (init + set operations).
|
||||
Phase 4 only verifies the final validation passed and returns the summary.
|
||||
</output_generation>
|
||||
|
||||
---
|
||||
@@ -243,28 +241,19 @@ Brief summary:
|
||||
|
||||
**ALWAYS**:
|
||||
1. **Search Tool Priority**: ACE (`mcp__ace-tool__search_context`) → CCW (`mcp__ccw-tools__smart_search`) / Built-in (`Grep`, `Glob`, `Read`)
|
||||
2. Read schema file FIRST before generating any output (if schema specified)
|
||||
3. Copy field names EXACTLY from schema (case-sensitive)
|
||||
4. Verify root structure matches schema (array vs object)
|
||||
5. Match nested/flat structures as schema requires
|
||||
6. Use exact enum values from schema (case-sensitive)
|
||||
7. Include ALL required fields at every level
|
||||
8. Include file:line references in findings
|
||||
9. **Every file MUST have rationale**: Specific selection basis tied to the topic (not generic)
|
||||
10. **Every file MUST have role**: Classify as modify_target/dependency/pattern_reference/test_target/type_definition/integration_point/config/context_only
|
||||
11. **Track discovery source**: Record how each file was found (bash-scan/cli-analysis/ace-search/dependency-trace/manual)
|
||||
12. **Populate key_code for high-relevance files**: relevance >= 0.7 → key_code array with symbol, location, description
|
||||
13. **Populate topic_relation for high-relevance files**: relevance >= 0.7 → topic_relation explaining file-to-angle connection
|
||||
2. **Use json_builder** for all JSON output: `init` → `set` (incremental) → `validate`
|
||||
3. Include file:line references in findings
|
||||
4. **Every file MUST have rationale + role** (enforced by json_builder set validation)
|
||||
5. **Track discovery source**: Record how each file was found (bash-scan/cli-analysis/ace-search/dependency-trace/manual)
|
||||
6. **Populate key_code + topic_relation for high-relevance files** (relevance >= 0.7; json_builder warns if missing)
|
||||
|
||||
**Bash Tool**:
|
||||
- Use `run_in_background=false` for all Bash/CLI calls to ensure foreground execution
|
||||
|
||||
**NEVER**:
|
||||
1. Modify any files (read-only agent)
|
||||
2. Skip schema reading step when schema is specified
|
||||
3. Guess field names - ALWAYS copy from schema
|
||||
4. Assume structure - ALWAYS verify against schema
|
||||
5. Omit required fields
|
||||
1. Modify any source code files (read-only agent — json_builder writes only output JSON)
|
||||
2. Hand-write JSON output — always use json_builder
|
||||
3. Skip the `validate` step before returning
|
||||
</operational_rules>
|
||||
|
||||
<output_contract>
|
||||
@@ -282,11 +271,8 @@ When exploration is complete, return one of:
|
||||
|
||||
Before returning, verify:
|
||||
- [ ] All 4 phases were executed (or skipped with justification)
|
||||
- [ ] Schema was read BEFORE output generation (if schema specified)
|
||||
- [ ] All field names match schema exactly (case-sensitive)
|
||||
- [ ] Every file entry has rationale (specific, >10 chars) and role
|
||||
- [ ] High-relevance files (>= 0.7) have key_code and topic_relation
|
||||
- [ ] json_builder `init` was called at start
|
||||
- [ ] json_builder `validate` returned `valid: true` (or all errors were fixed)
|
||||
- [ ] Discovery sources are tracked for all findings
|
||||
- [ ] No files were modified (read-only agent)
|
||||
- [ ] Output format matches schema root structure (array vs object)
|
||||
- [ ] No source code files were modified (read-only agent)
|
||||
</quality_gate>
|
||||
|
||||
@@ -139,16 +139,15 @@ When `process_docs: true`, generate planning-context.md before sub-plan.json:
|
||||
|
||||
## Schema-Driven Output
|
||||
|
||||
**CRITICAL**: Read the schema reference first to determine output structure:
|
||||
- `plan-overview-base-schema.json` → Implementation plan with `approach`, `complexity`
|
||||
- `plan-overview-fix-schema.json` → Fix plan with `root_cause`, `severity`, `risk_level`
|
||||
**CRITICAL**: Get schema info via json_builder to determine output structure:
|
||||
- `ccw tool exec json_builder '{"cmd":"info","schema":"plan"}'` → Implementation plan with `approach`, `complexity`
|
||||
- `ccw tool exec json_builder '{"cmd":"info","schema":"plan-fix"}'` → Fix plan with `root_cause`, `severity`, `risk_level`
|
||||
|
||||
```javascript
|
||||
// Step 1: Always read schema first
|
||||
const schema = Bash(`cat ${schema_path}`)
|
||||
|
||||
// Step 2: Generate plan conforming to schema
|
||||
const planObject = generatePlanFromSchema(schema, context)
|
||||
After generating plan.json and .task/*.json, validate:
|
||||
```bash
|
||||
ccw tool exec json_builder '{"cmd":"validate","target":"<session>/plan.json","schema":"plan"}'
|
||||
# For each task file:
|
||||
ccw tool exec json_builder '{"cmd":"validate","target":"<session>/.task/TASK-001.json","schema":"task"}'
|
||||
```
|
||||
|
||||
</schema_driven_output>
|
||||
@@ -863,7 +862,7 @@ function validateTask(task) {
|
||||
|
||||
**ALWAYS**:
|
||||
- **Search Tool Priority**: ACE (`mcp__ace-tool__search_context`) → CCW (`mcp__ccw-tools__smart_search`) / Built-in (`Grep`, `Glob`, `Read`)
|
||||
- **Read schema first** to determine output structure
|
||||
- **Get schema info via json_builder** to determine output structure
|
||||
- Generate task IDs (TASK-001/TASK-002 for plan, FIX-001/FIX-002 for fix-plan)
|
||||
- Include depends_on (even if empty [])
|
||||
- **Assign cli_execution_id** (`{sessionId}-{taskId}`)
|
||||
@@ -981,7 +980,7 @@ Upon completion, return one of:
|
||||
|
||||
Before returning, verify:
|
||||
|
||||
- [ ] Schema reference was read and output structure matches schema type (base vs fix)
|
||||
- [ ] Schema info was obtained via json_builder and output structure matches schema type (base vs fix)
|
||||
- [ ] All tasks have valid IDs (TASK-NNN or FIX-NNN format)
|
||||
- [ ] All tasks have 2+ implementation steps
|
||||
- [ ] All convergence criteria are quantified and testable (no vague language)
|
||||
|
||||
@@ -348,7 +348,7 @@ Write({ file_path: filePath, content: newContent })
|
||||
.workflow/issues/solutions/{issue-id}.jsonl
|
||||
```
|
||||
|
||||
Each line is a solution JSON containing tasks. Schema: `cat ~/.ccw/workflows/cli-templates/schemas/solution-schema.json`
|
||||
Each line is a solution JSON containing tasks. Schema: `ccw tool exec json_builder '{"cmd":"info","schema":"solution"}'`
|
||||
|
||||
### 2.2 Return Summary
|
||||
|
||||
@@ -388,7 +388,7 @@ Each line is a solution JSON containing tasks. Schema: `cat ~/.ccw/workflows/cli
|
||||
|
||||
**ALWAYS**:
|
||||
1. **Search Tool Priority**: ACE (`mcp__ace-tool__search_context`) → CCW (`mcp__ccw-tools__smart_search`) / Built-in (`Grep`, `Glob`, `Read`)
|
||||
2. Read schema first: `cat ~/.ccw/workflows/cli-templates/schemas/solution-schema.json`
|
||||
2. Get schema info: `ccw tool exec json_builder '{"cmd":"info","schema":"solution"}'` (replaces reading raw schema)
|
||||
3. Use ACE semantic search as PRIMARY exploration tool
|
||||
4. Fetch issue details via `ccw issue status <id> --json`
|
||||
5. **Analyze failure history**: Check `issue.feedback` for type='failure', stage='execute'
|
||||
@@ -408,6 +408,11 @@ Each line is a solution JSON containing tasks. Schema: `cat ~/.ccw/workflows/cli
|
||||
4. **Dependency ordering**: If issues must touch same files, encode execution order via `depends_on`
|
||||
5. **Scope minimization**: Prefer smaller, focused modifications over broad refactoring
|
||||
|
||||
**VALIDATE**: After writing solution JSONL, validate each solution:
|
||||
```bash
|
||||
ccw tool exec json_builder '{"cmd":"validate","target":".workflow/issues/solutions/<issue-id>.jsonl","schema":"solution"}'
|
||||
```
|
||||
|
||||
**NEVER**:
|
||||
1. Execute implementation (return plan only)
|
||||
2. Use vague criteria ("works correctly", "good performance")
|
||||
|
||||
112
.claude/agents/workflow-research-agent.md
Normal file
112
.claude/agents/workflow-research-agent.md
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: workflow-research-agent
|
||||
description: External research agent — web search for API details, design patterns, best practices, and technology validation. Returns structured markdown, does NOT write files.
|
||||
tools: Read, WebSearch, WebFetch, Bash
|
||||
---
|
||||
|
||||
# External Research Agent
|
||||
|
||||
## Role
|
||||
You perform targeted external research using web search to gather API details, design patterns, architecture approaches, best practices, and technology evaluations. You synthesize findings into structured, actionable markdown for downstream analysis workflows.
|
||||
|
||||
Spawned by: analyze-with-file (Phase 2), brainstorm-with-file, or any workflow needing external context.
|
||||
|
||||
**CRITICAL**: Return structured markdown only. Do NOT write any files unless explicitly instructed in the prompt.
|
||||
|
||||
## Process
|
||||
|
||||
1. **Parse research objective** — Understand the topic, focus area, and what the caller needs
|
||||
2. **Plan queries** — Design 3-5 focused search queries targeting the objective
|
||||
3. **Execute searches** — Use `WebSearch` for general research, `WebFetch` for specific documentation pages
|
||||
4. **Cross-reference** — If codebase files are provided in prompt, `Read` them to ground research in actual code context
|
||||
5. **Synthesize findings** — Extract key insights, patterns, and recommendations from search results
|
||||
6. **Return structured output** — Markdown-formatted research findings
|
||||
|
||||
## Research Modes
|
||||
|
||||
### Detail Verification (default for analyze)
|
||||
Focus: verify assumptions, check best practices, validate technology choices, confirm patterns.
|
||||
Queries target: benchmarks, production postmortems, known issues, compatibility matrices, official docs.
|
||||
|
||||
### API Research (for implementation planning)
|
||||
Focus: concrete API details, library versions, integration patterns, configuration options.
|
||||
Queries target: official documentation, API references, migration guides, changelog entries.
|
||||
|
||||
### Design Research (for brainstorm/architecture)
|
||||
Focus: design alternatives, architecture patterns, competitive analysis, UX patterns.
|
||||
Queries target: design systems, pattern libraries, case studies, comparison articles.
|
||||
|
||||
## Execution
|
||||
|
||||
### Query Strategy
|
||||
```
|
||||
1. Parse topic → extract key technologies, patterns, concepts
|
||||
2. Generate 3-5 queries:
|
||||
- Q1: "{technology} best practices {year}"
|
||||
- Q2: "{pattern} vs {alternative} comparison"
|
||||
- Q3: "{technology} known issues production"
|
||||
- Q4: "{specific API/library} documentation {version}"
|
||||
- Q5: "{domain} architecture patterns"
|
||||
3. Execute queries via WebSearch
|
||||
4. For promising results, WebFetch full content for detail extraction
|
||||
5. Synthesize across all sources
|
||||
```
|
||||
|
||||
### Codebase Grounding
|
||||
When the prompt includes `codebase_context` (file paths, patterns, tech stack):
|
||||
- Read referenced files to understand actual usage
|
||||
- Compare external best practices against current implementation
|
||||
- Flag gaps between current code and recommended patterns
|
||||
|
||||
## Output Format
|
||||
|
||||
Return structured markdown (do NOT write files):
|
||||
|
||||
```markdown
|
||||
## Research: {topic}
|
||||
|
||||
### Key Findings
|
||||
- **{Finding 1}**: {detail} (confidence: HIGH|MEDIUM|LOW, source: {url_or_reference})
|
||||
- **{Finding 2}**: {detail} (confidence: HIGH|MEDIUM|LOW, source: {url_or_reference})
|
||||
|
||||
### Technology / API Details
|
||||
- **{Library/API}**: version {X}, {key capabilities}
|
||||
- Integration: {how to integrate}
|
||||
- Caveats: {known issues or limitations}
|
||||
|
||||
### Best Practices
|
||||
- {Practice 1}: {rationale} (source: {reference})
|
||||
- {Practice 2}: {rationale} (source: {reference})
|
||||
|
||||
### Recommended Approach
|
||||
{Prescriptive recommendation with rationale — "use X" not "consider X or Y" when evidence is strong}
|
||||
|
||||
### Alternatives Considered
|
||||
| Option | Pros | Cons | Verdict |
|
||||
|--------|------|------|---------|
|
||||
| {A} | ... | ... | Recommended / Viable / Avoid |
|
||||
|
||||
### Pitfalls & Known Issues
|
||||
- {Issue 1}: {mitigation} (source: {reference})
|
||||
|
||||
### Codebase Gaps (if codebase_context provided)
|
||||
- {Gap}: current code does {X}, best practice recommends {Y}
|
||||
|
||||
### Sources
|
||||
- {source title}: {url} — {key takeaway}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
- If WebSearch returns no results for a query: note "no results" and proceed with remaining queries
|
||||
- If WebFetch fails for a URL: skip and note the intended lookup
|
||||
- If all searches fail: return "research unavailable — proceed with codebase-only analysis" and list the queries that were attempted
|
||||
- If codebase files referenced in prompt don't exist: proceed with external research only
|
||||
|
||||
## Constraints
|
||||
- Be prescriptive ("use X") not exploratory ("consider X or Y") when evidence is strong
|
||||
- Assign confidence levels (HIGH/MEDIUM/LOW) to all findings
|
||||
- Cite sources for claims — include URLs
|
||||
- Keep output under 200 lines
|
||||
- Do NOT write any files — return structured markdown only
|
||||
- Do NOT fabricate URLs or sources — only cite actual search results
|
||||
- Bash calls MUST use `run_in_background: false` (subagent cannot receive hook callbacks)
|
||||
@@ -1,359 +0,0 @@
|
||||
---
|
||||
name: auto
|
||||
description: Chain command - automated document-driven development flow. Detects project state and runs the appropriate chain for new or existing projects.
|
||||
argument-hint: "[-y|--yes] [--skip-spec] [--skip-build] [--spec <session-id>] [--resume] \"project idea or task description\""
|
||||
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: All sub-commands run in auto mode. Minimal human intervention.
|
||||
|
||||
# DDD Auto Command (/ddd:auto)
|
||||
|
||||
## Purpose
|
||||
|
||||
Orchestrate the full document-driven development lifecycle. **Adapts to project state** — works for both new projects and existing codebases.
|
||||
|
||||
## Flow Variants
|
||||
|
||||
### Variant 1: New Project (no code, no spec)
|
||||
```
|
||||
spec-generator → ddd:index-build → ddd:plan → ddd:execute → verify → ddd:sync
|
||||
```
|
||||
|
||||
### Variant 2: Existing Project (has code, no spec)
|
||||
```
|
||||
ddd:scan → ddd:plan → ddd:execute → verify → ddd:sync
|
||||
```
|
||||
|
||||
### Variant 3: Existing Project with Spec (has code + spec)
|
||||
```
|
||||
ddd:index-build → ddd:plan → ddd:execute → verify → ddd:sync
|
||||
```
|
||||
|
||||
### Variant 4: Index Exists (has doc-index.json)
|
||||
```
|
||||
ddd:plan → ddd:execute → verify → ddd:sync
|
||||
```
|
||||
|
||||
## Flow Diagram
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────┐
|
||||
│ /ddd:auto │
|
||||
│ │
|
||||
│ Stage 0: Detect Project State │
|
||||
│ ┌───────────────────────────────────┐ │
|
||||
│ │ has_codebase? has_spec? has_index?│ │
|
||||
│ └────────────┬──────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────┼──────────────┐ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ No Code Code Only Code + Spec Index Exists │
|
||||
│ │ │ │ │ │
|
||||
│ ▼ │ │ │ │
|
||||
│ Stage 1 │ │ │ │
|
||||
│ Spec Gen │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ ▼ │ ▼ │ │
|
||||
│ Stage 2a Stage 2b Stage 2a │ │
|
||||
│ index-build ddd:scan index-build │ │
|
||||
│ (Path A or Path B auto-detected) │ │
|
||||
│ │ │ │
|
||||
│ └───────────────────┬───────────────────┘ │
|
||||
│ ▼ │
|
||||
│ Stage 3: DDD Plan (enhanced) │
|
||||
│ (doc-index query + exploration + │
|
||||
│ clarification + task planning) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Stage 4: Execute │
|
||||
│ (ddd:execute = doc-aware execution) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Stage 4.5: Verify Gate │
|
||||
│ (convergence + build + lint + tests │
|
||||
│ → execution-manifest.json) │
|
||||
│ │ │
|
||||
│ PASS / WARN → continue │
|
||||
│ FAIL → ask user │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Stage 5: Doc Sync │
|
||||
│ (auto-triggered with --from-manifest, │
|
||||
│ or manual /ddd:sync) │
|
||||
└────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Stage 0: Project State Detection
|
||||
|
||||
Automatically detect project state to determine which stages to run:
|
||||
|
||||
```
|
||||
Check 1: doc-index.json exists? → has_index
|
||||
Check 2: SPEC-* directories exist? → has_spec
|
||||
Check 3: Source code directories? → has_codebase
|
||||
Check 4: project-tech.json exists? → has_tech_analysis
|
||||
```
|
||||
|
||||
### Decision Matrix
|
||||
|
||||
| has_codebase | has_spec | has_index | Action |
|
||||
|:---:|:---:|:---:|--------|
|
||||
| No | No | No | Stage 1 (spec-gen) → Stage 2a (index-build) → Stage 3-5 |
|
||||
| No | Yes | No | Stage 2a (index-build) → Stage 3-5 |
|
||||
| Yes | No | No | **Stage 2b (ddd:scan)** → Stage 3-5 |
|
||||
| Yes | Yes | No | Stage 2a (index-build) → Stage 3-5 |
|
||||
| Yes | * | Yes | **Skip to Stage 3** (index exists) |
|
||||
|
||||
### Override Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `--skip-spec` | Never run spec-generator |
|
||||
| `--skip-build` | Never run index-build |
|
||||
| `--spec <id>` | Use specific spec session, force Path A |
|
||||
| `--from-scratch` | Rebuild index even if exists |
|
||||
|
||||
## Stage 1: Specification (conditional)
|
||||
|
||||
### Run When
|
||||
- No codebase AND no spec AND `--skip-spec` not set
|
||||
- User provides a new project idea (not an existing task description)
|
||||
|
||||
### Skip When
|
||||
- `--skip-spec` flag
|
||||
- Codebase already exists (existing project)
|
||||
- `--spec <id>` pointing to existing session
|
||||
|
||||
### Execution
|
||||
```
|
||||
Invoke /spec-generator with user input
|
||||
→ Output: .workflow/.doc-index/specs/SPEC-{slug}-{date}/
|
||||
```
|
||||
|
||||
## Stage 2: Index Construction (conditional)
|
||||
|
||||
### Run When
|
||||
- `doc-index.json` does not exist
|
||||
- OR `--from-scratch` flag
|
||||
|
||||
### Route Selection
|
||||
|
||||
```
|
||||
Has spec outputs → Stage 2a: /ddd:index-build (spec-first)
|
||||
No spec, has code → Stage 2b: /ddd:scan (code-first)
|
||||
```
|
||||
|
||||
### Stage 2a: /ddd:index-build (has spec)
|
||||
```
|
||||
Invoke /ddd:index-build [-y] [-s <spec-id>]
|
||||
→ Output: doc-index.json from spec entities + code mapping
|
||||
```
|
||||
|
||||
### Stage 2b: /ddd:scan (no spec, has code)
|
||||
```
|
||||
Invoke /ddd:scan [-y]
|
||||
→ Output: doc-index.json from code analysis + inferred features
|
||||
```
|
||||
|
||||
### Skip When
|
||||
- `--skip-build` flag
|
||||
- `doc-index.json` exists AND NOT `--from-scratch`
|
||||
- In this case, suggest `/ddd:update` for incremental refresh
|
||||
|
||||
## Stage 3: Planning (always runs)
|
||||
|
||||
### Execution
|
||||
|
||||
```
|
||||
Invoke /ddd:plan [-y] "task description"
|
||||
```
|
||||
|
||||
The enhanced `/ddd:plan` now performs:
|
||||
1. Doc-index query (instant context from features, requirements, components, ADRs)
|
||||
2. Doc-index-guided exploration (1-4 angles based on affected features)
|
||||
3. Clarification (aggregate ambiguities from exploration + doc-index gaps)
|
||||
4. Task planning (plan.json + TASK-*.json with doc_context traceability)
|
||||
5. Handoff selection
|
||||
|
||||
Output:
|
||||
- `plan.json` — plan overview with doc_context
|
||||
- `.task/TASK-*.json` — individual tasks with doc_context
|
||||
- `exploration-{angle}.json` — exploration results (if Phase 2 ran)
|
||||
- `planning-context.md` — legacy context package
|
||||
|
||||
### Handoff Decision
|
||||
|
||||
After planning, `/ddd:plan` presents execution options:
|
||||
|
||||
| Option | Description | Auto-Select When |
|
||||
|--------|-------------|-----------------|
|
||||
| **ddd:execute** | Document-aware execution (recommended) | Default in ddd workflow |
|
||||
| **lite-execute** | Standard execution (no doc awareness) | When doc traceability not needed |
|
||||
| **direct** | Start coding with context | User prefers manual |
|
||||
| **stop** | Just the plan context | Planning/research only |
|
||||
|
||||
With `-y`: Auto-select `ddd:execute`.
|
||||
|
||||
## Stage 4: Execution
|
||||
|
||||
Based on Stage 3 handoff decision:
|
||||
|
||||
| Mode | Delegates To |
|
||||
|------|-------------|
|
||||
| **ddd:execute** | `/ddd:execute --in-memory` with plan.json + doc-index enrichment |
|
||||
| lite-execute | `/workflow:lite-execute` with plan.json path |
|
||||
| direct | Output context package, developer works manually |
|
||||
| stop | End here, no execution |
|
||||
|
||||
### ddd:execute Features (when selected)
|
||||
- Doc-enriched task prompts (feature context + component docs + ADR constraints)
|
||||
- Per-batch impact verification (changes stay within planned scope)
|
||||
- Result persistence (`TASK-*.result.json` per task, `execution-manifest.json` per session)
|
||||
- Post-execution verify gate (Stage 4.5, unless `--skip-verify`)
|
||||
- Post-completion auto-sync with manifest (Stage 5 triggered automatically)
|
||||
|
||||
**Note**: When using `ddd:execute`, Stage 4.5 and Stage 5 are auto-triggered. For other modes, run Stage 5 manually.
|
||||
|
||||
## Stage 4.5: Verify Gate
|
||||
|
||||
Embedded within `ddd:execute` (Step 4.5). Runs after all batches complete, before doc sync.
|
||||
|
||||
### Purpose
|
||||
|
||||
Quality gate ensuring execution output is correct before committing to documentation updates. Prevents bad code from being "blessed" into the doc-index.
|
||||
|
||||
### Checks Performed
|
||||
|
||||
| Check | Description | Gate Behavior |
|
||||
|-------|-------------|---------------|
|
||||
| **Convergence** | Run `task.convergence.verification` for each task | FAIL if any critical task fails |
|
||||
| **Build** | Run project build command (`tsc --noEmit`, etc.) | FAIL on build errors |
|
||||
| **Lint** | Run project linter (`eslint`, etc.) | WARN only (non-blocking) |
|
||||
| **Regression** | Run full test suite, compare to baseline | FAIL on new test failures |
|
||||
|
||||
### Gate Results
|
||||
|
||||
| Result | Action |
|
||||
|--------|--------|
|
||||
| **PASS** | All checks passed → proceed to Stage 5 |
|
||||
| **WARN** | Non-critical issues (lint warnings) → proceed with warnings logged |
|
||||
| **FAIL** | Critical issues → ask user: fix now / skip sync / abort |
|
||||
| **FAIL + `-y`** | Log failures, set `error_state` in session, stop |
|
||||
|
||||
### Output
|
||||
|
||||
- `execution-manifest.json` — persisted to session folder, consumed by Stage 5
|
||||
- Contains: task results, files_modified (with task attribution), verify gate results
|
||||
|
||||
## Stage 5: Post-Task Sync
|
||||
|
||||
### Trigger
|
||||
- **Auto**: `/ddd:execute` triggers `/ddd:sync --from-manifest` automatically after verify gate passes
|
||||
- **Manual**: User runs `/ddd:sync` after completing work in direct/lite-execute mode
|
||||
- **Resume**: `/ddd:auto --resume` after task completion
|
||||
|
||||
### Execution
|
||||
```
|
||||
# Auto mode (from ddd:execute): uses manifest for precise change tracking
|
||||
Invoke /ddd:sync [-y] --task-id <id> --from-manifest {session}/execution-manifest.json "task summary"
|
||||
|
||||
# Manual mode (from direct/lite-execute): falls back to git diff
|
||||
Invoke /ddd:sync [-y] [--task-id <id>] "task summary"
|
||||
|
||||
→ Updates: doc-index.json, feature-maps/, tech-registry/, action-logs/
|
||||
```
|
||||
|
||||
## State Tracking
|
||||
|
||||
### Session File: `.workflow/.doc-index/.auto-session.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "DAUTO-{timestamp}",
|
||||
"input": "user's original input",
|
||||
"detected_state": {
|
||||
"has_codebase": true,
|
||||
"has_spec": false,
|
||||
"has_index": false,
|
||||
"build_path": "code-first"
|
||||
},
|
||||
"stages_completed": ["detect", "index-build", "plan"],
|
||||
"current_stage": "execute",
|
||||
"spec_session": "SPEC-{slug}-{date}|null",
|
||||
"plan_session": "planning/{task-slug}-{date}/",
|
||||
"plan_context": "planning/{task-slug}-{date}/plan.json",
|
||||
"execution_mode": "ddd:execute|lite-execute|direct|stop",
|
||||
"execution_manifest": "planning/{task-slug}-{date}/execution-manifest.json|null",
|
||||
"verify_gate": "PASS|WARN|FAIL|null",
|
||||
"error_state": null,
|
||||
"last_error": {
|
||||
"stage": "execute",
|
||||
"message": "Task TASK-002 failed: compilation error",
|
||||
"timestamp": "ISO8601",
|
||||
"recoverable": true
|
||||
},
|
||||
"created_at": "ISO8601",
|
||||
"last_updated": "ISO8601"
|
||||
}
|
||||
```
|
||||
|
||||
### Resume
|
||||
```
|
||||
/ddd:auto --resume → Resume from current_stage in .auto-session.json
|
||||
```
|
||||
|
||||
### Error Recovery
|
||||
```
|
||||
/ddd:auto --resume
|
||||
IF error_state is set:
|
||||
Display last error context
|
||||
Ask: retry current stage / skip to next / abort
|
||||
ELSE:
|
||||
Resume from current_stage normally
|
||||
```
|
||||
|
||||
## Example Workflows
|
||||
|
||||
### New Project (Full Flow)
|
||||
```
|
||||
/ddd:auto "Build a task management API with user auth and team features"
|
||||
→ Stage 0: No code, no spec → need spec-gen
|
||||
→ Stage 1: spec-generator produces full spec
|
||||
→ Stage 2: index-build creates index from spec + empty codebase
|
||||
→ Stage 3: ddd:plan produces plan.json + TASK-*.json with doc_context
|
||||
→ Stage 4: ddd:execute runs tasks with feature context enrichment
|
||||
→ Stage 4.5: verify gate — convergence ✓, build ✓, tests ✓ → PASS
|
||||
→ Stage 5: ddd:sync --from-manifest auto-triggered, updates index
|
||||
```
|
||||
|
||||
### Existing Project, No Spec (Code-First)
|
||||
```
|
||||
/ddd:auto "Add rate limiting to API endpoints"
|
||||
→ Stage 0: Has code, no spec, no index
|
||||
→ Stage 2b: ddd:scan analyzes code, infers features from codebase
|
||||
→ Stage 3: ddd:plan queries index, explores with security + patterns angles
|
||||
→ Stage 4: ddd:execute runs with rate-limit component docs as context
|
||||
→ Stage 4.5: verify gate — convergence ✓, tests 41/42 (1 regression) → WARN
|
||||
→ Stage 5: ddd:sync --from-manifest, registers new rate-limit component
|
||||
```
|
||||
|
||||
### Existing Project with Index (Incremental)
|
||||
```
|
||||
/ddd:auto "Fix auth token expiration bug"
|
||||
→ Stage 0: Has code, has index → skip to plan
|
||||
→ Stage 3: ddd:plan finds feat-auth, REQ-002, tech-auth-service (Low complexity, skip exploration)
|
||||
→ Stage 4: ddd:execute runs single task with auth feature context
|
||||
→ Stage 4.5: verify gate — convergence ✓, build ✓, tests ✓ → PASS
|
||||
→ Stage 5: ddd:sync --from-manifest, updates tech-auth-service code locations
|
||||
```
|
||||
|
||||
### Planning Only
|
||||
```
|
||||
/ddd:auto "Investigate payment module architecture"
|
||||
→ Stage 0-2: (as needed)
|
||||
→ Stage 3: ddd:plan shows full context with exploration results
|
||||
→ Stage 4: user selects "stop" → gets plan.json + context package only
|
||||
```
|
||||
@@ -1,222 +0,0 @@
|
||||
---
|
||||
name: doc-generate
|
||||
description: Generate full document tree from doc-index.json. Layer 3 (components) → Layer 2 (features) → Layer 1 (indexes/overview). Standalone or called by scan/index-build.
|
||||
argument-hint: "[-y|--yes] [--layer <3|2|1|all>] [--force] [--skip-overview] [--skip-schema]"
|
||||
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Auto-generate all layers without confirmation prompts.
|
||||
|
||||
# DDD Doc Generate Command (/ddd:doc-generate)
|
||||
|
||||
## Purpose
|
||||
|
||||
Generate the complete document tree from `doc-index.json`. **Single source of truth** for all document generation logic, following bottom-up Layer 3 → 2 → 1 strategy.
|
||||
|
||||
```
|
||||
doc-index.json → tech-registry/*.md (L3) → feature-maps/*.md (L2) → _index.md + README + ARCHITECTURE (L1)
|
||||
```
|
||||
|
||||
## When to Use
|
||||
|
||||
| Scenario | Use |
|
||||
|----------|-----|
|
||||
| After `/ddd:scan` builds doc-index.json | **doc-generate** (auto-called by scan) |
|
||||
| After `/ddd:index-build` builds doc-index.json | **doc-generate** (auto-called by index-build) |
|
||||
| Rebuild all docs from existing index | **doc-generate --force** |
|
||||
| Regenerate only component docs | **doc-generate --layer 3** |
|
||||
| Regenerate only overview/index docs | **doc-generate --layer 1** |
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- `doc-index.json` must exist at `.workflow/.doc-index/doc-index.json`
|
||||
- If not found → error: "No doc-index.json found. Run /ddd:scan or /ddd:index-build first."
|
||||
|
||||
## Storage Output
|
||||
|
||||
```
|
||||
.workflow/.doc-index/
|
||||
├── doc-index.json ← Input (read-only, not modified)
|
||||
├── SCHEMA.md ← Schema documentation
|
||||
├── README.md ← Project overview (Layer 1)
|
||||
├── ARCHITECTURE.md ← Architecture overview (Layer 1)
|
||||
├── feature-maps/ ← Feature documentation (Layer 2)
|
||||
│ ├── _index.md
|
||||
│ └── {feature-slug}.md
|
||||
├── tech-registry/ ← Component documentation (Layer 3)
|
||||
│ ├── _index.md
|
||||
│ └── {component-slug}.md
|
||||
└── planning/ ← Planning sessions (Layer 1)
|
||||
├── _index.md ← Planning sessions index
|
||||
└── {task-slug}-{date}/ ← Individual session folders
|
||||
```
|
||||
|
||||
## Phase 1: Load & Validate
|
||||
|
||||
### 1.1 Load doc-index.json
|
||||
|
||||
```
|
||||
Read .workflow/.doc-index/doc-index.json
|
||||
Validate: features[], technicalComponents[] are non-empty arrays
|
||||
```
|
||||
|
||||
### 1.2 Schema Version Check
|
||||
|
||||
```javascript
|
||||
const schemaVersion = docIndex.schema_version || '0.0';
|
||||
if (schemaVersion !== '1.0') {
|
||||
warn(`Schema version mismatch: found ${schemaVersion}, expected 1.0`);
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 Determine Generation Scope
|
||||
|
||||
```
|
||||
IF --layer 3: generate Layer 3 only
|
||||
IF --layer 2: generate Layer 2 only (requires Layer 3 exists)
|
||||
IF --layer 1: generate Layer 1 only (requires Layer 2 exists)
|
||||
IF --layer all (default): generate Layer 3 → 2 → 1
|
||||
```
|
||||
|
||||
### 1.4 Check Existing Docs
|
||||
|
||||
```
|
||||
IF docs already exist AND NOT --force:
|
||||
Warn: "Documents already exist. Use --force to overwrite."
|
||||
Ask user (unless -y → overwrite)
|
||||
```
|
||||
|
||||
## Phase 2: Layer 3 -- Component Documentation
|
||||
|
||||
For each component in `technicalComponents[]`, call the generate_ddd_docs endpoint:
|
||||
|
||||
```bash
|
||||
for COMPONENT_ID in "${technicalComponents[@]}"; do
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"component","entityId":"'"$COMPONENT_ID"'","tool":"gemini"}'
|
||||
done
|
||||
```
|
||||
|
||||
The endpoint handles:
|
||||
- Loading the component entity from doc-index.json
|
||||
- Building YAML frontmatter (layer: 3, component_id, name, type, features, code_locations, generated_at)
|
||||
- Constructing the CLI prompt with code context paths
|
||||
- **Including Change History section**: Pull related entries from `doc-index.json.actions[]` where `affectedComponents` includes this component ID. Display as timeline (date, action type, description)
|
||||
- Writing output to `.workflow/.doc-index/tech-registry/{slug}.md`
|
||||
- Tool fallback (gemini -> qwen -> codex) on failure
|
||||
|
||||
Output: `.workflow/.doc-index/tech-registry/{component-slug}.md`
|
||||
|
||||
## Phase 3: Layer 2 -- Feature Documentation
|
||||
|
||||
For each feature in `features[]`, call the generate_ddd_docs endpoint:
|
||||
|
||||
```bash
|
||||
for FEATURE_ID in "${features[@]}"; do
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"feature","entityId":"'"$FEATURE_ID"'","tool":"gemini"}'
|
||||
done
|
||||
```
|
||||
|
||||
The endpoint handles:
|
||||
- Loading the feature entity from doc-index.json
|
||||
- Building YAML frontmatter (layer: 2, feature_id, name, epic_id, status, requirements, components, tags, generated_at)
|
||||
- Constructing the CLI prompt referencing Layer 3 component docs
|
||||
- **Including Change History section**: Pull related entries from `doc-index.json.actions[]` where `affectedFeatures` includes this feature ID. Display as timeline (date, action type, description)
|
||||
- Writing output to `.workflow/.doc-index/feature-maps/{slug}.md`
|
||||
- Tool fallback (gemini -> qwen -> codex) on failure
|
||||
|
||||
Output: `.workflow/.doc-index/feature-maps/{feature-slug}.md`
|
||||
|
||||
## Phase 4: Layer 1 -- Index & Overview Documentation
|
||||
|
||||
### 4.1 Index Documents
|
||||
|
||||
Generate catalog files for each subdirectory:
|
||||
|
||||
```bash
|
||||
# Feature maps index
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"index","entityId":"feature-maps","tool":"gemini"}'
|
||||
|
||||
# Tech registry index
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"index","entityId":"tech-registry","tool":"gemini"}'
|
||||
|
||||
# Action logs index
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"index","entityId":"action-logs","tool":"gemini"}'
|
||||
|
||||
# Planning sessions index
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"index","entityId":"planning","tool":"gemini"}'
|
||||
```
|
||||
|
||||
Or generate all indexes at once (omit entityId):
|
||||
|
||||
```bash
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"index","tool":"gemini"}'
|
||||
```
|
||||
|
||||
### 4.2 README.md (unless --skip-overview)
|
||||
|
||||
```bash
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"overview","tool":"gemini"}'
|
||||
```
|
||||
|
||||
### 4.3 ARCHITECTURE.md (unless --skip-overview)
|
||||
|
||||
```bash
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"overview","entityId":"architecture","tool":"gemini"}'
|
||||
```
|
||||
|
||||
## Phase 5: SCHEMA.md (unless --skip-schema)
|
||||
|
||||
### 5.1 Generate Schema Documentation
|
||||
|
||||
```bash
|
||||
ccw tool exec generate_ddd_docs '{"strategy":"schema","tool":"gemini"}'
|
||||
```
|
||||
|
||||
### 5.2 Versioning Policy
|
||||
|
||||
**Semantic Versioning**:
|
||||
- **Major** (X.0): Breaking changes (field removal, type changes, incompatible structure)
|
||||
- **Minor** (X.Y): Non-breaking additions (new optional fields, new sections)
|
||||
|
||||
**Migration Protocol**:
|
||||
1. Detect version mismatch in ddd:plan/ddd:sync
|
||||
2. Log warning with migration instructions
|
||||
3. Provide migration script or regeneration option
|
||||
4. Update schema_version after successful migration
|
||||
|
||||
## Phase 6: Generation Report
|
||||
|
||||
```
|
||||
Document Generation Report
|
||||
|
||||
Project: {name}
|
||||
Source: doc-index.json (build_path: {spec-first|code-first})
|
||||
|
||||
Generated:
|
||||
Layer 3 (Components): {N} documents in tech-registry/
|
||||
Layer 2 (Features): {N} documents in feature-maps/
|
||||
Layer 1 (Indexes): {N} documents (_index.md, README, ARCHITECTURE)
|
||||
Schema: SCHEMA.md
|
||||
|
||||
Total: {N} documents generated
|
||||
```
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-y, --yes` | Auto-confirm all decisions |
|
||||
| `--layer <3\|2\|1\|all>` | Generate specific layer only (default: all) |
|
||||
| `--force` | Overwrite existing documents |
|
||||
| `--skip-overview` | Skip README.md, ARCHITECTURE.md, planning/_index.md |
|
||||
| `--skip-schema` | Skip SCHEMA.md generation |
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Input from**: `doc-index.json` (from `/ddd:scan` or `/ddd:index-build`)
|
||||
- **Called by**: `/ddd:scan` (after index assembly), `/ddd:index-build` (after index assembly)
|
||||
- **Standalone**: Can be run independently on any project with existing doc-index.json
|
||||
- **Output**: Complete document tree in `.workflow/.doc-index/`
|
||||
- **Endpoint**: `ccw tool exec generate_ddd_docs` handles prompt construction, frontmatter, tool fallback, and file creation
|
||||
@@ -1,218 +0,0 @@
|
||||
---
|
||||
name: doc-refresh
|
||||
description: Incrementally update affected documents based on changed components/features. Layer 3 → 2 → 1 selective refresh. Called by sync/update or used standalone.
|
||||
argument-hint: "[-y|--yes] [--components <id1,id2,...>] [--features <id1,id2,...>] [--minimal] [--dry-run]"
|
||||
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Auto-update affected documents without confirmation prompts.
|
||||
|
||||
# DDD Doc Refresh Command (/ddd:doc-refresh)
|
||||
|
||||
## Purpose
|
||||
|
||||
Incrementally update **only the affected documents** after code changes. Unlike `/ddd:doc-generate` (full generation), this command selectively refreshes documents for specific components and features.
|
||||
|
||||
```
|
||||
affected component/feature IDs → update tech-registry (L3) → update feature-maps (L2) → update indexes (L1)
|
||||
```
|
||||
|
||||
## When to Use
|
||||
|
||||
| Scenario | Use |
|
||||
|----------|-----|
|
||||
| After `/ddd:sync` detects code changes | **doc-refresh** (auto-called by sync) |
|
||||
| After `/ddd:update` traces impact | **doc-refresh** (auto-called by update) |
|
||||
| Manual refresh of specific component docs | **doc-refresh --components tech-auth-service** |
|
||||
| Quick metadata-only update | **doc-refresh --minimal --components tech-auth-service** |
|
||||
| Preview what would change | **doc-refresh --dry-run --components tech-auth-service** |
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- `doc-index.json` must exist at `.workflow/.doc-index/doc-index.json`
|
||||
- At least one of `--components` or `--features` must be provided (or received from caller)
|
||||
- Corresponding documents must already exist (generated by `/ddd:doc-generate`)
|
||||
- If documents missing → error: "Documents not found. Run /ddd:doc-generate first."
|
||||
|
||||
## Phase 1: Determine Refresh Scope
|
||||
|
||||
### 1.1 Resolve Affected Entities
|
||||
|
||||
```
|
||||
IF --components provided:
|
||||
affected_components = parse comma-separated IDs
|
||||
affected_features = lookup featureIds for each component in doc-index.json
|
||||
|
||||
IF --features provided:
|
||||
affected_features = parse comma-separated IDs
|
||||
affected_components = union of all component IDs linked to features
|
||||
|
||||
Merge both sets if both flags provided.
|
||||
```
|
||||
|
||||
### 1.2 Validate Entities Exist
|
||||
|
||||
For each ID, verify it exists in doc-index.json. Warn and skip missing IDs.
|
||||
|
||||
### 1.3 Check Document Existence
|
||||
|
||||
For each affected entity, check if corresponding .md file exists:
|
||||
- Missing Layer 3 doc → warn: "Component doc not found. Run /ddd:doc-generate first."
|
||||
- Missing Layer 2 doc → warn: "Feature doc not found. Run /ddd:doc-generate first."
|
||||
|
||||
## Phase 2: Layer 3 — Update Component Docs
|
||||
|
||||
For each affected component's `tech-registry/{slug}.md`:
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Update component documentation for {component.name} after code changes
|
||||
TASK:
|
||||
• Update code locations and line ranges
|
||||
• Update symbol list (add new exports, remove deleted)
|
||||
• Add change entry to history table
|
||||
• Refresh usage examples if API changed
|
||||
MODE: write
|
||||
CONTEXT: @{component.codeLocations[].path}
|
||||
EXPECTED: Updated markdown with current API state
|
||||
CONSTRAINTS: Preserve existing structure | Only update changed sections
|
||||
" --tool gemini --mode write --cd .workflow/.doc-index/tech-registry/
|
||||
```
|
||||
|
||||
Update frontmatter:
|
||||
```markdown
|
||||
---
|
||||
layer: 3
|
||||
component_id: tech-auth-service
|
||||
generated_at: {original}
|
||||
last_updated: ISO8601
|
||||
---
|
||||
```
|
||||
|
||||
### 2.1 Minimal Mode (--minimal)
|
||||
|
||||
With `--minimal`, only update:
|
||||
- `codeLocations` in frontmatter
|
||||
- `last_updated` timestamp
|
||||
- Skip CLI call for content regeneration
|
||||
|
||||
## Phase 3: Layer 2 — Update Feature Docs
|
||||
|
||||
For each affected feature's `feature-maps/{slug}.md`:
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Update feature documentation for {feature.name} after component changes
|
||||
TASK:
|
||||
• Update component list if new components added
|
||||
• Update status if requirements now fully implemented
|
||||
• Add change entry to history table
|
||||
• Refresh integration guide if component APIs changed
|
||||
MODE: write
|
||||
CONTEXT: @.workflow/.doc-index/tech-registry/{affected-components}.md
|
||||
EXPECTED: Updated markdown reflecting current feature state
|
||||
CONSTRAINTS: Reference updated Layer 3 docs | Preserve business language
|
||||
" --tool gemini --mode write --cd .workflow/.doc-index/feature-maps/
|
||||
```
|
||||
|
||||
Update frontmatter:
|
||||
```markdown
|
||||
---
|
||||
layer: 2
|
||||
feature_id: feat-auth
|
||||
depends_on_layer3: [tech-auth-service, tech-user-model]
|
||||
generated_at: {original}
|
||||
last_updated: ISO8601
|
||||
---
|
||||
```
|
||||
|
||||
### 3.1 Minimal Mode (--minimal)
|
||||
|
||||
With `--minimal`, only update:
|
||||
- Component list in frontmatter
|
||||
- Feature status (if requirements mapping changed)
|
||||
- `last_updated` timestamp
|
||||
- Skip CLI call for content regeneration
|
||||
|
||||
## Phase 4: Layer 1 — Update Index Docs (conditional)
|
||||
|
||||
### 4.1 Trigger Conditions
|
||||
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
| New component registered | Update `tech-registry/_index.md` |
|
||||
| Component removed | Update `tech-registry/_index.md` |
|
||||
| Feature status changed | Update `feature-maps/_index.md` |
|
||||
| New feature added | Update `feature-maps/_index.md` + README.md |
|
||||
| Major architecture change | Update ARCHITECTURE.md |
|
||||
| New action-log entry | Update `action-logs/_index.md` |
|
||||
|
||||
### 4.2 Update _index.md Files
|
||||
|
||||
Refresh table entries for affected features/components:
|
||||
- `feature-maps/_index.md`
|
||||
- `tech-registry/_index.md`
|
||||
- `action-logs/_index.md` (if new action entry)
|
||||
|
||||
### 4.3 Update Overview Docs (only if significant)
|
||||
|
||||
If new features added or major status changes:
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Update project overview docs after feature changes
|
||||
TASK:
|
||||
• Update README.md feature list
|
||||
• Update ARCHITECTURE.md if new components added
|
||||
• Update planning/_index.md with new planning sessions
|
||||
MODE: write
|
||||
CONTEXT: @.workflow/.doc-index/feature-maps/*.md @.workflow/.doc-index/doc-index.json
|
||||
EXPECTED: Updated overview docs with current project state
|
||||
CONSTRAINTS: High-level only | Link to Layer 2 for details
|
||||
" --tool gemini --mode write --cd .workflow/.doc-index/
|
||||
```
|
||||
|
||||
### 4.4 Skip Layer 1
|
||||
|
||||
With `--minimal` or when changes are minor (only code location updates): skip Layer 1 entirely.
|
||||
|
||||
## Phase 5: Refresh Report
|
||||
|
||||
```
|
||||
Document Refresh Report
|
||||
|
||||
Affected Scope:
|
||||
Components: {N} ({component IDs})
|
||||
Features: {N} ({feature IDs})
|
||||
|
||||
Updated:
|
||||
Layer 3 (Components): {N} documents refreshed
|
||||
Layer 2 (Features): {N} documents refreshed
|
||||
Layer 1 (Indexes): {N} documents refreshed (or "skipped")
|
||||
|
||||
Mode: {full|minimal}
|
||||
```
|
||||
|
||||
## Dry-Run Mode
|
||||
|
||||
With `--dry-run`:
|
||||
- Execute Phase 1 (scope determination)
|
||||
- Display what would be updated (affected files list)
|
||||
- Skip all file writes (Phase 2-4)
|
||||
- Output: "Dry-run complete. {N} documents would be refreshed."
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-y, --yes` | Auto-confirm all updates |
|
||||
| `--components <ids>` | Comma-separated component IDs to refresh |
|
||||
| `--features <ids>` | Comma-separated feature IDs to refresh |
|
||||
| `--minimal` | Only update metadata/frontmatter, skip content regeneration |
|
||||
| `--dry-run` | Preview what would change without modifying files |
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Input from**: `doc-index.json`, affected entity IDs (from `/ddd:sync` or `/ddd:update`)
|
||||
- **Called by**: `/ddd:sync` (after change detection + index update), `/ddd:update` (after impact tracing + index update)
|
||||
- **Standalone**: Can be run independently to refresh specific component/feature docs
|
||||
- **Prerequisite**: Documents must exist (generated by `/ddd:doc-generate`)
|
||||
@@ -1,416 +0,0 @@
|
||||
---
|
||||
name: execute
|
||||
description: Document-aware execution engine — executes plan.json + TASK-*.json with doc-index context enrichment, per-batch impact verification, and post-completion doc sync.
|
||||
argument-hint: "[-y|--yes] [--skip-sync] [--skip-verify] [--plan <path>] [--in-memory] \"optional task description\""
|
||||
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Auto-confirm all decisions, auto-sync after completion.
|
||||
|
||||
# DDD Execute Command (/ddd:execute)
|
||||
|
||||
## Purpose
|
||||
|
||||
Same execution engine model as lite-execute, but each step is **doc-index-aware**:
|
||||
- Tasks are enriched with feature context, component docs, and architecture constraints
|
||||
- Per-batch impact verification ensures changes stay within planned scope
|
||||
- Post-completion automatically syncs the document index
|
||||
|
||||
### Core Differentiator
|
||||
Unlike generic execution engines, ddd:execute leverages the document architecture:
|
||||
- Feature-maps provide business context for each task
|
||||
- Tech-registry provides implementation patterns to follow
|
||||
- ADRs surface as hard constraints during execution
|
||||
- Requirement acceptance criteria inform convergence verification
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- `plan.json` + `.task/TASK-*.json` files from `/ddd:plan`
|
||||
- `doc-index.json` at `.workflow/.doc-index/doc-index.json`
|
||||
- If `--in-memory`: receives executionContext from `/ddd:plan` handoff
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Initialize & Load Context
|
||||
|
||||
### 1.1 Locate Plan
|
||||
|
||||
```
|
||||
IF --in-memory:
|
||||
Load executionContext from ddd:plan handoff
|
||||
plan_path = executionContext.plan_path
|
||||
task_dir = executionContext.task_dir
|
||||
ELIF --plan <path>:
|
||||
plan_path = <path>
|
||||
task_dir = {dirname(path)}/.task/
|
||||
ELSE:
|
||||
Scan .workflow/.doc-index/planning/ for most recent session
|
||||
plan_path = {latest_session}/plan.json
|
||||
task_dir = {latest_session}/.task/
|
||||
```
|
||||
|
||||
### 1.2 Load Plan & Tasks
|
||||
|
||||
- Read `plan.json` — validate against plan-overview-base-schema
|
||||
- Read all `TASK-*.json` from `.task/` directory — validate against task-schema
|
||||
- Read `doc-index.json` from `.workflow/.doc-index/`
|
||||
|
||||
### 1.3 Pre-Load Doc Context
|
||||
|
||||
For each task with `doc_context`:
|
||||
- Load referenced `feature_docs` (feature-maps/{slug}.md)
|
||||
- Load referenced `component_docs` (tech-registry/{slug}.md)
|
||||
- Load ADR excerpts from doc-index `architectureDecisions[]`
|
||||
- Extract requirement acceptance criteria from doc-index `requirements[]`
|
||||
- Load `doc_context.symbol_docs[]` documentation content (if present)
|
||||
|
||||
### 1.4 Echo Strategy
|
||||
|
||||
Display execution summary:
|
||||
|
||||
```
|
||||
DDD Execute: {plan.summary}
|
||||
Complexity: {plan.complexity}
|
||||
Tasks: {plan.task_count}
|
||||
|
||||
Doc-Index Impact:
|
||||
Features: {doc_context.affected_features}
|
||||
Requirements: {doc_context.affected_requirements}
|
||||
Components: {doc_context.affected_components}
|
||||
Constraints: {doc_context.architecture_constraints}
|
||||
|
||||
Execution plan: {batch count} batches, {parallel tasks} parallel where possible
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Task Grouping & Batch Creation
|
||||
|
||||
### 2.1 Extract Dependencies
|
||||
|
||||
From each `TASK-*.json`, read `depends_on[]` to build dependency graph.
|
||||
|
||||
### 2.2 Group into Batches
|
||||
|
||||
```
|
||||
Batch 1: Tasks with no dependencies (depends_on: [])
|
||||
Batch 2: Tasks depending only on Batch 1 tasks
|
||||
Batch 3: Tasks depending on Batch 1 + 2 tasks
|
||||
...
|
||||
```
|
||||
|
||||
Within each batch, tasks with the same `parallel_group` can run concurrently.
|
||||
|
||||
### 2.3 Assign Executor per Task
|
||||
|
||||
| Signal | Executor |
|
||||
|--------|----------|
|
||||
| `meta.execution_config.method == "cli"` | CLI tool (gemini/codex/qwen) |
|
||||
| `meta.execution_config.method == "agent"` | Agent (code-developer/universal-executor) |
|
||||
| Default | Agent (code-developer) |
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Doc-Enriched Execution
|
||||
|
||||
For each task in batch order, build an enriched prompt:
|
||||
|
||||
### 3.1 Task Prompt Template
|
||||
|
||||
```markdown
|
||||
## Goal
|
||||
${plan.summary} — specifically: ${task.title}
|
||||
|
||||
## Document Context
|
||||
|
||||
### Feature: ${feature.name} (${feature.id})
|
||||
${feature-map content excerpt — overview + requirements section}
|
||||
|
||||
### Components
|
||||
${for each component in task.doc_context.component_ids:
|
||||
tech-registry excerpt — responsibility + code locations + key patterns}
|
||||
|
||||
### Symbol Documentation
|
||||
${if doc_context.symbol_docs is non-empty:
|
||||
for each component in doc_context.component_ids:
|
||||
#### ${component.name} Symbols (Top-5)
|
||||
${for each symbol in component.symbol_docs.slice(0, 5):
|
||||
- **${symbol.name}** (${symbol.type}): ${symbol.doc_summary}
|
||||
Source: `${symbol.source_path}` | Freshness: ${symbol.freshness}
|
||||
}
|
||||
}
|
||||
|
||||
### Architecture Constraints
|
||||
${for each ADR in task.doc_context.adr_ids:
|
||||
ADR title + decision + rationale from doc-index}
|
||||
|
||||
### Requirement Acceptance Criteria
|
||||
${for each requirement in task.doc_context.requirement_ids:
|
||||
requirement title + priority + success criteria from doc-index}
|
||||
|
||||
## Task Details
|
||||
${task.description}
|
||||
|
||||
### Files to Modify
|
||||
${task.files[] — path, action, changes}
|
||||
|
||||
### Implementation Steps
|
||||
${task.implementation[] — step-by-step guide}
|
||||
|
||||
## Done When
|
||||
${task.convergence.criteria[]}
|
||||
${task.convergence.verification}
|
||||
```
|
||||
|
||||
### 3.2 Execute Task
|
||||
|
||||
**Agent execution**:
|
||||
```
|
||||
Agent(subagent_type="code-developer", prompt="{enriched prompt}")
|
||||
```
|
||||
|
||||
**CLI execution**:
|
||||
```bash
|
||||
ccw cli -p "{enriched prompt}" --tool {cli_tool} --mode write
|
||||
```
|
||||
|
||||
### 3.3 Record & Persist Result
|
||||
|
||||
After each task completes:
|
||||
- Update `TASK-*.json` with `status`, `executed_at`, `result`
|
||||
- Track `result.files_modified` for impact verification
|
||||
- **Persist** result to `TASK-{id}.result.json` alongside the task file:
|
||||
|
||||
```json
|
||||
{
|
||||
"task_id": "TASK-001",
|
||||
"status": "completed|failed",
|
||||
"executed_at": "ISO8601",
|
||||
"executor": "code-developer|gemini|codex",
|
||||
"files_modified": [
|
||||
{ "path": "src/services/auth.ts", "action": "modified", "symbols_changed": ["AuthService.validate"] },
|
||||
{ "path": "src/routes/login.ts", "action": "created", "symbols_changed": ["loginRoute"] }
|
||||
],
|
||||
"convergence_result": {
|
||||
"criteria_met": ["Rate limiter middleware exists"],
|
||||
"criteria_unmet": [],
|
||||
"verification_output": "test output snippet..."
|
||||
},
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
This file serves as the durable handoff between execute and sync — survives process interruptions.
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Per-Batch Impact Verification
|
||||
|
||||
After each batch completes (unless `--skip-verify`):
|
||||
|
||||
### 4.1 Trace Changed Files
|
||||
|
||||
For each file modified in the batch:
|
||||
```
|
||||
changed_file → match to doc-index.technicalComponents[].codeLocations[].path
|
||||
→ component_ids → featureIds → requirementIds
|
||||
```
|
||||
|
||||
### 4.2 Scope Verification
|
||||
|
||||
Compare actual impact to planned impact:
|
||||
|
||||
```
|
||||
Planned scope:
|
||||
Features: [feat-auth]
|
||||
Components: [tech-auth-service, tech-user-model]
|
||||
|
||||
Actual impact:
|
||||
Features: [feat-auth] ← OK, within scope
|
||||
Components: [tech-auth-service, tech-user-model, tech-email-service]
|
||||
← WARNING: tech-email-service not in plan
|
||||
```
|
||||
|
||||
### 4.3 Flag Unexpected Impact
|
||||
|
||||
If changes affect features/components NOT in `plan.doc_context`:
|
||||
- **Warning**: Display unexpected impact
|
||||
- **No -y**: Ask user to confirm continuation
|
||||
- **With -y**: Log warning, continue execution
|
||||
|
||||
### 4.4 Skip Conditions
|
||||
|
||||
Skip verification when:
|
||||
- `--skip-verify` flag is set
|
||||
- Only 1 batch (no intermediate verification needed for simple plans)
|
||||
|
||||
---
|
||||
|
||||
## Step 4.5: Post-Execution Verify Gate
|
||||
|
||||
After all batches complete, before doc sync (unless `--skip-verify`):
|
||||
|
||||
### 4.5.1 Convergence Verification
|
||||
|
||||
For each completed task with `convergence.verification`:
|
||||
```
|
||||
Execute: {task.convergence.verification}
|
||||
→ e.g., "npm test -- --grep rate-limit"
|
||||
Record: pass/fail → update TASK-{id}.result.json.convergence_result
|
||||
```
|
||||
|
||||
### 4.5.2 Build & Lint Check
|
||||
|
||||
```
|
||||
Run project build command (if configured):
|
||||
→ npm run build / tsc --noEmit / etc.
|
||||
Run project lint command (if configured):
|
||||
→ npm run lint / eslint src/ / etc.
|
||||
```
|
||||
|
||||
If build or lint fails:
|
||||
- **No -y**: Display errors, ask user: fix now / continue anyway / abort
|
||||
- **With -y**: Log warning, continue (non-blocking)
|
||||
|
||||
### 4.5.3 Regression Test
|
||||
|
||||
```
|
||||
Run project test suite:
|
||||
→ npm test / pytest / etc.
|
||||
Compare: test results before execution (baseline) vs after
|
||||
```
|
||||
|
||||
If tests fail:
|
||||
- **No -y**: Display failures, ask user: fix now / skip sync / abort
|
||||
- **With -y**: Log failures as warning in execution results, continue
|
||||
|
||||
### 4.5.4 Verify Summary
|
||||
|
||||
```
|
||||
Verify Gate Results:
|
||||
Convergence: {passed}/{total} tasks verified
|
||||
Build: pass|fail|skipped
|
||||
Lint: pass|fail|skipped
|
||||
Tests: {passed}/{total} ({new_failures} regressions)
|
||||
|
||||
Gate: PASS / WARN (continue with warnings) / FAIL (blocked)
|
||||
```
|
||||
|
||||
### 4.5.5 Persist Verify Manifest
|
||||
|
||||
Write `execution-manifest.json` to session folder:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "{session-id}",
|
||||
"plan_path": "planning/{slug}/plan.json",
|
||||
"completed_at": "ISO8601",
|
||||
"tasks": [
|
||||
{
|
||||
"task_id": "TASK-001",
|
||||
"status": "completed",
|
||||
"result_file": ".task/TASK-001.result.json"
|
||||
}
|
||||
],
|
||||
"files_modified": [
|
||||
{ "path": "src/services/auth.ts", "action": "modified", "task_id": "TASK-001" },
|
||||
{ "path": "src/routes/login.ts", "action": "created", "task_id": "TASK-001" }
|
||||
],
|
||||
"verify": {
|
||||
"convergence": { "passed": 2, "total": 2 },
|
||||
"build": "pass",
|
||||
"lint": "pass",
|
||||
"tests": { "passed": 42, "total": 42, "regressions": 0 },
|
||||
"gate": "PASS"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This manifest is the **single source of truth** consumed by `ddd:sync --from-manifest`.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Post-Completion Doc Sync
|
||||
|
||||
After all batches complete (unless `--skip-sync`):
|
||||
|
||||
### 5.1 Auto-Trigger ddd:sync
|
||||
|
||||
```
|
||||
Invoke /ddd:sync [-y] --task-id {session-id} --from-manifest {session}/execution-manifest.json "{plan.summary}"
|
||||
```
|
||||
|
||||
Note: `/ddd:sync` automatically creates a backup of `doc-index.json` before modifications.
|
||||
|
||||
When `--from-manifest` is provided, sync uses the **execution manifest** as its primary data source instead of git diff. This ensures:
|
||||
- Precise file-level and symbol-level change tracking (from TASK-*.result.json)
|
||||
- Task-to-file attribution (which task modified which file)
|
||||
- Convergence verification results carried forward
|
||||
- Survives process interruptions (manifest is persisted to disk)
|
||||
|
||||
Fallback: If manifest is unavailable (e.g., manual mode), sync falls back to git diff discovery.
|
||||
|
||||
### 5.2 Generate Action Log
|
||||
|
||||
Create action entry with:
|
||||
- All tasks executed and their results
|
||||
- Files modified across all batches
|
||||
- Features and requirements addressed
|
||||
|
||||
### 5.3 Update Feature Status
|
||||
|
||||
Based on execution results:
|
||||
- Requirements with verified convergence → update status
|
||||
- Features with all requirements met → `status: "implemented"`
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Summary & Follow-up
|
||||
|
||||
### 6.1 Execution Results
|
||||
|
||||
```
|
||||
DDD Execute Complete
|
||||
|
||||
Tasks: {completed}/{total} ({failed} failed)
|
||||
Files modified: {count}
|
||||
Batches: {batch_count}
|
||||
|
||||
Doc-Index Changes:
|
||||
Features updated: {list}
|
||||
Components updated: {list}
|
||||
New components registered: {list}
|
||||
Requirements addressed: {list}
|
||||
|
||||
Convergence:
|
||||
{for each task: task.id — criteria met: X/Y}
|
||||
```
|
||||
|
||||
### 6.2 Follow-up Suggestions
|
||||
|
||||
Based on execution results, suggest:
|
||||
- **New issues**: If unexpected scope expansion was detected
|
||||
- **Additional tests**: If convergence criteria only partially met
|
||||
- **Documentation gaps**: If new components were created without docs
|
||||
- **Next tasks**: If plan had tasks marked as future/deferred
|
||||
|
||||
---
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-y, --yes` | Auto-confirm, auto-sync |
|
||||
| `--skip-sync` | Skip post-completion ddd:sync (Step 5) |
|
||||
| `--skip-verify` | Skip per-batch impact verification (Step 4) AND post-execution verify gate (Step 4.5) |
|
||||
| `--plan <path>` | Explicit plan.json path |
|
||||
| `--in-memory` | Accept executionContext from ddd:plan handoff |
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Input from**: `/ddd:plan` output (plan.json + TASK-*.json), `doc-index.json`
|
||||
- **Output to**: Updated `doc-index.json` (via ddd:sync), `TASK-*.result.json` (per-task), `execution-manifest.json` (session-level)
|
||||
- **Schemas**: `plan-overview-ddd-schema.json` (input), `task-schema.json` + `task-ddd-extension-schema.json` (input), `doc-index.json` (enrichment)
|
||||
- **Delegates to**: `/ddd:sync` for post-completion synchronization
|
||||
@@ -1,212 +0,0 @@
|
||||
---
|
||||
name: index-build
|
||||
description: Build document index from spec-generator outputs + codebase mapping. Requires existing spec session. For projects without specs, use /ddd:scan instead.
|
||||
argument-hint: "[-y|--yes] [-s|--spec <spec-session-id>] [--from-scratch]"
|
||||
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Auto-confirm all decisions, use inferred mappings, skip interactive review.
|
||||
|
||||
# DDD Index Build Command (/ddd:index-build)
|
||||
|
||||
## Purpose
|
||||
|
||||
From **spec-generator outputs** (requirements, architecture, epics), construct the central document index and map spec entities to actual code locations.
|
||||
|
||||
```
|
||||
Spec outputs (REQ, ADR, EPIC) + Codebase → doc-index.json
|
||||
```
|
||||
|
||||
> **No spec?** Use `/ddd:scan` instead — it reverse-engineers the index from code alone.
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- At least one spec session in `.workflow/.doc-index/specs/` or `.workflow/.spec/`
|
||||
- If no spec found → error with suggestion: "No spec session found. Run /ddd:scan for code-first indexing, or /spec-generator to create specs."
|
||||
|
||||
## Storage Location
|
||||
|
||||
```
|
||||
.workflow/.doc-index/
|
||||
├── doc-index.json ← Central index (primary output)
|
||||
├── specs/ ← Spec-generator outputs
|
||||
│ └── SPEC-{slug}-{date}/
|
||||
├── feature-maps/ ← Feature documentation (from Epics)
|
||||
│ ├── _index.md
|
||||
│ └── {feature-slug}.md
|
||||
├── tech-registry/ ← Technical component docs (from code mapping)
|
||||
│ ├── _index.md
|
||||
│ └── {component-slug}.md
|
||||
└── action-logs/ ← Change history (initially empty)
|
||||
└── _index.md
|
||||
```
|
||||
|
||||
## Phase 1: Discover & Parse Spec Sources
|
||||
|
||||
### 1.1 Locate Spec Session
|
||||
|
||||
```
|
||||
IF --spec <id> provided:
|
||||
Load from .workflow/.doc-index/specs/<id>/ OR .workflow/.spec/<id>/
|
||||
ELSE:
|
||||
Scan for all SPEC-* directories
|
||||
IF multiple → present list, ask user to select (-y picks latest)
|
||||
IF none → ERROR: "No spec session found. Use /ddd:scan or /spec-generator."
|
||||
```
|
||||
|
||||
### 1.2 Migrate Specs (if needed)
|
||||
|
||||
If spec in `.workflow/.spec/` but not in `.workflow/.doc-index/specs/`:
|
||||
- Copy to `.workflow/.doc-index/specs/`
|
||||
- Preserve original (backward compatibility)
|
||||
|
||||
### 1.3 Extract Structured Entities
|
||||
|
||||
| Source File | Extract To |
|
||||
|------------|------------|
|
||||
| `spec-config.json` | project name, domain, spec_type |
|
||||
| `glossary.json` | → index glossary[] |
|
||||
| `product-brief.md` | vision, goals |
|
||||
| `requirements/REQ-*.md` | → index requirements[] (with MoSCoW priority) |
|
||||
| `requirements/NFR-*.md` | → index requirements[] (non-functional) |
|
||||
| `architecture/ADR-*.md` | → index architectureDecisions[] |
|
||||
| `epics/EPIC-*.md` | → feature grouping seeds |
|
||||
|
||||
## Phase 2: Codebase Mapping
|
||||
|
||||
Map spec entities to actual code locations using Gemini:
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Map codebase to specification entities for documentation indexing.
|
||||
TASK:
|
||||
• Scan the codebase and identify all major modules/components
|
||||
• For each component: extract file paths, exported symbols (classes, functions, types)
|
||||
• Match components to these specification entities by name/domain similarity:
|
||||
Requirements: {REQ-001: desc, REQ-002: desc, ...extracted from Phase 1}
|
||||
Architecture decisions: {ADR-001: title, ...extracted from Phase 1}
|
||||
• Report unmatched components (exist in code but no spec counterpart)
|
||||
• Report unmatched requirements (in spec but no code found)
|
||||
MODE: analysis
|
||||
CONTEXT: @**/*
|
||||
EXPECTED: JSON: { components: [{ name, type, files, symbols, matched_req_ids, matched_adr_id, is_orphan }], unmatched_reqs: [REQ-NNN] }
|
||||
CONSTRAINTS: Focus on source directories | Ignore node_modules, dist, build" --tool gemini --mode analysis
|
||||
```
|
||||
|
||||
### 2.1 Generate Component IDs & Link
|
||||
|
||||
For each discovered component:
|
||||
- ID: `tech-{kebab-case-name}`
|
||||
- Link to matched `REQ-NNN` and `ADR-NNN`
|
||||
- Flag orphans for user review
|
||||
|
||||
## Phase 3: Build Feature Map (from Epics)
|
||||
|
||||
### 3.1 Epic → Feature Mapping
|
||||
|
||||
```
|
||||
Each EPIC-NNN → one feat-{slug}
|
||||
- id: feat-{slug} (from epic slug)
|
||||
- name: from Epic name
|
||||
- epicId: EPIC-NNN
|
||||
- status: inferred from code mapping
|
||||
- all requirements have matched components → "implemented"
|
||||
- some matched → "in-progress"
|
||||
- none matched → "planned"
|
||||
- requirementIds: from Epic's stories → requirement links
|
||||
- tags: from domain keywords
|
||||
```
|
||||
|
||||
### 3.2 Document Generation (delegated)
|
||||
|
||||
Feature-map and tech-registry document generation is handled by `/ddd:doc-generate` in Phase 5.
|
||||
Phase 3 only builds the data structures (feature → requirement → component mappings) that doc-generate consumes.
|
||||
|
||||
## Phase 4: Assemble doc-index.json
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"project": "{project-name}",
|
||||
"build_path": "spec-first",
|
||||
"spec_session": "SPEC-{slug}-{date}",
|
||||
"last_updated": "ISO8601",
|
||||
"glossary": [
|
||||
{ "id": "gloss-{slug}", "term": "Term", "definition": "...", "aliases": [], "category": "core|technical|business" }
|
||||
],
|
||||
"features": [
|
||||
{ "id": "feat-{slug}", "name": "...", "epicId": "EPIC-NNN", "status": "...", "docPath": "feature-maps/{slug}.md", "requirementIds": ["REQ-NNN"], "tags": [] }
|
||||
],
|
||||
"requirements": [
|
||||
{ "id": "REQ-NNN", "title": "...", "source": "spec", "priority": "Must|Should|Could|Won't", "sourcePath": "specs/SPEC-*/requirements/REQ-NNN-*.md", "techComponentIds": ["tech-{slug}"], "featureId": "feat-{slug}" }
|
||||
],
|
||||
"technicalComponents": [
|
||||
{ "id": "tech-{slug}", "name": "...", "type": "...", "responsibility": "...", "adrId": "ADR-NNN|null", "docPath": "tech-registry/{slug}.md", "codeLocations": [{ "path": "...", "symbols": [], "lineRange": [0,0] }], "dependsOn": [], "featureIds": ["feat-{slug}"], "actionIds": [] }
|
||||
],
|
||||
"architectureDecisions": [
|
||||
{ "id": "ADR-NNN", "title": "...", "source": "spec", "sourcePath": "specs/SPEC-*/architecture/ADR-NNN-*.md", "componentIds": ["tech-{slug}"] }
|
||||
],
|
||||
"actions": []
|
||||
}
|
||||
```
|
||||
|
||||
### Merge with Existing Code-First Index
|
||||
|
||||
If a code-first index exists (from prior `/ddd:scan`):
|
||||
- Replace `IREQ-NNN` with matching `REQ-NNN` where content overlaps
|
||||
- Keep `IREQ-NNN` without spec counterpart (mark `source: "legacy-inferred"`)
|
||||
- Replace `IADR-NNN` with `ADR-NNN` where applicable
|
||||
- Update `build_path` to `"spec-first"`
|
||||
- Preserve existing `tech-*` components (update links only)
|
||||
|
||||
## Phase 5: Generate Documents
|
||||
|
||||
Delegate all document generation to `/ddd:doc-generate`:
|
||||
|
||||
```
|
||||
Invoke /ddd:doc-generate [-y]
|
||||
```
|
||||
|
||||
This generates the complete document tree (Layer 3 → 2 → 1):
|
||||
- `tech-registry/{slug}.md` — component docs from Phase 2 mapping (Layer 3)
|
||||
- `feature-maps/{slug}.md` — feature docs from Phase 3 mapping (Layer 2)
|
||||
- `_index.md`, `README.md`, `ARCHITECTURE.md`, `SCHEMA.md` — index/overview docs (Layer 1)
|
||||
|
||||
See `/ddd:doc-generate` for full details on generation strategy and flags.
|
||||
|
||||
## Phase 6: Coverage Report
|
||||
|
||||
```
|
||||
Index Build Report (spec-first)
|
||||
|
||||
Spec: {session-id}
|
||||
Features: {N} (from {N} Epics)
|
||||
Requirements: {N} (REQ: {n}, NFR: {n})
|
||||
Components: {N} ({orphan} orphans without spec match)
|
||||
ADRs: {N}
|
||||
|
||||
Mapping Coverage:
|
||||
Requirements → Components: {%} ({unmapped} unmapped)
|
||||
Components → Features: {%}
|
||||
Epics → Features: 100%
|
||||
|
||||
Gaps:
|
||||
- {N} requirements have no matching code component
|
||||
- {N} code components are not linked to any requirement
|
||||
```
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-y, --yes` | Skip all interactive prompts |
|
||||
| `-s, --spec <id>` | Use specific spec session |
|
||||
| `--from-scratch` | Delete existing index and rebuild |
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Input from**: `spec-generator` outputs, codebase, existing `/ddd:scan` index
|
||||
- **Delegates to**: `/ddd:doc-generate` (Phase 5, full document generation)
|
||||
- **Output to**: `ddd:plan`, `ddd:sync`, `ddd:update`
|
||||
- **Upgrades**: Can merge with prior code-first (`/ddd:scan`) index
|
||||
@@ -1,611 +0,0 @@
|
||||
---
|
||||
name: plan
|
||||
description: Document-driven planning pipeline — queries doc-index, explores codebase with doc-aware angles, clarifies ambiguities, and produces unified plan.json + TASK-*.json artifacts with doc_context traceability.
|
||||
argument-hint: "[-y|--yes] [--explore] [--skip-explore] [--skip-clarify] \"task description or feature keyword\""
|
||||
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Write(*), mcp__ace-tool__search_context(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Skip clarification (Phase 3), auto-select ddd:execute (Phase 5), skip interactive refinement.
|
||||
|
||||
# DDD Plan Command (/ddd:plan)
|
||||
|
||||
## Purpose
|
||||
|
||||
Full planning pipeline for document-driven development. Unlike simple context lookup, this command:
|
||||
1. **Queries** the doc-index for instant context (features, requirements, components, ADRs)
|
||||
2. **Explores** the codebase with doc-index-informed angles (not generic presets)
|
||||
3. **Clarifies** ambiguities from exploration results and doc-index gaps
|
||||
4. **Plans** with unified schema output (plan.json + TASK-*.json with doc_context)
|
||||
5. **Hands off** to ddd:execute or other execution engines
|
||||
|
||||
### Key Differentiation from lite-plan
|
||||
- Phase 1 provides instant context from doc-index (no cold-start exploration)
|
||||
- Exploration angles are doc-index-informed (not generic preset selection)
|
||||
- Tasks carry doc_context for traceability (features → requirements → code)
|
||||
- Architecture decisions (ADRs) automatically surface as constraints
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- `doc-index.json` must exist at `.workflow/.doc-index/doc-index.json`
|
||||
- If not found → suggest running `/ddd:index-build` or `/ddd:scan` first
|
||||
|
||||
## Session Folder
|
||||
|
||||
```
|
||||
.workflow/.doc-index/planning/{task-slug}-{YYYY-MM-DD}/
|
||||
├── exploration-{angle}.json # Per-angle exploration (Phase 2)
|
||||
├── explorations-manifest.json # Exploration index
|
||||
├── plan.json # Plan overview (Phase 4)
|
||||
├── planning-context.md # Legacy context package (Phase 0+1 combined)
|
||||
├── .process/
|
||||
│ └── doc-context-package.json # Bundled doc_context (Phase 1.8)
|
||||
└── .task/
|
||||
├── TASK-001.json
|
||||
└── TASK-002.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 0: Parse Task Intent (enhanced)
|
||||
|
||||
### 0.1 Extract Keywords
|
||||
|
||||
From the user's task description, extract:
|
||||
- **Domain keywords**: feature names, module names, business terms
|
||||
- **Technical keywords**: file paths, class names, function names
|
||||
- **Action type**: feature | bugfix | refactor | optimization | migration
|
||||
|
||||
### 0.2 Glossary Match
|
||||
|
||||
Cross-reference extracted keywords against `doc-index.json.glossary[]`:
|
||||
- Match terms and aliases
|
||||
- Expand user's vocabulary with canonical terms
|
||||
|
||||
### 0.3 Classify Complexity
|
||||
|
||||
Assess task complexity based on:
|
||||
- Number of features potentially affected (from keyword matching)
|
||||
- Whether new components are needed or existing ones modified
|
||||
- Cross-feature impact (single feature vs multiple)
|
||||
|
||||
| Signal | Complexity |
|
||||
|--------|-----------|
|
||||
| Single feature, existing components | Low |
|
||||
| 1-2 features, some new components | Medium |
|
||||
| 3+ features, new architecture needed | High |
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Doc-Index Query
|
||||
|
||||
### 1.0 Schema Version Check (TASK-006)
|
||||
|
||||
Before querying doc-index, verify schema compatibility:
|
||||
|
||||
```javascript
|
||||
const docIndex = JSON.parse(Read('.workflow/.doc-index/doc-index.json'));
|
||||
const schemaVersion = docIndex.schema_version || '0.0'; // Default for legacy
|
||||
|
||||
if (schemaVersion !== '1.0') {
|
||||
console.warn(`Schema version mismatch: found ${schemaVersion}, expected 1.0`);
|
||||
console.warn('Consider running schema migration or regenerating doc-index with /ddd:scan');
|
||||
// Continue with degraded functionality - may encounter missing fields
|
||||
}
|
||||
```
|
||||
|
||||
**Graceful degradation**: If version mismatch detected → log warning → continue with caution (some features may not work as expected).
|
||||
|
||||
### 1.1 Feature Search
|
||||
|
||||
```
|
||||
Search doc-index.json.features[] where:
|
||||
- name CONTAINS keyword (fuzzy)
|
||||
- tags INTERSECT keywords
|
||||
- requirementIds link to matching requirements
|
||||
→ Output: matched feature IDs + names
|
||||
```
|
||||
|
||||
### 1.2 Requirement Search
|
||||
|
||||
```
|
||||
Search doc-index.json.requirements[] where:
|
||||
- title CONTAINS keyword
|
||||
- id matches explicit REQ-NNN reference
|
||||
- featureId matches found features
|
||||
→ Output: matched requirement IDs + titles + priorities
|
||||
```
|
||||
|
||||
### 1.3 Component Search
|
||||
|
||||
```
|
||||
Search doc-index.json.technicalComponents[] where:
|
||||
- name CONTAINS keyword
|
||||
- codeLocations[].path CONTAINS file path keyword
|
||||
- codeLocations[].symbols CONTAINS symbol keyword
|
||||
- featureIds INTERSECT found features
|
||||
→ Output: matched component IDs + code locations
|
||||
```
|
||||
|
||||
### 1.4 ADR Search
|
||||
|
||||
```
|
||||
Search doc-index.json.architectureDecisions[] where:
|
||||
- componentIds INTERSECT found components
|
||||
→ Output: matched ADR IDs + titles
|
||||
```
|
||||
|
||||
### 1.5 Action History Search
|
||||
|
||||
```
|
||||
Search doc-index.json.actions[] where:
|
||||
- related to found features or components
|
||||
→ Output: recent actions with descriptions
|
||||
```
|
||||
|
||||
### 1.6 Build Impact Map
|
||||
|
||||
Assemble all found references into a structured impact map:
|
||||
|
||||
```json
|
||||
{
|
||||
"affected_features": ["feat-auth"],
|
||||
"affected_requirements": ["REQ-001", "REQ-002"],
|
||||
"affected_components": ["tech-auth-service", "tech-user-model"],
|
||||
"architecture_constraints": ["ADR-001"],
|
||||
"recent_actions": ["task-123"],
|
||||
"complexity": "Medium"
|
||||
}
|
||||
```
|
||||
|
||||
Save as `planning-context.md` (legacy format for backward compatibility).
|
||||
|
||||
### Phase 1.7: Symbol Query (DeepWiki Bridge)
|
||||
|
||||
If DeepWiki is available (`deepwiki_feature_to_symbol_index` exists in doc-index.json):
|
||||
|
||||
1. Collect all `codeLocations[].path` from matched `technicalComponents[]`
|
||||
2. Query DeepWiki: `POST /api/deepwiki/symbols-for-paths { paths: unique_paths }`
|
||||
3. Build symbol_docs by component, sorted by type priority (class > function > method)
|
||||
4. Populate `doc_context.symbol_docs[]` with Top-5 symbols per component
|
||||
|
||||
**Graceful degradation**: If DeepWiki unavailable → log warning → skip symbol injection → continue flow.
|
||||
|
||||
### Phase 1.8: Persist Doc Context Package
|
||||
|
||||
After building doc_context (including symbol_docs from Phase 1.7), persist it as a reusable context package:
|
||||
|
||||
1. Bundle doc_context into JSON structure:
|
||||
```json
|
||||
{
|
||||
"affected_features": ["feat-auth"],
|
||||
"affected_requirements": ["REQ-001", "REQ-002"],
|
||||
"affected_components": ["tech-auth-service"],
|
||||
"architecture_constraints": ["ADR-001"],
|
||||
"index_path": ".workflow/.doc-index/doc-index.json",
|
||||
"symbol_docs": [...]
|
||||
}
|
||||
```
|
||||
|
||||
2. Write to session folder: `{sessionFolder}/.process/doc-context-package.json`
|
||||
3. Store relative path for task.json population: `../.process/doc-context-package.json`
|
||||
|
||||
**Error handling**: If write fails → log warning → continue without context package (backward compatible).
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Doc-Index-Guided Exploration (NEW)
|
||||
|
||||
Use Phase 1 results to **SELECT exploration angles intelligently**:
|
||||
|
||||
### 2.1 Angle Selection Logic
|
||||
|
||||
| Phase 1 Signal | Add Exploration Angle |
|
||||
|----------------|----------------------|
|
||||
| feat-auth or security-related ADR affected | `security` |
|
||||
| Multiple features crossed (2+) | `integration-points` |
|
||||
| New component needed (no matching tech-*) | `architecture` |
|
||||
| Performance-related requirements | `performance` |
|
||||
| Default (always included) | `patterns` + `dependencies` |
|
||||
|
||||
Select 1-4 angles total. More angles for higher complexity.
|
||||
|
||||
### 2.2 Skip & Trigger Conditions
|
||||
|
||||
| Complexity | Default Behavior | Override |
|
||||
|-----------|-----------------|---------|
|
||||
| **Low** | Auto-skip Phase 2 | `--explore` forces exploration |
|
||||
| **Medium** | Ask user (unless `-y` → skip) | `--explore` forces, `--skip-explore` forces skip |
|
||||
| **High** | Always run | `--skip-explore` forces skip |
|
||||
|
||||
Skip Phase 2 entirely when:
|
||||
- Complexity is Low AND `--explore` not set
|
||||
- OR `--skip-explore` flag is set
|
||||
- OR `-y` flag AND complexity is Medium
|
||||
|
||||
### 2.3 Parallel Exploration
|
||||
|
||||
Launch 1-4 parallel `cli-explore-agent` runs:
|
||||
|
||||
```
|
||||
For each selected angle:
|
||||
Agent(subagent_type="cli-explore-agent", prompt="
|
||||
Explore codebase for: {user task description}
|
||||
Angle: {angle}
|
||||
|
||||
## Doc-Index Context (pre-loaded)
|
||||
Features affected: {feature names + IDs}
|
||||
Components: {component names + code locations}
|
||||
Requirements: {requirement titles}
|
||||
Architecture decisions: {ADR titles + decisions}
|
||||
|
||||
Focus exploration on {angle}-specific concerns.
|
||||
Output: explore-json-schema format.
|
||||
")
|
||||
```
|
||||
|
||||
Each agent receives doc-index context (feature-maps, tech-registry docs) to avoid cold-start.
|
||||
|
||||
### 2.4 Save Exploration Results
|
||||
|
||||
- Each exploration → `exploration-{angle}.json` (explore-json-schema)
|
||||
- Manifest → `explorations-manifest.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"explorations": [
|
||||
{ "angle": "patterns", "path": "exploration-patterns.json", "file_count": 12 },
|
||||
{ "angle": "security", "path": "exploration-security.json", "file_count": 8 }
|
||||
],
|
||||
"total_files_discovered": 18,
|
||||
"timestamp": "ISO8601"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Clarification (NEW)
|
||||
|
||||
### 3.1 Aggregate Clarification Needs
|
||||
|
||||
Collect from three sources:
|
||||
1. **Exploration results**: `clarification_needs[]` from each exploration JSON
|
||||
2. **Doc-index gaps**: unmapped requirements, orphan components, missing feature coverage
|
||||
3. **Conflicting constraints**: contradictory architecture decisions, requirement priority conflicts
|
||||
|
||||
### 3.2 Deduplicate & Batch
|
||||
|
||||
- Merge duplicate/similar questions across exploration angles
|
||||
- Group into rounds (max 4 questions per AskUserQuestion call)
|
||||
- Prioritize: blocking questions first, nice-to-have last
|
||||
|
||||
### 3.3 Skip Conditions
|
||||
|
||||
Skip Phase 3 when:
|
||||
- `-y` flag is set
|
||||
- `--skip-clarify` flag is set
|
||||
- No clarification needs collected from any source
|
||||
- Complexity is Low AND Phase 2 was skipped (no exploration results to aggregate)
|
||||
|
||||
### 3.4 Execute Clarification
|
||||
|
||||
```
|
||||
AskUserQuestion(questions=[
|
||||
{
|
||||
question: "Which authentication strategy should the new endpoint use?",
|
||||
header: "Auth strategy",
|
||||
options: [
|
||||
{ label: "JWT Bearer (Recommended)", description: "Consistent with ADR-001 and existing auth middleware" },
|
||||
{ label: "API Key", description: "Simpler but inconsistent with current architecture" },
|
||||
{ label: "OAuth2", description: "Most flexible but higher implementation cost" }
|
||||
],
|
||||
multiSelect: false
|
||||
}
|
||||
])
|
||||
```
|
||||
|
||||
Feed answers back into Phase 4 as constraints.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Task Planning (NEW — produces plan.json + TASK-*.json)
|
||||
|
||||
### 4.1 Planning Strategy Selection
|
||||
|
||||
| Complexity | Strategy |
|
||||
|-----------|---------|
|
||||
| Low | Direct Claude planning (inline) |
|
||||
| Medium | cli-lite-planning-agent with doc-index context |
|
||||
| High | cli-lite-planning-agent with full exploration + doc-index context |
|
||||
|
||||
### 4.2 Planning Input Assembly
|
||||
|
||||
Combine:
|
||||
- User's original task description
|
||||
- Phase 1 impact map (features, requirements, components, ADRs)
|
||||
- Phase 2 exploration results (if executed)
|
||||
- Phase 3 clarification answers (if collected)
|
||||
- Relevant feature-map and tech-registry doc excerpts
|
||||
|
||||
### 4.3 Execute Planning
|
||||
|
||||
For **Low complexity** (direct):
|
||||
```
|
||||
Generate plan.json + TASK-*.json directly based on assembled context.
|
||||
```
|
||||
|
||||
For **Medium/High complexity**:
|
||||
```
|
||||
Agent(subagent_type="cli-lite-planning-agent", prompt="
|
||||
Task: {user task description}
|
||||
|
||||
## Doc-Index Impact Map
|
||||
{Phase 1 results}
|
||||
|
||||
## Exploration Context
|
||||
{Phase 2 results summary}
|
||||
|
||||
## Clarification Answers
|
||||
{Phase 3 answers}
|
||||
|
||||
## Architecture Constraints
|
||||
{ADR excerpts}
|
||||
|
||||
Generate plan following plan-overview-base-schema.
|
||||
Generate tasks following task-schema.
|
||||
Include doc_context in both plan.json and each TASK-*.json.
|
||||
")
|
||||
```
|
||||
|
||||
### 4.3.1 Populate Task Artifacts (TASK-002)
|
||||
|
||||
After task generation, enrich each TASK-*.json with artifacts[] field:
|
||||
|
||||
1. Load doc-index.json from `.workflow/.doc-index/doc-index.json`
|
||||
2. For each task, extract feature_ids from task.doc_context
|
||||
3. Filter doc-index features/requirements matching task scope:
|
||||
- Match by feature_ids in task.doc_context.feature_ids
|
||||
- Include linked requirements via requirementIds
|
||||
- Include linked components via componentIds
|
||||
4. Populate task.artifacts[] with filtered references:
|
||||
|
||||
```json
|
||||
{
|
||||
"artifacts": [
|
||||
{
|
||||
"type": "feature_spec",
|
||||
"source": "doc-index",
|
||||
"path": ".workflow/.doc-index/feature-maps/auth.md",
|
||||
"feature_id": "feat-auth",
|
||||
"usage": "Reference for authentication requirements"
|
||||
},
|
||||
{
|
||||
"type": "requirement",
|
||||
"source": "doc-index",
|
||||
"path": ".workflow/.doc-index/doc-index.json#requirements[0]",
|
||||
"feature_id": "feat-auth",
|
||||
"requirement_id": "REQ-001",
|
||||
"usage": "Acceptance criteria source"
|
||||
},
|
||||
{
|
||||
"type": "component_doc",
|
||||
"source": "doc-index",
|
||||
"path": ".workflow/.doc-index/tech-registry/auth-service.md",
|
||||
"component_id": "tech-auth-service",
|
||||
"usage": "Implementation reference"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Loading pattern** (following brainstorm pattern from action-planning-agent.md:200-214):
|
||||
- Load doc-index.json once for catalog
|
||||
- Filter by task-relevant feature IDs (1-3 per task)
|
||||
- Only include artifacts directly referenced in task scope
|
||||
- Use relative paths from task file location
|
||||
|
||||
### 4.3.2 Populate Context Package Path (TASK-001)
|
||||
|
||||
Set context_package_path field in each TASK-*.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"context_package_path": "../.process/doc-context-package.json"
|
||||
}
|
||||
```
|
||||
|
||||
Relative path from `.task/TASK-*.json` to `.process/doc-context-package.json`.
|
||||
|
||||
### 4.3.3 Add Navigation Links Block (TASK-003)
|
||||
|
||||
Add links{} navigation block to each TASK-*.json for improved discoverability:
|
||||
|
||||
```json
|
||||
{
|
||||
"links": {
|
||||
"plan": "../plan.json",
|
||||
"doc_index": "../../../doc-index.json",
|
||||
"feature_maps": [
|
||||
"../../../feature-maps/auth.md"
|
||||
],
|
||||
"related_tasks": [
|
||||
"TASK-002.json",
|
||||
"TASK-003.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Path computation**:
|
||||
- `plan`: Relative path from `.task/TASK-*.json` to `plan.json` (sibling of .task/)
|
||||
- `doc_index`: Relative path to `.workflow/.doc-index/doc-index.json`
|
||||
- `feature_maps`: Paths to feature-map docs from task.doc_context.feature_docs
|
||||
- `related_tasks`: Task IDs from task.depends_on or tasks sharing same feature_ids
|
||||
|
||||
**Backward compatibility**: links{} is optional field (task-schema allows additionalProperties).
|
||||
|
||||
### 4.4 Output Schema: plan.json
|
||||
|
||||
Follows `plan-overview-base-schema` with ddd-specific `doc_context` extension:
|
||||
|
||||
```json
|
||||
{
|
||||
"summary": "...",
|
||||
"approach": "...",
|
||||
"task_ids": ["TASK-001", "TASK-002"],
|
||||
"task_count": 2,
|
||||
"complexity": "Medium",
|
||||
"doc_context": {
|
||||
"affected_features": ["feat-auth"],
|
||||
"affected_requirements": ["REQ-001", "REQ-002"],
|
||||
"affected_components": ["tech-auth-service"],
|
||||
"architecture_constraints": ["ADR-001"],
|
||||
"index_path": ".workflow/.doc-index/doc-index.json",
|
||||
"symbol_docs": [
|
||||
{
|
||||
"symbol_urn": "deepwiki:symbol:<path>#L<start>-L<end>",
|
||||
"name": "SymbolName",
|
||||
"type": "class|function|method",
|
||||
"doc_summary": "Generated documentation summary...",
|
||||
"source_path": "src/path/to/file.ts",
|
||||
"doc_path": ".deepwiki/file.md",
|
||||
"freshness": "fresh|stale|unknown"
|
||||
}
|
||||
]
|
||||
},
|
||||
"_metadata": {
|
||||
"timestamp": "ISO8601",
|
||||
"source": "cli-lite-planning-agent",
|
||||
"plan_type": "feature",
|
||||
"schema_version": "2.0",
|
||||
"exploration_angles": ["patterns", "security"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 Output Schema: TASK-*.json
|
||||
|
||||
Follows `task-schema` with ddd-specific `doc_context` extension:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "TASK-001",
|
||||
"title": "Add rate limiting middleware",
|
||||
"description": "...",
|
||||
"depends_on": [],
|
||||
"convergence": {
|
||||
"criteria": ["Rate limiter middleware exists and is registered", "Tests pass"],
|
||||
"verification": "npm test -- --grep rate-limit",
|
||||
"definition_of_done": "API endpoints enforce rate limits per ADR-001 specifications"
|
||||
},
|
||||
"doc_context": {
|
||||
"feature_ids": ["feat-auth"],
|
||||
"requirement_ids": ["REQ-001"],
|
||||
"component_ids": ["tech-auth-service"],
|
||||
"adr_ids": ["ADR-001"],
|
||||
"feature_docs": ["feature-maps/auth.md"],
|
||||
"component_docs": ["tech-registry/auth-service.md"],
|
||||
"symbol_docs": [
|
||||
{
|
||||
"symbol_urn": "deepwiki:symbol:<path>#L<start>-L<end>",
|
||||
"name": "SymbolName",
|
||||
"type": "class|function|method",
|
||||
"doc_summary": "Generated documentation summary...",
|
||||
"source_path": "src/path/to/file.ts",
|
||||
"doc_path": ".deepwiki/file.md",
|
||||
"freshness": "fresh|stale|unknown"
|
||||
}
|
||||
]
|
||||
},
|
||||
"files": [...],
|
||||
"implementation": [...]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.6 Enrichment Rules
|
||||
|
||||
Each task is enriched with:
|
||||
- `feature_ids`, `requirement_ids`, `component_ids`, `adr_ids` — traced from Phase 1
|
||||
- Relevant feature-map and tech-registry doc paths
|
||||
- Requirement acceptance criteria as convergence criteria source
|
||||
- ADR decisions as implementation constraints
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Confirmation & Handoff Selection
|
||||
|
||||
### 5.1 Display Plan Summary
|
||||
|
||||
Show:
|
||||
- Plan overview (summary, approach, complexity)
|
||||
- Task list with dependencies
|
||||
- Doc-index impact: which features/requirements/components will be affected
|
||||
- Estimated scope
|
||||
|
||||
### 5.2 Handoff Options
|
||||
|
||||
| Option | Description | When |
|
||||
|--------|-------------|------|
|
||||
| **ddd:execute** | Document-aware execution (recommended) | Default for ddd workflow |
|
||||
| **lite-execute** | Standard execution (no doc awareness) | When doc traceability not needed |
|
||||
| **direct** | Output context, manual work | User prefers manual coding |
|
||||
| **stop** | Planning only, no execution | Research/analysis tasks |
|
||||
|
||||
### 5.3 Auto-Selection
|
||||
|
||||
With `-y`: auto-select `ddd:execute`.
|
||||
|
||||
Without `-y`: present options via AskUserQuestion.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Handoff
|
||||
|
||||
### 6.1 Build Execution Context
|
||||
|
||||
Build `executionContext` compatible with lite-execute format:
|
||||
|
||||
```json
|
||||
{
|
||||
"plan_path": ".workflow/.doc-index/planning/{slug}/plan.json",
|
||||
"task_dir": ".workflow/.doc-index/planning/{slug}/.task/",
|
||||
"doc_index_path": ".workflow/.doc-index/doc-index.json",
|
||||
"exploration_manifest": ".workflow/.doc-index/planning/{slug}/explorations-manifest.json",
|
||||
"original_input": "user's task description"
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 Invoke Selected Engine
|
||||
|
||||
| Selection | Action |
|
||||
|-----------|--------|
|
||||
| `ddd:execute` | Invoke `/ddd:execute --in-memory` with executionContext |
|
||||
| `lite-execute` | Invoke `/workflow:lite-execute` with plan.json path |
|
||||
| `direct` | Display context package + file list for manual work |
|
||||
| `stop` | Output plan summary, end here |
|
||||
|
||||
---
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-y, --yes` | Skip clarification, auto-select ddd:execute |
|
||||
| `--explore` | Force Phase 2 exploration even for Low complexity |
|
||||
| `--skip-explore` | Skip Phase 2 (doc-index-guided exploration) |
|
||||
| `--skip-clarify` | Skip Phase 3 (clarification) only |
|
||||
|
||||
## Output
|
||||
|
||||
- **Primary**: plan.json + TASK-*.json in session folder
|
||||
- **Secondary**: planning-context.md (legacy format)
|
||||
- **Exploration**: exploration-{angle}.json files (if Phase 2 ran)
|
||||
- **Console**: Plan summary with doc-index impact
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Input from**: `doc-index.json` (built by `/ddd:index-build` or `/ddd:scan`)
|
||||
- **Output to**: `/ddd:execute`, `/workflow:lite-execute`, `/ddd:sync` post-task
|
||||
- **Schemas**: `plan-overview-ddd-schema.json` (plan output), `task-schema.json` + `task-ddd-extension-schema.json` (task output), `explore-json-schema.json`
|
||||
- **Triggers**: Before any development task in ddd workflow
|
||||
@@ -1,365 +0,0 @@
|
||||
---
|
||||
name: scan
|
||||
description: Scan existing codebase to build document index without specs. Analyzes code structure, infers features, discovers components, and reverse-engineers project knowledge graph.
|
||||
argument-hint: "[-y|--yes] [--from-scratch] [--scope <dir>] \"optional project description\""
|
||||
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Auto-confirm feature groupings, component naming, skip interactive review.
|
||||
|
||||
# DDD Scan Command (/ddd:scan)
|
||||
|
||||
## Purpose
|
||||
|
||||
For **existing projects without specifications**: analyze codebase to construct the document index by reverse-engineering project structure. This is the code-first entry point — no spec-generator required.
|
||||
|
||||
```
|
||||
Codebase → Components → Features (inferred) → Requirements (inferred) → doc-index.json
|
||||
```
|
||||
|
||||
## When to Use
|
||||
|
||||
- Existing project, no spec-generator outputs
|
||||
- Want to start using doc-driven workflow on a legacy codebase
|
||||
- Quick project mapping for onboarding or audit
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- A codebase must exist (src/, lib/, app/, or similar source directories)
|
||||
- Git repository recommended (for action history seeding)
|
||||
|
||||
## Storage Location
|
||||
|
||||
```
|
||||
.workflow/.doc-index/
|
||||
├── doc-index.json ← Central index (primary output)
|
||||
├── feature-maps/ ← Inferred feature documentation
|
||||
│ ├── _index.md
|
||||
│ └── {feature-slug}.md
|
||||
├── tech-registry/ ← Discovered component documentation
|
||||
│ ├── _index.md
|
||||
│ └── {component-slug}.md
|
||||
└── action-logs/ ← Git history seeds
|
||||
├── _index.md
|
||||
└── {act-hash}.md
|
||||
```
|
||||
|
||||
## Phase 1: Project Structure Analysis
|
||||
|
||||
### 1.1 Framework & Stack Detection
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Analyze project structure, tech stack, and architecture for documentation indexing.
|
||||
TASK:
|
||||
• Detect language/framework from manifest files (package.json, go.mod, Cargo.toml, requirements.txt, etc.)
|
||||
• Map directory structure: source dirs, test dirs, config dirs, entry points
|
||||
• Identify architectural pattern: monolith, microservices, monorepo, library, CLI tool
|
||||
• Detect key dependencies and their roles (ORM, HTTP framework, auth library, etc.)
|
||||
• List all major source directories with brief purpose description
|
||||
MODE: analysis
|
||||
CONTEXT: @**/*
|
||||
EXPECTED: JSON with: {
|
||||
project_name, language, framework, architecture_pattern,
|
||||
source_dirs: [{ path, purpose, file_count }],
|
||||
dependencies: [{ name, role }],
|
||||
entry_points: [{ path, description }]
|
||||
}
|
||||
CONSTRAINTS: Prioritize source directories | Ignore node_modules, dist, build, vendor" --tool gemini --mode analysis
|
||||
```
|
||||
|
||||
### 1.2 Merge with project-tech.json
|
||||
|
||||
If `.workflow/project-tech.json` exists, merge to reduce redundant analysis.
|
||||
|
||||
## Phase 2: Component Discovery
|
||||
|
||||
### 2.1 Deep Module Scan
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Discover all significant code components/modules for documentation indexing.
|
||||
TASK:
|
||||
• For each source directory, identify distinct modules/components
|
||||
• For each component extract:
|
||||
- Name (class name, module name, or logical group)
|
||||
- Type: service | controller | model | util | hook | route | config | middleware | component
|
||||
- File paths (primary file + related files)
|
||||
- Exported symbols (public API: classes, functions, types, constants)
|
||||
- Internal dependencies: what other modules it imports from within the project
|
||||
- Responsibility: one-line description of what it does
|
||||
• Group small utility files under parent module when they share domain
|
||||
MODE: analysis
|
||||
CONTEXT: @{source_dirs from Phase 1}
|
||||
EXPECTED: JSON array: [{ name, type, files, symbols, depends_on, responsibility }]
|
||||
CONSTRAINTS: Focus on business logic | Min threshold: components with 2+ exports or clear domain purpose | Group utilities under parent domain" --tool gemini --mode analysis
|
||||
```
|
||||
|
||||
### 2.2 Generate Component IDs
|
||||
|
||||
For each discovered component:
|
||||
- ID: `tech-{kebab-case-name}` (e.g., `tech-auth-service`, `tech-user-model`)
|
||||
- Validate uniqueness, append counter on collision
|
||||
|
||||
### 2.3 Build Dependency Graph
|
||||
|
||||
From `depends_on` fields, construct internal dependency edges:
|
||||
```
|
||||
tech-auth-service → tech-user-model
|
||||
tech-auth-service → tech-jwt-util
|
||||
tech-order-controller → tech-auth-service
|
||||
```
|
||||
|
||||
## Phase 3: Feature Inference
|
||||
|
||||
**Key step: group components into logical features without formal specs.**
|
||||
|
||||
### 3.1 Inference Strategy (priority order)
|
||||
|
||||
```
|
||||
Strategy 1 — Directory grouping:
|
||||
src/auth/** → feat-auth
|
||||
src/orders/** → feat-orders
|
||||
src/payments/** → feat-payments
|
||||
|
||||
Strategy 2 — Route/endpoint grouping (web apps):
|
||||
/api/users/* → feat-user-management
|
||||
/api/orders/* → feat-order-management
|
||||
|
||||
Strategy 3 — Dependency clustering:
|
||||
Components that heavily import each other → same feature
|
||||
|
||||
Strategy 4 — Domain keyword extraction:
|
||||
Class names + file names → domain terms → feature names
|
||||
```
|
||||
|
||||
### 3.2 Gemini Feature Synthesis
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Infer high-level features from discovered code components. This project has no formal specification.
|
||||
TASK:
|
||||
Given these discovered components:
|
||||
{component list from Phase 2: names, types, files, responsibilities, dependencies}
|
||||
|
||||
• Group them into logical features (3-10 features for a typical project)
|
||||
• For each feature:
|
||||
- name: human-readable (Chinese OK)
|
||||
- component_ids: which components belong
|
||||
- description: what the feature does (inferred from code)
|
||||
- inferred_requirements: what this feature needs to accomplish (1-3 per feature)
|
||||
- status: 'implemented' (code complete) or 'partial' (incomplete patterns)
|
||||
- tags: search keywords
|
||||
• Identify cross-cutting concerns (logging, auth middleware, error handling) as separate features
|
||||
MODE: analysis
|
||||
CONTEXT: {component list JSON}
|
||||
EXPECTED: JSON: { features: [{ name, description, component_ids, inferred_requirements: [{ id, title }], status, tags }] }
|
||||
CONSTRAINTS: Every component must belong to at least 1 feature | Prefer fewer broad features over many narrow ones" --tool gemini --mode analysis
|
||||
```
|
||||
|
||||
### 3.3 Interactive Feature Review (unless -y)
|
||||
|
||||
Present inferred features to user:
|
||||
- Allow renaming, merging, splitting
|
||||
- Allow reassigning components between features
|
||||
- Confirm final feature list
|
||||
|
||||
## Phase 4: Implicit Requirement & Architecture Extraction
|
||||
|
||||
### 4.1 Inferred Requirements
|
||||
|
||||
For each feature, generate lightweight requirement entries from its components:
|
||||
|
||||
```
|
||||
Feature: feat-auth (User Authentication)
|
||||
→ IREQ-001: "Users can log in with email and password" (from LoginController)
|
||||
→ IREQ-002: "JWT tokens for session management" (from AuthMiddleware + jwt dep)
|
||||
→ IREQ-003: "Password reset via email" (from PasswordResetService)
|
||||
```
|
||||
|
||||
**ID Convention**: `IREQ-NNN` — distinguishes inferred from formal `REQ-NNN`.
|
||||
|
||||
### 4.2 Inferred Architecture Decisions
|
||||
|
||||
Detect patterns from code + dependencies:
|
||||
|
||||
```
|
||||
Express.js + JWT middleware → IADR-001: "REST API with JWT authentication"
|
||||
Prisma ORM + PostgreSQL → IADR-002: "PostgreSQL via Prisma ORM"
|
||||
React + Redux → IADR-003: "React frontend with Redux state"
|
||||
```
|
||||
|
||||
**ID Convention**: `IADR-NNN` — distinguishes inferred from formal `ADR-NNN`.
|
||||
|
||||
### 4.3 Glossary Generation
|
||||
|
||||
Extract domain terms from:
|
||||
- Class/function names (CamelCase → terms)
|
||||
- Key business terms in comments and strings
|
||||
- Framework-specific terminology
|
||||
|
||||
Write to `.workflow/.doc-index/glossary.json`.
|
||||
|
||||
## Phase 5: Git History Seeds
|
||||
|
||||
```bash
|
||||
git log --oneline --since="3 months ago" --no-merges --format="%H|%s|%ai" | head -30
|
||||
```
|
||||
|
||||
For each significant commit:
|
||||
- Match changed files to discovered components
|
||||
- Create action entry with `type: "historical"`
|
||||
|
||||
## Phase 6: Assemble doc-index.json
|
||||
|
||||
Write the index with code-first markers:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"project": "{project-name}",
|
||||
"build_path": "code-first",
|
||||
"spec_session": null,
|
||||
"last_updated": "ISO8601",
|
||||
"glossary": [...],
|
||||
"features": [{
|
||||
"id": "feat-{slug}",
|
||||
"name": "Feature Name",
|
||||
"epicId": null,
|
||||
"status": "implemented|partial",
|
||||
"docPath": "feature-maps/{slug}.md",
|
||||
"requirementIds": ["IREQ-NNN"],
|
||||
"tags": ["tag"]
|
||||
}],
|
||||
"requirements": [{
|
||||
"id": "IREQ-NNN",
|
||||
"title": "Inferred requirement",
|
||||
"source": "inferred",
|
||||
"priority": "inferred",
|
||||
"sourcePath": null,
|
||||
"techComponentIds": ["tech-{slug}"],
|
||||
"featureId": "feat-{slug}"
|
||||
}],
|
||||
"technicalComponents": [{
|
||||
"id": "tech-{slug}",
|
||||
"name": "ComponentName",
|
||||
"type": "service|controller|model|...",
|
||||
"responsibility": "One-line description",
|
||||
"adrId": "IADR-NNN|null",
|
||||
"docPath": "tech-registry/{slug}.md",
|
||||
"codeLocations": [{ "path": "src/...", "symbols": [...] }],
|
||||
"dependsOn": ["tech-{other}"],
|
||||
"featureIds": ["feat-{slug}"],
|
||||
"actionIds": []
|
||||
}],
|
||||
"architectureDecisions": [{
|
||||
"id": "IADR-NNN",
|
||||
"title": "Inferred decision",
|
||||
"source": "inferred",
|
||||
"sourcePath": null,
|
||||
"componentIds": ["tech-{slug}"]
|
||||
}],
|
||||
"actions": [{
|
||||
"id": "act-{short-hash}",
|
||||
"description": "Commit message",
|
||||
"type": "historical",
|
||||
"status": "historical",
|
||||
"affectedComponents": ["tech-{slug}"],
|
||||
"relatedCommit": "full-hash",
|
||||
"timestamp": "ISO8601"
|
||||
}],
|
||||
"freshness": {
|
||||
"thresholds": { "warning": 0.3, "stale": 0.7 },
|
||||
"weights": { "time": 0.1, "churn": 0.4, "symbol": 0.5 },
|
||||
"time_decay_k": 0.05,
|
||||
"auto_regenerate": false
|
||||
},
|
||||
"deepwiki_feature_to_symbol_index": {}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Phase 7: Build DeepWiki Feature-to-Symbol Index
|
||||
|
||||
If DeepWiki is available (`.codexlens/deepwiki_index.db` exists):
|
||||
|
||||
1. Collect all `codeLocations[].path` from `technicalComponents[]`
|
||||
2. Query DeepWiki: `POST /api/deepwiki/symbols-for-paths { paths: [...] }`
|
||||
3. Build `deepwiki_feature_to_symbol_index` by traversing:
|
||||
`feature → requirementIds → techComponentIds → codeLocations → symbols`
|
||||
|
||||
```json
|
||||
"deepwiki_feature_to_symbol_index": {
|
||||
"feat-auth": [
|
||||
"deepwiki:symbol:src/auth/jwt.ts#L30-L55",
|
||||
"deepwiki:symbol:src/models/user.ts#L12-L40"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Symbol URN format**: `deepwiki:symbol:<file_path>#L<start>-L<end>`
|
||||
|
||||
**Graceful degradation**: If DeepWiki is unavailable, set `deepwiki_feature_to_symbol_index: {}` and log warning.
|
||||
|
||||
## Phase 8: Generate Documents
|
||||
|
||||
Delegate all document generation to `/ddd:doc-generate`:
|
||||
|
||||
```
|
||||
Invoke /ddd:doc-generate [-y]
|
||||
```
|
||||
|
||||
This generates the complete document tree (Layer 3 → 2 → 1):
|
||||
- `tech-registry/{slug}.md` — component docs (Layer 3)
|
||||
- `feature-maps/{slug}.md` — feature docs (Layer 2)
|
||||
- `_index.md`, `README.md`, `ARCHITECTURE.md`, `SCHEMA.md` — index/overview docs (Layer 1)
|
||||
|
||||
See `/ddd:doc-generate` for full details on generation strategy and flags.
|
||||
|
||||
## Phase 9: Validation & Report
|
||||
|
||||
```
|
||||
Scan Report
|
||||
|
||||
Project: {name} ({language}/{framework})
|
||||
Architecture: {pattern}
|
||||
Source dirs: {N}
|
||||
|
||||
Discovered:
|
||||
Components: {N} ({by type breakdown})
|
||||
Features: {N} (inferred)
|
||||
Requirements: {N} (IREQ, inferred)
|
||||
Architecture Decisions: {N} (IADR, inferred)
|
||||
Historical Actions: {N} (from git)
|
||||
|
||||
Coverage:
|
||||
Components → Features: {%}
|
||||
Dependencies mapped: {%}
|
||||
|
||||
Recommendations:
|
||||
- Run /spec-generator to formalize {N} inferred requirements
|
||||
- {N} components have unclear responsibility — review tech-registry docs
|
||||
- Use /ddd:plan to start planning tasks with this index
|
||||
```
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-y, --yes` | Auto-confirm all decisions |
|
||||
| `--from-scratch` | Delete existing index and rebuild |
|
||||
| `--scope <dir>` | Limit scan to specific directory (e.g., `--scope src/auth`) |
|
||||
|
||||
## Upgrade Path: scan → spec
|
||||
|
||||
When a scanned project later runs `spec-generator` + `/ddd:index-build`:
|
||||
- `/ddd:index-build` detects existing code-first index
|
||||
- Merges: `IREQ-NNN` → `REQ-NNN`, `IADR-NNN` → `ADR-NNN` where content overlaps
|
||||
- Updates `build_path` to `"spec-first"`
|
||||
- Preserves all `tech-*` and `feat-*` entries (updates links only)
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Input from**: Codebase, git history, `project-tech.json`
|
||||
- **Delegates to**: `/ddd:doc-generate` (Phase 8, full document generation)
|
||||
- **Output to**: `ddd:plan`, `ddd:sync`, `ddd:update`, `ddd:index-build` (upgrade)
|
||||
- **Standalone**: Can be used independently on any project
|
||||
@@ -1,353 +0,0 @@
|
||||
---
|
||||
name: sync
|
||||
description: Post-task synchronization - update document index, generate action log, and refresh feature/component docs after completing a development task.
|
||||
argument-hint: "[-y|--yes] [--dry-run] [--from-manifest <path>] [--task-id <id>] [--commit <hash>] \"task summary\""
|
||||
allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Auto-detect changes, auto-update all docs, skip review prompts.
|
||||
|
||||
# DDD Sync Command (/ddd:sync)
|
||||
|
||||
## Purpose
|
||||
|
||||
After completing a development task, synchronize the document index with actual code changes:
|
||||
1. **Analyze** what changed (git diff)
|
||||
2. **Trace** which features/requirements/components are affected
|
||||
3. **Update** index entries (status, code locations, links)
|
||||
4. **Generate** action log entry
|
||||
5. **Refresh** feature-map and tech-registry documents
|
||||
|
||||
## When to Use: sync vs update
|
||||
|
||||
| Scenario | Use |
|
||||
|----------|-----|
|
||||
| Task completed, ready to commit | **ddd:sync** — full post-task reconciliation |
|
||||
| Mid-development, quick impact check | ddd:update |
|
||||
| Pre-commit validation | ddd:update --check-only |
|
||||
| Auto-triggered after ddd:execute | **ddd:sync** (automatic) |
|
||||
| Periodic index refresh during refactoring | ddd:update |
|
||||
|
||||
**Rule of thumb**: `sync` = task boundary (done something), `update` = development pulse (doing something).
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- `doc-index.json` must exist
|
||||
- Git repository with committed or staged changes
|
||||
|
||||
## Phase 0: Consistency Validation
|
||||
|
||||
Before processing changes, verify that `doc-index.json` entries are consistent with actual code state.
|
||||
|
||||
### 0.1 Validate Code Locations
|
||||
|
||||
For each `technicalComponents[].codeLocations[]`:
|
||||
- Verify file exists on disk
|
||||
- If file was deleted/moved → flag for removal or update
|
||||
- If file exists → verify listed `symbols[]` still exist (quick grep/AST check)
|
||||
|
||||
### 0.2 Validate Symbols
|
||||
|
||||
For components with `codeLocations[].symbols[]`:
|
||||
- Check each symbol still exists in the referenced file
|
||||
- Detect new exported symbols not yet tracked
|
||||
- Report: `{N} stale symbols, {N} untracked symbols`
|
||||
|
||||
### 0.3 Validation Report
|
||||
|
||||
```
|
||||
Consistency Check:
|
||||
Components validated: {N}
|
||||
Files verified: {N}
|
||||
Stale references: {N} (files missing or symbols removed)
|
||||
Untracked symbols: {N} (new exports not in index)
|
||||
```
|
||||
|
||||
If stale references found: warn and auto-fix during Phase 3 updates.
|
||||
If `--dry-run`: report only, no fixes.
|
||||
|
||||
## Phase 1: Change Detection
|
||||
|
||||
### 1.0.1 Schema Version Check
|
||||
|
||||
Before processing changes, verify doc-index.json schema compatibility:
|
||||
|
||||
```javascript
|
||||
const docIndex = JSON.parse(Read('.workflow/.doc-index/doc-index.json'));
|
||||
const schemaVersion = docIndex.schema_version || '0.0'; // Default for legacy
|
||||
|
||||
if (schemaVersion !== '1.0') {
|
||||
console.warn(`Schema version mismatch: found ${schemaVersion}, expected 1.0`);
|
||||
console.warn('Consider running schema migration or regenerating doc-index with /ddd:scan');
|
||||
// Continue with degraded functionality - may encounter missing fields
|
||||
}
|
||||
```
|
||||
|
||||
**Graceful degradation**: If version mismatch detected → log warning → continue with caution (some features may not work as expected).
|
||||
|
||||
### 1.0 Data Source Selection
|
||||
|
||||
```
|
||||
IF --from-manifest <path>:
|
||||
Load execution-manifest.json
|
||||
→ files_modified[] provides precise file list + action type + task attribution
|
||||
→ TASK-*.result.json provides symbol-level changes + convergence results
|
||||
→ Skip Phase 1.1/1.2 (already classified by execute)
|
||||
→ Proceed directly to Phase 2 with manifest data
|
||||
ELSE:
|
||||
→ Fall through to Phase 1.1 (git-based discovery)
|
||||
```
|
||||
|
||||
**`--from-manifest` advantages** (used automatically by ddd:execute):
|
||||
- Precise file → task attribution (which task modified which file)
|
||||
- Symbol-level change tracking (not just file-level)
|
||||
- Convergence verification results carried forward to action-log
|
||||
- Survives process interruptions (manifest is persisted to disk)
|
||||
|
||||
### 1.1 Identify Changes (git-based fallback)
|
||||
|
||||
```bash
|
||||
# If --commit provided:
|
||||
git diff --name-only {commit}^..{commit}
|
||||
git diff --stat {commit}^..{commit}
|
||||
|
||||
# If --task-id provided, find related commits:
|
||||
git log --oneline --grep="task-{id}" | head -10
|
||||
|
||||
# Otherwise: changes since last ddd:sync
|
||||
git diff --name-only HEAD~1..HEAD
|
||||
```
|
||||
|
||||
### 1.2 Classify Changes (git-based fallback)
|
||||
|
||||
For each changed file, determine:
|
||||
- **Type**: added | modified | deleted | renamed
|
||||
- **Category**: source | test | config | docs | other
|
||||
- **Symbols affected**: parse diff for changed functions/classes (use Gemini if complex)
|
||||
|
||||
## Phase 2: Impact Tracing (Layer-Based, TASK-004)
|
||||
|
||||
**Strategy**: Trace impact through layers (files → components → features → indexes) following memory-manage pattern.
|
||||
|
||||
### 2.1 Match to Index
|
||||
|
||||
For each changed file path:
|
||||
|
||||
```
|
||||
Search doc-index.json.technicalComponents[].codeLocations[].path
|
||||
→ Find matching component IDs (Layer 3)
|
||||
→ From components, find linked featureIds (Layer 2)
|
||||
→ From features, find linked requirementIds (Layer 2)
|
||||
```
|
||||
|
||||
### 2.2 Discover New Components
|
||||
|
||||
If changed files don't match any existing component:
|
||||
- Flag as potential new component
|
||||
- Ask user if it should be registered (or auto-register with `-y`)
|
||||
|
||||
### 2.3 Build Impact Report
|
||||
|
||||
```markdown
|
||||
## Impact Summary
|
||||
|
||||
### Changed Files (5)
|
||||
- src/services/auth.ts (modified) → tech-auth-service → feat-auth
|
||||
- src/models/user.ts (modified) → tech-user-model → feat-auth
|
||||
- src/routes/login.ts (added) → NEW COMPONENT → feat-auth
|
||||
- src/tests/auth.test.ts (modified) → [test file, skip]
|
||||
- package.json (modified) → [config, skip]
|
||||
|
||||
### Affected Features
|
||||
- feat-auth: User Authentication (2 components modified, 1 new)
|
||||
|
||||
### Affected Requirements
|
||||
- REQ-001: Email login (implementation updated)
|
||||
- REQ-002: JWT token generation (implementation updated)
|
||||
```
|
||||
|
||||
## Phase 2.4: DeepWiki Freshness Check
|
||||
|
||||
If DeepWiki integration is configured (`doc-index.json.freshness` exists):
|
||||
|
||||
### 2.4.1 Identify Modified Files
|
||||
From `execution-manifest.json` or git diff, collect `files_modified[]` with `action == "modified"`.
|
||||
|
||||
### 2.4.2 Check Staleness
|
||||
Query DeepWiki: `POST /api/deepwiki/stale-files { files: [{path, hash}] }`
|
||||
|
||||
For each stale file's symbols, calculate staleness score:
|
||||
```
|
||||
S(symbol) = min(1.0, w_t × T + w_c × C + w_s × M)
|
||||
```
|
||||
Where weights come from `doc-index.json.freshness.weights`.
|
||||
|
||||
### 2.4.3 Score Propagation (max aggregation)
|
||||
```
|
||||
S_file = max(S_symbol_1, S_symbol_2, ...)
|
||||
S_component = max(S_file_1, S_file_2, ...)
|
||||
S_feature = max(S_component_1, S_component_2, ...)
|
||||
```
|
||||
|
||||
### 2.4.4 Status Assignment
|
||||
Using thresholds from `doc-index.json.freshness.thresholds`:
|
||||
- `fresh`: score in [0, warning_threshold)
|
||||
- `warning`: score in [warning_threshold, stale_threshold)
|
||||
- `stale`: score in [stale_threshold, 1.0]
|
||||
|
||||
### 2.4.5 Update Records
|
||||
- Update `deepwiki_symbols.staleness_score` and `deepwiki_files.staleness_score` in DeepWiki SQLite
|
||||
- Update `tech-registry/{slug}.md` YAML frontmatter with freshness block
|
||||
- Update `feature-maps/{slug}.md` YAML frontmatter with freshness block
|
||||
- Update `deepwiki_feature_to_symbol_index` in doc-index.json
|
||||
|
||||
### 2.4.6 Staleness Report
|
||||
Add to action-log:
|
||||
- Number of stale symbols/files/components
|
||||
- Top-5 most stale items with scores
|
||||
- Auto-regeneration candidates (if `auto_regenerate: true` and score >= stale threshold)
|
||||
|
||||
## Phase 3: Update Index
|
||||
|
||||
### 3.0 Dry-Run Gate
|
||||
|
||||
If `--dry-run` is set:
|
||||
- Execute Phase 3 analysis (determine what would change)
|
||||
- Display planned modifications as a preview report
|
||||
- Skip all file writes (Phase 3.1-3.5 and Phase 4)
|
||||
- Output: "Dry-run complete. Run without --dry-run to apply changes."
|
||||
|
||||
### 3.0.1 Backup Index
|
||||
|
||||
Before any modifications, create backup:
|
||||
- Copy `doc-index.json` → `doc-index.json.bak`
|
||||
- On failure: restore from `.bak` and report error
|
||||
- On success: remove `.bak`
|
||||
|
||||
### 3.1 Update Technical Components
|
||||
|
||||
For each affected component in `doc-index.json`:
|
||||
- Update `codeLocations` if file paths or line ranges changed
|
||||
- Update `symbols` if new exports were added
|
||||
- Add new `actionIds` entry
|
||||
- **Auto-update `responsibility`**: If symbols changed (new methods/exports added or removed), re-infer responsibility from current symbols list using Gemini analysis. This prevents stale descriptions (e.g., responsibility still says "登录、注册" after adding logout support)
|
||||
|
||||
### 3.2 Register New Components
|
||||
|
||||
For newly discovered components:
|
||||
- Generate `tech-{slug}` ID
|
||||
- Create entry in `technicalComponents[]`
|
||||
- Link to appropriate features
|
||||
- Generate new `tech-registry/{slug}.md` document
|
||||
|
||||
### 3.3 Update Feature Status
|
||||
|
||||
For each affected feature:
|
||||
- If all requirements now have mapped components → `status: "implemented"`
|
||||
- If some requirements still unmapped → `status: "in-progress"`
|
||||
|
||||
### 3.4 Add Action Entry
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "task-{id}",
|
||||
"description": "{task summary from user}",
|
||||
"type": "feature|bugfix|refactor",
|
||||
"status": "completed",
|
||||
"affectedFeatures": ["feat-auth"],
|
||||
"affectedComponents": ["tech-auth-service", "tech-user-model"],
|
||||
"changedFiles": [
|
||||
{ "path": "src/services/auth.ts", "action": "modified", "task_id": "TASK-001" },
|
||||
{ "path": "src/models/user.ts", "action": "modified", "task_id": "TASK-001" }
|
||||
],
|
||||
"symbolsChanged": ["AuthService.validate", "UserModel.toJSON"],
|
||||
"convergenceResults": {
|
||||
"passed": 2,
|
||||
"total": 2,
|
||||
"details": ["Rate limiter middleware exists", "Config accepts per-route limits"]
|
||||
},
|
||||
"verifyGate": "PASS|WARN|FAIL|skipped",
|
||||
"relatedCommit": "{commit hash}",
|
||||
"manifestPath": "{execution-manifest.json path | null}",
|
||||
"timestamp": "ISO8601"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 Update Timestamp
|
||||
|
||||
Set `doc-index.json.last_updated` to current time.
|
||||
|
||||
## Phase 4: Refresh Documents & Action Log
|
||||
|
||||
### 4.1 Delegate Document Refresh to /ddd:doc-refresh
|
||||
|
||||
From Phase 2 impact tracing, collect affected component and feature IDs, then delegate:
|
||||
|
||||
```
|
||||
Invoke /ddd:doc-refresh [-y] --components {affected_component_ids} --features {affected_feature_ids}
|
||||
```
|
||||
|
||||
This handles Layer 3 → 2 → 1 selective document refresh. See `/ddd:doc-refresh` for full details.
|
||||
|
||||
### 4.2 Generate Action Log Entry
|
||||
|
||||
Create `.workflow/.doc-index/action-logs/{task-id}.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
id: task-{id}
|
||||
type: feature|bugfix|refactor
|
||||
status: completed
|
||||
features: [feat-auth]
|
||||
components: [tech-auth-service, tech-user-model]
|
||||
commit: {hash}
|
||||
timestamp: ISO8601
|
||||
---
|
||||
|
||||
# Task: {summary}
|
||||
|
||||
## Changes
|
||||
| File | Type | Component |
|
||||
|------|------|-----------|
|
||||
| src/services/auth.ts | modified | tech-auth-service |
|
||||
|
||||
## Impact
|
||||
- Features affected: feat-auth
|
||||
- Requirements addressed: REQ-001, REQ-002
|
||||
|
||||
## Staleness (if DeepWiki freshness enabled)
|
||||
| Item | Type | Score | Status |
|
||||
|------|------|-------|--------|
|
||||
| {symbol/file/component} | {type} | {score} | {fresh/warning/stale} |
|
||||
|
||||
## Notes
|
||||
{any user-provided notes}
|
||||
```
|
||||
|
||||
## Phase 5: Confirmation (unless -y)
|
||||
|
||||
Present update summary to user:
|
||||
- Files updated in doc-index
|
||||
- New documents created
|
||||
- Status changes
|
||||
- Ask for confirmation before writing
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-y, --yes` | Auto-confirm all updates |
|
||||
| `--dry-run` | Preview all changes without modifying any files |
|
||||
| `--from-manifest <path>` | Use execution-manifest.json as data source (auto-set by ddd:execute) |
|
||||
| `--task-id <id>` | Associate with specific task ID |
|
||||
| `--commit <hash>` | Analyze specific commit |
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Input from**: `execution-manifest.json` (preferred, from ddd:execute) OR Git history (fallback), `doc-index.json`, `/ddd:plan` output
|
||||
- **Delegates to**: `/ddd:doc-refresh` (Phase 4.1, selective document refresh)
|
||||
- **Output to**: Updated `doc-index.json`, feature-maps/, tech-registry/, action-logs/
|
||||
- **Triggers**: After completing any development task
|
||||
- **Data source priority**: `--from-manifest` > `--commit` > `--task-id` > git diff HEAD~1
|
||||
@@ -1,160 +0,0 @@
|
||||
---
|
||||
name: update
|
||||
description: Incremental index update - detect code changes and trace impact to related features/requirements. Lightweight alternative to full sync.
|
||||
argument-hint: "[-y|--yes] [--files <file1,file2,...>] [--staged] [--check-only]"
|
||||
allowed-tools: TodoWrite(*), AskUserQuestion(*), Read(*), Grep(*), Glob(*), Bash(*), Edit(*), Write(*), mcp__ace-tool__search_context(*)
|
||||
---
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Auto-update index without confirmation prompts.
|
||||
|
||||
# DDD Update Command (/ddd:update)
|
||||
|
||||
## Purpose
|
||||
|
||||
Lightweight incremental update: given a set of changed files, trace their impact through the document index and update affected entries. Unlike `/ddd:sync` (full post-task sync), this command focuses on keeping the index fresh during development.
|
||||
|
||||
## When to Use: update vs sync
|
||||
|
||||
| Scenario | Use |
|
||||
|----------|-----|
|
||||
| Quick impact check during development | **ddd:update** |
|
||||
| Preview what sync would change | **ddd:update --check-only** |
|
||||
| Task completed, full reconciliation | ddd:sync |
|
||||
| Register new components + update all docs | ddd:sync |
|
||||
|
||||
**Rule of thumb**: `update` = lightweight pulse (during work), `sync` = full checkpoint (after work).
|
||||
|
||||
## Use Cases
|
||||
|
||||
1. **During development**: Quick check which docs are affected by current changes
|
||||
2. **Pre-commit check**: Ensure index is up-to-date before committing
|
||||
3. **Periodic refresh**: Update stale code locations after refactoring
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- `doc-index.json` must exist at `.workflow/.doc-index/doc-index.json`
|
||||
|
||||
## Phase 1: Identify Changed Files
|
||||
|
||||
### Source Priority
|
||||
|
||||
```
|
||||
1. --files <list> → Explicit file list
|
||||
2. --staged → git diff --cached --name-only
|
||||
3. (default) → git diff --name-only (unstaged changes)
|
||||
```
|
||||
|
||||
### Output
|
||||
|
||||
List of changed file paths with change type (added/modified/deleted/renamed).
|
||||
|
||||
## Phase 2: Trace Impact
|
||||
|
||||
### 2.1 Forward Lookup (Code → Components → Features)
|
||||
|
||||
For each changed file:
|
||||
|
||||
```
|
||||
doc-index.json.technicalComponents[]
|
||||
.codeLocations[].path MATCH changed_file
|
||||
→ component_ids[]
|
||||
|
||||
doc-index.json.technicalComponents[component_ids]
|
||||
.featureIds[]
|
||||
→ feature_ids[]
|
||||
|
||||
doc-index.json.features[feature_ids]
|
||||
.requirementIds[]
|
||||
→ requirement_ids[]
|
||||
```
|
||||
|
||||
### 2.2 Orphan Detection
|
||||
|
||||
Files not matching any component → flag as:
|
||||
- **Potential new component**: if in src/ directory
|
||||
- **Ignorable**: if in test/, docs/, config/ directories
|
||||
|
||||
### 2.3 Impact Report
|
||||
|
||||
```
|
||||
Impact Analysis for 3 changed files:
|
||||
|
||||
src/services/auth.ts (modified)
|
||||
→ Component: tech-auth-service (AuthService)
|
||||
→ Feature: feat-auth (User Authentication)
|
||||
→ Requirements: REQ-001, REQ-002
|
||||
|
||||
src/middleware/rate-limit.ts (added)
|
||||
→ No matching component (new file)
|
||||
→ Suggested: Register as new component
|
||||
|
||||
src/utils/hash.ts (modified)
|
||||
→ Component: tech-hash-util
|
||||
→ Features: feat-auth, feat-password-reset
|
||||
→ Requirements: REQ-001, REQ-005
|
||||
```
|
||||
|
||||
## Phase 3: Update Index (unless --check-only)
|
||||
|
||||
### 3.1 Update Code Locations
|
||||
|
||||
For matched components:
|
||||
- If file was renamed → update `codeLocations[].path`
|
||||
- If file was deleted → remove code location entry
|
||||
- If symbols changed → update `symbols` list (requires AST or Gemini analysis)
|
||||
|
||||
### 3.2 Register New Components (interactive unless -y)
|
||||
|
||||
For orphan files in src/:
|
||||
- Prompt user for component name and type
|
||||
- Or auto-generate with `-y`: derive name from file path
|
||||
- Create `technicalComponents[]` entry
|
||||
- Ask which feature it belongs to (or auto-link by directory structure)
|
||||
|
||||
### 3.3 Update Timestamps
|
||||
|
||||
- Update `technicalComponents[].docPath` last_updated in corresponding .md
|
||||
- Update `doc-index.json.last_updated`
|
||||
|
||||
## Phase 4: Refresh Documents (if updates were made)
|
||||
|
||||
### 4.1 Delegate to /ddd:doc-refresh
|
||||
|
||||
From Phase 2 impact tracing, collect affected component and feature IDs, then delegate:
|
||||
|
||||
```
|
||||
Invoke /ddd:doc-refresh [-y] --minimal --components {affected_component_ids} --features {affected_feature_ids}
|
||||
```
|
||||
|
||||
The `--minimal` flag ensures only metadata/frontmatter is updated (code locations, timestamps), skipping full content regeneration. This keeps the update lightweight.
|
||||
|
||||
See `/ddd:doc-refresh` for full details.
|
||||
|
||||
### 4.2 Skip If --check-only
|
||||
|
||||
With `--check-only`, skip Phase 3 and Phase 4 entirely — only output the impact report.
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `-y, --yes` | Auto-confirm updates |
|
||||
| `--files <list>` | Explicit comma-separated file list |
|
||||
| `--staged` | Analyze staged (git cached) files |
|
||||
| `--check-only` | Report impact without modifying index |
|
||||
|
||||
## Output
|
||||
|
||||
- **Console**: Impact report showing affected features/requirements
|
||||
- **Updated**: `doc-index.json` (if not --check-only)
|
||||
- **Updated**: Affected tech-registry/ and feature-maps/ docs
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Input from**: Git working tree, `doc-index.json`
|
||||
- **Delegates to**: `/ddd:doc-refresh` (Phase 4.1, incremental document refresh with --minimal)
|
||||
- **Output to**: Updated `doc-index.json`, impact report
|
||||
- **Triggers**: During development, pre-commit, or periodic refresh
|
||||
- **Can chain to**: `/ddd:sync` for full post-task synchronization
|
||||
@@ -1,287 +0,0 @@
|
||||
---
|
||||
name: add
|
||||
description: Add IDAW tasks - manual creation or import from ccw issue
|
||||
argument-hint: "[-y|--yes] [--from-issue <id>[,<id>,...]] \"description\" [--type <task_type>] [--priority <1-5>]"
|
||||
allowed-tools: AskUserQuestion(*), Read(*), Bash(*), Write(*), Glob(*)
|
||||
---
|
||||
|
||||
# IDAW Add Command (/idaw:add)
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Skip clarification questions, create task with inferred details.
|
||||
|
||||
## IDAW Task Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "IDAW-001",
|
||||
"title": "string",
|
||||
"description": "string",
|
||||
"status": "pending",
|
||||
"priority": 2,
|
||||
"task_type": null,
|
||||
"skill_chain": null,
|
||||
"context": {
|
||||
"affected_files": [],
|
||||
"acceptance_criteria": [],
|
||||
"constraints": [],
|
||||
"references": []
|
||||
},
|
||||
"source": {
|
||||
"type": "manual|import-issue",
|
||||
"issue_id": null,
|
||||
"issue_snapshot": null
|
||||
},
|
||||
"execution": {
|
||||
"session_id": null,
|
||||
"started_at": null,
|
||||
"completed_at": null,
|
||||
"skill_results": [],
|
||||
"git_commit": null,
|
||||
"error": null
|
||||
},
|
||||
"created_at": "ISO",
|
||||
"updated_at": "ISO"
|
||||
}
|
||||
```
|
||||
|
||||
**Valid task_type values**: `bugfix|bugfix-hotfix|feature|feature-complex|refactor|tdd|test|test-fix|review|docs`
|
||||
|
||||
## Implementation
|
||||
|
||||
### Phase 1: Parse Arguments
|
||||
|
||||
```javascript
|
||||
const args = $ARGUMENTS;
|
||||
const autoYes = /(-y|--yes)\b/.test(args);
|
||||
const fromIssue = args.match(/--from-issue\s+([\w,-]+)/)?.[1];
|
||||
const typeFlag = args.match(/--type\s+([\w-]+)/)?.[1];
|
||||
const priorityFlag = args.match(/--priority\s+(\d)/)?.[1];
|
||||
|
||||
// Extract description: content inside quotes (preferred), or fallback to stripping flags
|
||||
const quotedMatch = args.match(/(?:^|\s)["']([^"']+)["']/);
|
||||
const description = quotedMatch
|
||||
? quotedMatch[1].trim()
|
||||
: args.replace(/(-y|--yes|--from-issue\s+[\w,-]+|--type\s+[\w-]+|--priority\s+\d)/g, '').trim();
|
||||
```
|
||||
|
||||
### Phase 2: Route — Import or Manual
|
||||
|
||||
```
|
||||
--from-issue present?
|
||||
├─ YES → Import Mode (Phase 3A)
|
||||
└─ NO → Manual Mode (Phase 3B)
|
||||
```
|
||||
|
||||
### Phase 3A: Import Mode (from ccw issue)
|
||||
|
||||
```javascript
|
||||
const issueIds = fromIssue.split(',');
|
||||
|
||||
// Fetch all issues once (outside loop)
|
||||
let issues = [];
|
||||
try {
|
||||
const issueJson = Bash(`ccw issue list --json`);
|
||||
issues = JSON.parse(issueJson).issues || [];
|
||||
} catch (e) {
|
||||
console.log(`Error fetching CCW issues: ${e.message || e}`);
|
||||
console.log('Ensure ccw is installed and issues exist. Use /issue:new to create issues first.');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const issueId of issueIds) {
|
||||
// 1. Find issue data
|
||||
const issue = issues.find(i => i.id === issueId.trim());
|
||||
if (!issue) {
|
||||
console.log(`Warning: Issue ${issueId} not found, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. Check duplicate (same issue_id already imported)
|
||||
const existing = Glob('.workflow/.idaw/tasks/IDAW-*.json');
|
||||
for (const f of existing) {
|
||||
const data = JSON.parse(Read(f));
|
||||
if (data.source?.issue_id === issueId.trim()) {
|
||||
console.log(`Warning: Issue ${issueId} already imported as ${data.id}, skipping`);
|
||||
continue; // skip to next issue
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Generate next IDAW ID
|
||||
const nextId = generateNextId();
|
||||
|
||||
// 4. Map issue → IDAW task
|
||||
const task = {
|
||||
id: nextId,
|
||||
title: issue.title,
|
||||
description: issue.context || issue.title,
|
||||
status: 'pending',
|
||||
priority: parseInt(priorityFlag) || issue.priority || 3,
|
||||
task_type: typeFlag || inferTaskType(issue.title, issue.context || ''),
|
||||
skill_chain: null,
|
||||
context: {
|
||||
affected_files: issue.affected_components || [],
|
||||
acceptance_criteria: [],
|
||||
constraints: [],
|
||||
references: issue.source_url ? [issue.source_url] : []
|
||||
},
|
||||
source: {
|
||||
type: 'import-issue',
|
||||
issue_id: issue.id,
|
||||
issue_snapshot: {
|
||||
id: issue.id,
|
||||
title: issue.title,
|
||||
status: issue.status,
|
||||
context: issue.context,
|
||||
priority: issue.priority,
|
||||
created_at: issue.created_at
|
||||
}
|
||||
},
|
||||
execution: {
|
||||
session_id: null,
|
||||
started_at: null,
|
||||
completed_at: null,
|
||||
skill_results: [],
|
||||
git_commit: null,
|
||||
error: null
|
||||
},
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
};
|
||||
|
||||
// 5. Write task file
|
||||
Bash('mkdir -p .workflow/.idaw/tasks');
|
||||
Write(`.workflow/.idaw/tasks/${nextId}.json`, JSON.stringify(task, null, 2));
|
||||
console.log(`Created ${nextId} from issue ${issueId}: ${issue.title}`);
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3B: Manual Mode
|
||||
|
||||
```javascript
|
||||
// 1. Validate description
|
||||
if (!description && !autoYes) {
|
||||
const answer = AskUserQuestion({
|
||||
questions: [{
|
||||
question: 'Please provide a task description:',
|
||||
header: 'Task',
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: 'Provide description', description: 'What needs to be done?' }
|
||||
]
|
||||
}]
|
||||
});
|
||||
// Use custom text from "Other"
|
||||
description = answer.customText || '';
|
||||
}
|
||||
|
||||
if (!description) {
|
||||
console.log('Error: No description provided. Usage: /idaw:add "task description"');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Generate next IDAW ID
|
||||
const nextId = generateNextId();
|
||||
|
||||
// 3. Build title from first sentence
|
||||
const title = description.split(/[.\n]/)[0].substring(0, 80).trim();
|
||||
|
||||
// 4. Determine task_type
|
||||
const taskType = typeFlag || null; // null → inferred at run time
|
||||
|
||||
// 5. Create task
|
||||
const task = {
|
||||
id: nextId,
|
||||
title: title,
|
||||
description: description,
|
||||
status: 'pending',
|
||||
priority: parseInt(priorityFlag) || 3,
|
||||
task_type: taskType,
|
||||
skill_chain: null,
|
||||
context: {
|
||||
affected_files: [],
|
||||
acceptance_criteria: [],
|
||||
constraints: [],
|
||||
references: []
|
||||
},
|
||||
source: {
|
||||
type: 'manual',
|
||||
issue_id: null,
|
||||
issue_snapshot: null
|
||||
},
|
||||
execution: {
|
||||
session_id: null,
|
||||
started_at: null,
|
||||
completed_at: null,
|
||||
skill_results: [],
|
||||
git_commit: null,
|
||||
error: null
|
||||
},
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString()
|
||||
};
|
||||
|
||||
Bash('mkdir -p .workflow/.idaw/tasks');
|
||||
Write(`.workflow/.idaw/tasks/${nextId}.json`, JSON.stringify(task, null, 2));
|
||||
console.log(`Created ${nextId}: ${title}`);
|
||||
```
|
||||
|
||||
## Helper Functions
|
||||
|
||||
### ID Generation
|
||||
|
||||
```javascript
|
||||
function generateNextId() {
|
||||
const files = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
|
||||
if (files.length === 0) return 'IDAW-001';
|
||||
|
||||
const maxNum = files
|
||||
.map(f => parseInt(f.match(/IDAW-(\d+)/)?.[1] || '0'))
|
||||
.reduce((max, n) => Math.max(max, n), 0);
|
||||
|
||||
return `IDAW-${String(maxNum + 1).padStart(3, '0')}`;
|
||||
}
|
||||
```
|
||||
|
||||
### Task Type Inference (deferred — used at run time if task_type is null)
|
||||
|
||||
```javascript
|
||||
function inferTaskType(title, description) {
|
||||
const text = `${title} ${description}`.toLowerCase();
|
||||
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
|
||||
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
|
||||
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
|
||||
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
|
||||
if (/generate test|写测试|add test/.test(text)) return 'test';
|
||||
if (/review|code review/.test(text)) return 'review';
|
||||
if (/docs|documentation|readme/.test(text)) return 'docs';
|
||||
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
|
||||
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
|
||||
return 'feature';
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# Manual creation
|
||||
/idaw:add "Fix login timeout bug" --type bugfix --priority 2
|
||||
/idaw:add "Add rate limiting to API endpoints" --priority 1
|
||||
/idaw:add "Refactor auth module to use strategy pattern"
|
||||
|
||||
# Import from ccw issue
|
||||
/idaw:add --from-issue ISS-20260128-001
|
||||
/idaw:add --from-issue ISS-20260128-001,ISS-20260128-002 --priority 1
|
||||
|
||||
# Auto mode (skip clarification)
|
||||
/idaw:add -y "Quick fix for typo in header"
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
```
|
||||
Created IDAW-001: Fix login timeout bug
|
||||
Type: bugfix | Priority: 2 | Source: manual
|
||||
→ Next: /idaw:run or /idaw:status
|
||||
```
|
||||
@@ -1,442 +0,0 @@
|
||||
---
|
||||
name: resume
|
||||
description: Resume interrupted IDAW session from last checkpoint
|
||||
argument-hint: "[-y|--yes] [session-id]"
|
||||
allowed-tools: Skill(*), TodoWrite(*), AskUserQuestion(*), Read(*), Write(*), Bash(*), Glob(*)
|
||||
---
|
||||
|
||||
# IDAW Resume Command (/idaw:resume)
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Auto-skip interrupted task, continue with remaining.
|
||||
|
||||
## Skill Chain Mapping
|
||||
|
||||
```javascript
|
||||
const SKILL_CHAIN_MAP = {
|
||||
'bugfix': ['workflow-lite-plan', 'workflow-test-fix'],
|
||||
'bugfix-hotfix': ['workflow-lite-plan'],
|
||||
'feature': ['workflow-lite-plan', 'workflow-test-fix'],
|
||||
'feature-complex': ['workflow-plan', 'workflow-execute', 'workflow-test-fix'],
|
||||
'refactor': ['workflow:refactor-cycle'],
|
||||
'tdd': ['workflow-tdd-plan', 'workflow-execute'],
|
||||
'test': ['workflow-test-fix'],
|
||||
'test-fix': ['workflow-test-fix'],
|
||||
'review': ['review-cycle'],
|
||||
'docs': ['workflow-lite-plan']
|
||||
};
|
||||
```
|
||||
|
||||
## Task Type Inference
|
||||
|
||||
```javascript
|
||||
function inferTaskType(title, description) {
|
||||
const text = `${title} ${description}`.toLowerCase();
|
||||
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
|
||||
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
|
||||
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
|
||||
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
|
||||
if (/generate test|写测试|add test/.test(text)) return 'test';
|
||||
if (/review|code review/.test(text)) return 'review';
|
||||
if (/docs|documentation|readme/.test(text)) return 'docs';
|
||||
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
|
||||
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
|
||||
return 'feature';
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Phase 1: Find Resumable Session
|
||||
|
||||
```javascript
|
||||
const args = $ARGUMENTS;
|
||||
const autoYes = /(-y|--yes)/.test(args);
|
||||
const targetSessionId = args.replace(/(-y|--yes)/g, '').trim();
|
||||
|
||||
let session = null;
|
||||
let sessionDir = null;
|
||||
|
||||
if (targetSessionId) {
|
||||
// Load specific session
|
||||
sessionDir = `.workflow/.idaw/sessions/${targetSessionId}`;
|
||||
try {
|
||||
session = JSON.parse(Read(`${sessionDir}/session.json`));
|
||||
} catch {
|
||||
console.log(`Session "${targetSessionId}" not found.`);
|
||||
console.log('Use /idaw:status to list sessions, or /idaw:run to start a new one.');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Find most recent running session
|
||||
const sessionFiles = Glob('.workflow/.idaw/sessions/IDA-*/session.json') || [];
|
||||
|
||||
for (const f of sessionFiles) {
|
||||
try {
|
||||
const s = JSON.parse(Read(f));
|
||||
if (s.status === 'running') {
|
||||
session = s;
|
||||
sessionDir = f.replace(/\/session\.json$/, '').replace(/\\session\.json$/, '');
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
// Skip malformed
|
||||
}
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
console.log('No running sessions found to resume.');
|
||||
console.log('Use /idaw:run to start a new execution.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Resuming session: ${session.session_id}`);
|
||||
```
|
||||
|
||||
### Phase 2: Handle Interrupted Task
|
||||
|
||||
```javascript
|
||||
// Find the task that was in_progress when interrupted
|
||||
let currentTaskId = session.current_task;
|
||||
let currentTask = null;
|
||||
|
||||
if (currentTaskId) {
|
||||
try {
|
||||
currentTask = JSON.parse(Read(`.workflow/.idaw/tasks/${currentTaskId}.json`));
|
||||
} catch {
|
||||
console.log(`Warning: Could not read task ${currentTaskId}`);
|
||||
currentTaskId = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTask && currentTask.status === 'in_progress') {
|
||||
if (autoYes) {
|
||||
// Auto: skip interrupted task
|
||||
currentTask.status = 'skipped';
|
||||
currentTask.execution.error = 'Skipped on resume (auto mode)';
|
||||
currentTask.execution.completed_at = new Date().toISOString();
|
||||
currentTask.updated_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
|
||||
session.skipped.push(currentTaskId);
|
||||
console.log(`Skipped interrupted task: ${currentTaskId}`);
|
||||
} else {
|
||||
const answer = AskUserQuestion({
|
||||
questions: [{
|
||||
question: `Task ${currentTaskId} was interrupted: "${currentTask.title}". How to proceed?`,
|
||||
header: 'Resume',
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: 'Retry', description: 'Reset to pending, re-execute from beginning' },
|
||||
{ label: 'Skip', description: 'Mark as skipped, move to next task' }
|
||||
]
|
||||
}]
|
||||
});
|
||||
|
||||
if (answer.answers?.Resume === 'Skip') {
|
||||
currentTask.status = 'skipped';
|
||||
currentTask.execution.error = 'Skipped on resume (user choice)';
|
||||
currentTask.execution.completed_at = new Date().toISOString();
|
||||
currentTask.updated_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
|
||||
session.skipped.push(currentTaskId);
|
||||
} else {
|
||||
// Retry: reset to pending
|
||||
currentTask.status = 'pending';
|
||||
currentTask.execution.started_at = null;
|
||||
currentTask.execution.completed_at = null;
|
||||
currentTask.execution.skill_results = [];
|
||||
currentTask.execution.error = null;
|
||||
currentTask.updated_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${currentTaskId}.json`, JSON.stringify(currentTask, null, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: Build Remaining Task Queue
|
||||
|
||||
```javascript
|
||||
// Collect remaining tasks (pending, or the retried current task)
|
||||
const allTaskIds = session.tasks;
|
||||
const completedSet = new Set([...session.completed, ...session.failed, ...session.skipped]);
|
||||
|
||||
const remainingTasks = [];
|
||||
for (const taskId of allTaskIds) {
|
||||
if (completedSet.has(taskId)) continue;
|
||||
try {
|
||||
const task = JSON.parse(Read(`.workflow/.idaw/tasks/${taskId}.json`));
|
||||
if (task.status === 'pending') {
|
||||
remainingTasks.push(task);
|
||||
}
|
||||
} catch {
|
||||
console.log(`Warning: Could not read task ${taskId}, skipping`);
|
||||
}
|
||||
}
|
||||
|
||||
if (remainingTasks.length === 0) {
|
||||
console.log('No remaining tasks to execute. Session complete.');
|
||||
session.status = 'completed';
|
||||
session.current_task = null;
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort: priority ASC, then ID ASC
|
||||
remainingTasks.sort((a, b) => {
|
||||
if (a.priority !== b.priority) return a.priority - b.priority;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
|
||||
console.log(`Remaining tasks: ${remainingTasks.length}`);
|
||||
|
||||
// Append resume marker to progress.md
|
||||
const progressFile = `${sessionDir}/progress.md`;
|
||||
try {
|
||||
const currentProgress = Read(progressFile);
|
||||
Write(progressFile, currentProgress + `\n---\n**Resumed**: ${new Date().toISOString()}\n\n`);
|
||||
} catch {
|
||||
Write(progressFile, `# IDAW Progress — ${session.session_id}\n\n---\n**Resumed**: ${new Date().toISOString()}\n\n`);
|
||||
}
|
||||
|
||||
// Update TodoWrite
|
||||
TodoWrite({
|
||||
todos: remainingTasks.map((t, i) => ({
|
||||
content: `IDAW:[${i + 1}/${remainingTasks.length}] ${t.title}`,
|
||||
status: i === 0 ? 'in_progress' : 'pending',
|
||||
activeForm: `Executing ${t.title}`
|
||||
}))
|
||||
});
|
||||
```
|
||||
|
||||
### Phase 4-6: Execute Remaining (reuse run.md main loop)
|
||||
|
||||
Execute remaining tasks using the same Phase 4-6 logic from `/idaw:run`:
|
||||
|
||||
```javascript
|
||||
// Phase 4: Main Loop — identical to run.md Phase 4
|
||||
for (let taskIdx = 0; taskIdx < remainingTasks.length; taskIdx++) {
|
||||
const task = remainingTasks[taskIdx];
|
||||
|
||||
// Resolve skill chain
|
||||
const resolvedType = task.task_type || inferTaskType(task.title, task.description);
|
||||
const chain = task.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
|
||||
|
||||
// Update task → in_progress
|
||||
task.status = 'in_progress';
|
||||
task.task_type = resolvedType;
|
||||
task.execution.started_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
||||
|
||||
session.current_task = task.id;
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
console.log(`\n--- [${taskIdx + 1}/${remainingTasks.length}] ${task.id}: ${task.title} ---`);
|
||||
console.log(`Chain: ${chain.join(' → ')}`);
|
||||
|
||||
// ━━━ Pre-Task CLI Context Analysis (for complex/bugfix tasks) ━━━
|
||||
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(resolvedType)) {
|
||||
console.log(` Pre-analysis: gathering context for ${resolvedType} task...`);
|
||||
const affectedFiles = (task.context?.affected_files || []).join(', ');
|
||||
const preAnalysisPrompt = `PURPOSE: Pre-analyze codebase context for IDAW task before execution.
|
||||
TASK: • Understand current state of: ${affectedFiles || 'files related to: ' + task.title} • Identify dependencies and risk areas • Note existing patterns to follow
|
||||
MODE: analysis
|
||||
CONTEXT: @**/*
|
||||
EXPECTED: Brief context summary (affected modules, dependencies, risk areas) in 3-5 bullet points
|
||||
CONSTRAINTS: Keep concise | Focus on execution-relevant context`;
|
||||
const preAnalysis = Bash(`ccw cli -p '${preAnalysisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis 2>&1 || echo "Pre-analysis skipped"`);
|
||||
task.execution.skill_results.push({
|
||||
skill: 'cli-pre-analysis',
|
||||
status: 'completed',
|
||||
context_summary: preAnalysis?.substring(0, 500),
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
// Execute skill chain
|
||||
let previousResult = null;
|
||||
let taskFailed = false;
|
||||
|
||||
for (let skillIdx = 0; skillIdx < chain.length; skillIdx++) {
|
||||
const skillName = chain[skillIdx];
|
||||
const skillArgs = assembleSkillArgs(skillName, task, previousResult, autoYes, skillIdx === 0);
|
||||
|
||||
console.log(` [${skillIdx + 1}/${chain.length}] ${skillName}`);
|
||||
|
||||
try {
|
||||
const result = Skill({ skill: skillName, args: skillArgs });
|
||||
previousResult = result;
|
||||
task.execution.skill_results.push({
|
||||
skill: skillName,
|
||||
status: 'completed',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
} catch (error) {
|
||||
// ━━━ CLI-Assisted Error Recovery ━━━
|
||||
console.log(` Diagnosing failure: ${skillName}...`);
|
||||
const diagnosisPrompt = `PURPOSE: Diagnose why skill "${skillName}" failed during IDAW task execution.
|
||||
TASK: • Analyze error: ${String(error).substring(0, 300)} • Check affected files: ${(task.context?.affected_files || []).join(', ') || 'unknown'} • Identify root cause • Suggest fix strategy
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Memory: IDAW task ${task.id}: ${task.title}
|
||||
EXPECTED: Root cause + actionable fix recommendation (1-2 sentences)
|
||||
CONSTRAINTS: Focus on actionable diagnosis`;
|
||||
const diagnosisResult = Bash(`ccw cli -p '${diagnosisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause 2>&1 || echo "CLI diagnosis unavailable"`);
|
||||
|
||||
task.execution.skill_results.push({
|
||||
skill: `cli-diagnosis:${skillName}`,
|
||||
status: 'completed',
|
||||
diagnosis: diagnosisResult?.substring(0, 500),
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Retry with diagnosis context
|
||||
console.log(` Retry with diagnosis: ${skillName}`);
|
||||
try {
|
||||
const retryResult = Skill({ skill: skillName, args: skillArgs });
|
||||
previousResult = retryResult;
|
||||
task.execution.skill_results.push({
|
||||
skill: skillName,
|
||||
status: 'completed-retry-with-diagnosis',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
} catch (retryError) {
|
||||
task.execution.skill_results.push({
|
||||
skill: skillName,
|
||||
status: 'failed',
|
||||
error: String(retryError).substring(0, 200),
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (autoYes) {
|
||||
taskFailed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const answer = AskUserQuestion({
|
||||
questions: [{
|
||||
question: `${skillName} failed after CLI diagnosis + retry: ${String(retryError).substring(0, 100)}`,
|
||||
header: 'Error',
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: 'Skip task', description: 'Mark as failed, continue' },
|
||||
{ label: 'Abort', description: 'Stop run' }
|
||||
]
|
||||
}]
|
||||
});
|
||||
|
||||
if (answer.answers?.Error === 'Abort') {
|
||||
task.status = 'failed';
|
||||
task.execution.error = String(retryError).substring(0, 200);
|
||||
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
||||
session.failed.push(task.id);
|
||||
session.status = 'failed';
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
return;
|
||||
}
|
||||
taskFailed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 5: Checkpoint
|
||||
if (taskFailed) {
|
||||
task.status = 'failed';
|
||||
task.execution.error = 'Skill chain failed after retry';
|
||||
task.execution.completed_at = new Date().toISOString();
|
||||
session.failed.push(task.id);
|
||||
} else {
|
||||
// Git commit
|
||||
const commitMsg = `feat(idaw): ${task.title} [${task.id}]`;
|
||||
const diffCheck = Bash('git diff --stat HEAD 2>/dev/null || echo ""');
|
||||
const untrackedCheck = Bash('git ls-files --others --exclude-standard 2>/dev/null || echo ""');
|
||||
|
||||
if (diffCheck?.trim() || untrackedCheck?.trim()) {
|
||||
Bash('git add -A');
|
||||
Bash(`git commit -m "$(cat <<'EOF'\n${commitMsg}\nEOF\n)"`);
|
||||
const commitHash = Bash('git rev-parse --short HEAD 2>/dev/null')?.trim();
|
||||
task.execution.git_commit = commitHash;
|
||||
} else {
|
||||
task.execution.git_commit = 'no-commit';
|
||||
}
|
||||
|
||||
task.status = 'completed';
|
||||
task.execution.completed_at = new Date().toISOString();
|
||||
session.completed.push(task.id);
|
||||
}
|
||||
|
||||
task.updated_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
// Append progress
|
||||
const chain_str = chain.join(' → ');
|
||||
const progressEntry = `## ${task.id} — ${task.title}\n- Status: ${task.status}\n- Chain: ${chain_str}\n- Commit: ${task.execution.git_commit || '-'}\n\n`;
|
||||
const currentProgress = Read(`${sessionDir}/progress.md`);
|
||||
Write(`${sessionDir}/progress.md`, currentProgress + progressEntry);
|
||||
}
|
||||
|
||||
// Phase 6: Report
|
||||
session.status = session.failed.length > 0 && session.completed.length === 0 ? 'failed' : 'completed';
|
||||
session.current_task = null;
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
const summary = `\n---\n## Summary (Resumed)\n- Completed: ${session.completed.length}\n- Failed: ${session.failed.length}\n- Skipped: ${session.skipped.length}\n`;
|
||||
const finalProgress = Read(`${sessionDir}/progress.md`);
|
||||
Write(`${sessionDir}/progress.md`, finalProgress + summary);
|
||||
|
||||
console.log('\n=== IDAW Resume Complete ===');
|
||||
console.log(`Session: ${session.session_id}`);
|
||||
console.log(`Completed: ${session.completed.length} | Failed: ${session.failed.length} | Skipped: ${session.skipped.length}`);
|
||||
```
|
||||
|
||||
## Helper Functions
|
||||
|
||||
### assembleSkillArgs
|
||||
|
||||
```javascript
|
||||
function assembleSkillArgs(skillName, task, previousResult, autoYes, isFirst) {
|
||||
let args = '';
|
||||
|
||||
if (isFirst) {
|
||||
// Sanitize for shell safety
|
||||
const goal = `${task.title}\n${task.description}`
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/\$/g, '\\$')
|
||||
.replace(/`/g, '\\`');
|
||||
args = `"${goal}"`;
|
||||
if (task.task_type === 'bugfix-hotfix') args += ' --hotfix';
|
||||
} else if (previousResult?.session_id) {
|
||||
args = `--session="${previousResult.session_id}"`;
|
||||
}
|
||||
|
||||
if (autoYes && !args.includes('-y') && !args.includes('--yes')) {
|
||||
args = args ? `${args} -y` : '-y';
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# Resume most recent running session (interactive)
|
||||
/idaw:resume
|
||||
|
||||
# Resume specific session
|
||||
/idaw:resume IDA-auth-fix-20260301
|
||||
|
||||
# Resume with auto mode (skip interrupted, continue)
|
||||
/idaw:resume -y
|
||||
|
||||
# Resume specific session with auto mode
|
||||
/idaw:resume -y IDA-auth-fix-20260301
|
||||
```
|
||||
@@ -1,648 +0,0 @@
|
||||
---
|
||||
name: run-coordinate
|
||||
description: IDAW coordinator - execute task skill chains via external CLI with hook callbacks and git checkpoints
|
||||
argument-hint: "[-y|--yes] [--task <id>[,<id>,...]] [--dry-run] [--tool <tool>]"
|
||||
allowed-tools: Agent(*), AskUserQuestion(*), Read(*), Write(*), Bash(*), Glob(*), Grep(*)
|
||||
---
|
||||
|
||||
# IDAW Run Coordinate Command (/idaw:run-coordinate)
|
||||
|
||||
Coordinator variant of `/idaw:run`: external CLI execution with background tasks and hook callbacks.
|
||||
|
||||
**Execution Model**: `ccw cli -p "..." --tool <tool> --mode write` in background → hook callback → next step.
|
||||
|
||||
**vs `/idaw:run`**: Direct `Skill()` calls (blocking, main process) vs `ccw cli` (background, external process).
|
||||
|
||||
## When to Use
|
||||
|
||||
| Scenario | Use |
|
||||
|----------|-----|
|
||||
| Standard IDAW execution (main process) | `/idaw:run` |
|
||||
| External CLI execution (background, hook-driven) | `/idaw:run-coordinate` |
|
||||
| Need `claude` or `gemini` as execution tool | `/idaw:run-coordinate --tool claude` |
|
||||
| Long-running tasks, avoid context window pressure | `/idaw:run-coordinate` |
|
||||
|
||||
## Skill Chain Mapping
|
||||
|
||||
```javascript
|
||||
const SKILL_CHAIN_MAP = {
|
||||
'bugfix': ['workflow-lite-plan', 'workflow-test-fix'],
|
||||
'bugfix-hotfix': ['workflow-lite-plan'],
|
||||
'feature': ['workflow-lite-plan', 'workflow-test-fix'],
|
||||
'feature-complex': ['workflow-plan', 'workflow-execute', 'workflow-test-fix'],
|
||||
'refactor': ['workflow:refactor-cycle'],
|
||||
'tdd': ['workflow-tdd-plan', 'workflow-execute'],
|
||||
'test': ['workflow-test-fix'],
|
||||
'test-fix': ['workflow-test-fix'],
|
||||
'review': ['review-cycle'],
|
||||
'docs': ['workflow-lite-plan']
|
||||
};
|
||||
```
|
||||
|
||||
## Task Type Inference
|
||||
|
||||
```javascript
|
||||
function inferTaskType(title, description) {
|
||||
const text = `${title} ${description}`.toLowerCase();
|
||||
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
|
||||
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
|
||||
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
|
||||
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
|
||||
if (/generate test|写测试|add test/.test(text)) return 'test';
|
||||
if (/review|code review/.test(text)) return 'review';
|
||||
if (/docs|documentation|readme/.test(text)) return 'docs';
|
||||
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
|
||||
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
|
||||
return 'feature';
|
||||
}
|
||||
```
|
||||
|
||||
## 6-Phase Execution (Coordinator Model)
|
||||
|
||||
### Phase 1: Load Tasks
|
||||
|
||||
```javascript
|
||||
const args = $ARGUMENTS;
|
||||
const autoYes = /(-y|--yes)/.test(args);
|
||||
const dryRun = /--dry-run/.test(args);
|
||||
const taskFilter = args.match(/--task\s+([\w,-]+)/)?.[1]?.split(',') || null;
|
||||
const cliTool = args.match(/--tool\s+(\w+)/)?.[1] || 'claude';
|
||||
|
||||
// Load task files
|
||||
const taskFiles = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
|
||||
|
||||
if (taskFiles.length === 0) {
|
||||
console.log('No IDAW tasks found. Use /idaw:add to create tasks.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse and filter
|
||||
let tasks = taskFiles.map(f => JSON.parse(Read(f)));
|
||||
|
||||
if (taskFilter) {
|
||||
tasks = tasks.filter(t => taskFilter.includes(t.id));
|
||||
} else {
|
||||
tasks = tasks.filter(t => t.status === 'pending');
|
||||
}
|
||||
|
||||
if (tasks.length === 0) {
|
||||
console.log('No pending tasks to execute. Use /idaw:add to add tasks or --task to specify IDs.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort: priority ASC (1=critical first), then ID ASC
|
||||
tasks.sort((a, b) => {
|
||||
if (a.priority !== b.priority) return a.priority - b.priority;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
```
|
||||
|
||||
### Phase 2: Session Setup
|
||||
|
||||
```javascript
|
||||
// Generate session ID: IDA-{slug}-YYYYMMDD
|
||||
const slug = tasks[0].title
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.substring(0, 20)
|
||||
.replace(/-$/, '');
|
||||
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
||||
let sessionId = `IDA-${slug}-${dateStr}`;
|
||||
|
||||
// Check collision
|
||||
const existingSession = Glob(`.workflow/.idaw/sessions/${sessionId}/session.json`);
|
||||
if (existingSession?.length > 0) {
|
||||
sessionId = `${sessionId}-2`;
|
||||
}
|
||||
|
||||
const sessionDir = `.workflow/.idaw/sessions/${sessionId}`;
|
||||
Bash(`mkdir -p "${sessionDir}"`);
|
||||
|
||||
const session = {
|
||||
session_id: sessionId,
|
||||
mode: 'coordinate', // ★ Marks this as coordinator-mode session
|
||||
cli_tool: cliTool,
|
||||
status: 'running',
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
tasks: tasks.map(t => t.id),
|
||||
current_task: null,
|
||||
current_skill_index: 0,
|
||||
completed: [],
|
||||
failed: [],
|
||||
skipped: [],
|
||||
prompts_used: []
|
||||
};
|
||||
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
// Initialize progress.md
|
||||
const progressHeader = `# IDAW Progress — ${sessionId} (coordinate mode)\nStarted: ${session.created_at}\nCLI Tool: ${cliTool}\n\n`;
|
||||
Write(`${sessionDir}/progress.md`, progressHeader);
|
||||
```
|
||||
|
||||
### Phase 3: Startup Protocol
|
||||
|
||||
```javascript
|
||||
// Check for existing running sessions
|
||||
const runningSessions = Glob('.workflow/.idaw/sessions/IDA-*/session.json')
|
||||
?.map(f => { try { return JSON.parse(Read(f)); } catch { return null; } })
|
||||
.filter(s => s && s.status === 'running' && s.session_id !== sessionId) || [];
|
||||
|
||||
if (runningSessions.length > 0 && !autoYes) {
|
||||
const answer = AskUserQuestion({
|
||||
questions: [{
|
||||
question: `Found running session: ${runningSessions[0].session_id}. How to proceed?`,
|
||||
header: 'Conflict',
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: 'Resume existing', description: 'Use /idaw:resume instead' },
|
||||
{ label: 'Start fresh', description: 'Continue with new session' },
|
||||
{ label: 'Abort', description: 'Cancel this run' }
|
||||
]
|
||||
}]
|
||||
});
|
||||
if (answer.answers?.Conflict === 'Resume existing') {
|
||||
console.log(`Use: /idaw:resume ${runningSessions[0].session_id}`);
|
||||
return;
|
||||
}
|
||||
if (answer.answers?.Conflict === 'Abort') return;
|
||||
}
|
||||
|
||||
// Check git status
|
||||
const gitStatus = Bash('git status --porcelain 2>/dev/null');
|
||||
if (gitStatus?.trim() && !autoYes) {
|
||||
const answer = AskUserQuestion({
|
||||
questions: [{
|
||||
question: 'Working tree has uncommitted changes. How to proceed?',
|
||||
header: 'Git',
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: 'Continue', description: 'Proceed with dirty tree' },
|
||||
{ label: 'Stash', description: 'git stash before running' },
|
||||
{ label: 'Abort', description: 'Stop and handle manually' }
|
||||
]
|
||||
}]
|
||||
});
|
||||
if (answer.answers?.Git === 'Stash') Bash('git stash push -m "idaw-pre-run"');
|
||||
if (answer.answers?.Git === 'Abort') return;
|
||||
}
|
||||
|
||||
// Dry run
|
||||
if (dryRun) {
|
||||
console.log(`# Dry Run — ${sessionId} (coordinate mode, tool: ${cliTool})\n`);
|
||||
for (const task of tasks) {
|
||||
const taskType = task.task_type || inferTaskType(task.title, task.description);
|
||||
const chain = task.skill_chain || SKILL_CHAIN_MAP[taskType] || SKILL_CHAIN_MAP['feature'];
|
||||
console.log(`## ${task.id}: ${task.title}`);
|
||||
console.log(` Type: ${taskType} | Priority: ${task.priority}`);
|
||||
console.log(` Chain: ${chain.join(' → ')}`);
|
||||
console.log(` CLI: ccw cli --tool ${cliTool} --mode write\n`);
|
||||
}
|
||||
console.log(`Total: ${tasks.length} tasks`);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Launch First Task (then wait for hook)
|
||||
|
||||
```javascript
|
||||
// Start with the first task, first skill
|
||||
const firstTask = tasks[0];
|
||||
const resolvedType = firstTask.task_type || inferTaskType(firstTask.title, firstTask.description);
|
||||
const chain = firstTask.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
|
||||
|
||||
// Update task → in_progress
|
||||
firstTask.status = 'in_progress';
|
||||
firstTask.task_type = resolvedType;
|
||||
firstTask.execution.started_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${firstTask.id}.json`, JSON.stringify(firstAgent, null, 2));
|
||||
|
||||
// Update session
|
||||
session.current_task = firstTask.id;
|
||||
session.current_skill_index = 0;
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
// ━━━ Pre-Task CLI Context Analysis (for complex/bugfix tasks) ━━━
|
||||
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(resolvedType)) {
|
||||
console.log(`Pre-analysis: gathering context for ${resolvedType} task...`);
|
||||
const affectedFiles = (firstTask.context?.affected_files || []).join(', ');
|
||||
const preAnalysisPrompt = `PURPOSE: Pre-analyze codebase context for IDAW task.
|
||||
TASK: • Understand current state of: ${affectedFiles || 'files related to: ' + firstTask.title} • Identify dependencies and risk areas
|
||||
MODE: analysis
|
||||
CONTEXT: @**/*
|
||||
EXPECTED: Brief context summary in 3-5 bullet points
|
||||
CONSTRAINTS: Keep concise`;
|
||||
Bash(`ccw cli -p '${preAnalysisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis 2>&1 || echo "Pre-analysis skipped"`);
|
||||
}
|
||||
|
||||
// Assemble prompt for first skill
|
||||
const skillName = chain[0];
|
||||
const prompt = assembleCliPrompt(skillName, firstAgent, null, autoYes);
|
||||
|
||||
session.prompts_used.push({
|
||||
task_id: firstTask.id,
|
||||
skill_index: 0,
|
||||
skill: skillName,
|
||||
prompt: prompt,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
// Launch via ccw cli in background
|
||||
console.log(`[1/${tasks.length}] ${firstTask.id}: ${firstTask.title}`);
|
||||
console.log(` Chain: ${chain.join(' → ')}`);
|
||||
console.log(` Launching: ${skillName} via ccw cli --tool ${cliTool}`);
|
||||
|
||||
Bash(
|
||||
`ccw cli -p "${escapeForShell(prompt)}" --tool ${cliTool} --mode write`,
|
||||
{ run_in_background: true }
|
||||
);
|
||||
|
||||
// ★ STOP HERE — wait for hook callback
|
||||
// Hook callback will trigger handleStepCompletion() below
|
||||
```
|
||||
|
||||
### Phase 5: Hook Callback Handler (per-step completion)
|
||||
|
||||
```javascript
|
||||
// Called by hook when background CLI completes
|
||||
async function handleStepCompletion(sessionId, cliOutput) {
|
||||
const sessionDir = `.workflow/.idaw/sessions/${sessionId}`;
|
||||
const session = JSON.parse(Read(`${sessionDir}/session.json`));
|
||||
|
||||
const taskId = session.current_task;
|
||||
const task = JSON.parse(Read(`.workflow/.idaw/tasks/${taskId}.json`));
|
||||
|
||||
const resolvedType = task.task_type || inferTaskType(task.title, task.description);
|
||||
const chain = task.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
|
||||
const skillIdx = session.current_skill_index;
|
||||
const skillName = chain[skillIdx];
|
||||
|
||||
// Parse CLI output for session ID
|
||||
const parsedOutput = parseCliOutput(cliOutput);
|
||||
|
||||
// Record skill result
|
||||
task.execution.skill_results.push({
|
||||
skill: skillName,
|
||||
status: parsedOutput.success ? 'completed' : 'failed',
|
||||
session_id: parsedOutput.sessionId,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// ━━━ Handle failure with CLI diagnosis ━━━
|
||||
if (!parsedOutput.success) {
|
||||
console.log(` ${skillName} failed. Running CLI diagnosis...`);
|
||||
const diagnosisPrompt = `PURPOSE: Diagnose why skill "${skillName}" failed during IDAW task.
|
||||
TASK: • Analyze error output • Check affected files: ${(task.context?.affected_files || []).join(', ') || 'unknown'}
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Memory: IDAW task ${task.id}: ${task.title}
|
||||
EXPECTED: Root cause + fix recommendation
|
||||
CONSTRAINTS: Actionable diagnosis`;
|
||||
Bash(`ccw cli -p '${diagnosisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause 2>&1 || true`);
|
||||
|
||||
task.execution.skill_results.push({
|
||||
skill: `cli-diagnosis:${skillName}`,
|
||||
status: 'completed',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Retry once
|
||||
console.log(` Retrying: ${skillName}`);
|
||||
const retryPrompt = assembleCliPrompt(skillName, task, parsedOutput, true);
|
||||
session.prompts_used.push({
|
||||
task_id: taskId,
|
||||
skill_index: skillIdx,
|
||||
skill: `${skillName}-retry`,
|
||||
prompt: retryPrompt,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
|
||||
|
||||
Bash(
|
||||
`ccw cli -p "${escapeForShell(retryPrompt)}" --tool ${session.cli_tool} --mode write`,
|
||||
{ run_in_background: true }
|
||||
);
|
||||
return; // Wait for retry hook
|
||||
}
|
||||
|
||||
// ━━━ Skill succeeded — advance ━━━
|
||||
const nextSkillIdx = skillIdx + 1;
|
||||
|
||||
if (nextSkillIdx < chain.length) {
|
||||
// More skills in this task's chain → launch next skill
|
||||
session.current_skill_index = nextSkillIdx;
|
||||
session.updated_at = new Date().toISOString();
|
||||
|
||||
const nextSkill = chain[nextSkillIdx];
|
||||
const nextPrompt = assembleCliPrompt(nextSkill, task, parsedOutput, true);
|
||||
|
||||
session.prompts_used.push({
|
||||
task_id: taskId,
|
||||
skill_index: nextSkillIdx,
|
||||
skill: nextSkill,
|
||||
prompt: nextPrompt,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
|
||||
|
||||
console.log(` Next skill: ${nextSkill}`);
|
||||
Bash(
|
||||
`ccw cli -p "${escapeForShell(nextPrompt)}" --tool ${session.cli_tool} --mode write`,
|
||||
{ run_in_background: true }
|
||||
);
|
||||
return; // Wait for next hook
|
||||
}
|
||||
|
||||
// ━━━ Task chain complete — git checkpoint ━━━
|
||||
const commitMsg = `feat(idaw): ${task.title} [${task.id}]`;
|
||||
const diffCheck = Bash('git diff --stat HEAD 2>/dev/null || echo ""');
|
||||
const untrackedCheck = Bash('git ls-files --others --exclude-standard 2>/dev/null || echo ""');
|
||||
|
||||
if (diffCheck?.trim() || untrackedCheck?.trim()) {
|
||||
Bash('git add -A');
|
||||
Bash(`git commit -m "$(cat <<'EOF'\n${commitMsg}\nEOF\n)"`);
|
||||
const commitHash = Bash('git rev-parse --short HEAD 2>/dev/null')?.trim();
|
||||
task.execution.git_commit = commitHash;
|
||||
} else {
|
||||
task.execution.git_commit = 'no-commit';
|
||||
}
|
||||
|
||||
task.status = 'completed';
|
||||
task.execution.completed_at = new Date().toISOString();
|
||||
task.updated_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${taskId}.json`, JSON.stringify(task, null, 2));
|
||||
|
||||
session.completed.push(taskId);
|
||||
|
||||
// Append progress
|
||||
const progressEntry = `## ${task.id} — ${task.title}\n` +
|
||||
`- Status: completed\n` +
|
||||
`- Type: ${task.task_type}\n` +
|
||||
`- Chain: ${chain.join(' → ')}\n` +
|
||||
`- Commit: ${task.execution.git_commit || '-'}\n` +
|
||||
`- Mode: coordinate (${session.cli_tool})\n\n`;
|
||||
const currentProgress = Read(`${sessionDir}/progress.md`);
|
||||
Write(`${sessionDir}/progress.md`, currentProgress + progressEntry);
|
||||
|
||||
// ━━━ Advance to next task ━━━
|
||||
const allTaskIds = session.tasks;
|
||||
const completedSet = new Set([...session.completed, ...session.failed, ...session.skipped]);
|
||||
const nextTaskId = allTaskIds.find(id => !completedSet.has(id));
|
||||
|
||||
if (nextTaskId) {
|
||||
// Load next task
|
||||
const nextTask = JSON.parse(Read(`.workflow/.idaw/tasks/${nextTaskId}.json`));
|
||||
const nextType = nextTask.task_type || inferTaskType(nextTask.title, nextTask.description);
|
||||
const nextChain = nextTask.skill_chain || SKILL_CHAIN_MAP[nextType] || SKILL_CHAIN_MAP['feature'];
|
||||
|
||||
nextTask.status = 'in_progress';
|
||||
nextTask.task_type = nextType;
|
||||
nextTask.execution.started_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${nextTaskId}.json`, JSON.stringify(nextAgent, null, 2));
|
||||
|
||||
session.current_task = nextTaskId;
|
||||
session.current_skill_index = 0;
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
// Pre-analysis for complex tasks
|
||||
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(nextType)) {
|
||||
const affectedFiles = (nextTask.context?.affected_files || []).join(', ');
|
||||
Bash(`ccw cli -p 'PURPOSE: Pre-analyze context for ${nextTask.title}. TASK: Check ${affectedFiles || "related files"}. MODE: analysis. EXPECTED: 3-5 bullet points.' --tool gemini --mode analysis 2>&1 || true`);
|
||||
}
|
||||
|
||||
const nextSkillName = nextChain[0];
|
||||
const nextPrompt = assembleCliPrompt(nextSkillName, nextAgent, null, true);
|
||||
|
||||
session.prompts_used.push({
|
||||
task_id: nextTaskId,
|
||||
skill_index: 0,
|
||||
skill: nextSkillName,
|
||||
prompt: nextPrompt,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
const taskNum = session.completed.length + 1;
|
||||
const totalTasks = session.tasks.length;
|
||||
console.log(`\n[${taskNum}/${totalTasks}] ${nextTaskId}: ${nextTask.title}`);
|
||||
console.log(` Chain: ${nextChain.join(' → ')}`);
|
||||
|
||||
Bash(
|
||||
`ccw cli -p "${escapeForShell(nextPrompt)}" --tool ${session.cli_tool} --mode write`,
|
||||
{ run_in_background: true }
|
||||
);
|
||||
return; // Wait for hook
|
||||
}
|
||||
|
||||
// ━━━ All tasks complete — Phase 6: Report ━━━
|
||||
session.status = session.failed.length > 0 && session.completed.length === 0 ? 'failed' : 'completed';
|
||||
session.current_task = null;
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
const summary = `\n---\n## Summary (coordinate mode)\n` +
|
||||
`- CLI Tool: ${session.cli_tool}\n` +
|
||||
`- Completed: ${session.completed.length}\n` +
|
||||
`- Failed: ${session.failed.length}\n` +
|
||||
`- Skipped: ${session.skipped.length}\n` +
|
||||
`- Total: ${session.tasks.length}\n`;
|
||||
const finalProgress = Read(`${sessionDir}/progress.md`);
|
||||
Write(`${sessionDir}/progress.md`, finalProgress + summary);
|
||||
|
||||
console.log('\n=== IDAW Coordinate Complete ===');
|
||||
console.log(`Session: ${sessionId}`);
|
||||
console.log(`Completed: ${session.completed.length}/${session.tasks.length}`);
|
||||
if (session.failed.length > 0) console.log(`Failed: ${session.failed.join(', ')}`);
|
||||
}
|
||||
```
|
||||
|
||||
## Helper Functions
|
||||
|
||||
### assembleCliPrompt
|
||||
|
||||
```javascript
|
||||
function assembleCliPrompt(skillName, task, previousResult, autoYes) {
|
||||
let prompt = '';
|
||||
const yFlag = autoYes ? ' -y' : '';
|
||||
|
||||
// Map skill to command invocation
|
||||
if (skillName === 'workflow-lite-plan') {
|
||||
const goal = sanitize(`${task.title}\n${task.description}`);
|
||||
prompt = `/workflow-lite-plan${yFlag} "${goal}"`;
|
||||
if (task.task_type === 'bugfix') prompt = `/workflow-lite-plan${yFlag} --bugfix "${goal}"`;
|
||||
if (task.task_type === 'bugfix-hotfix') prompt = `/workflow-lite-plan${yFlag} --hotfix "${goal}"`;
|
||||
|
||||
} else if (skillName === 'workflow-plan') {
|
||||
prompt = `/workflow-plan${yFlag} "${sanitize(task.title)}"`;
|
||||
|
||||
} else if (skillName === 'workflow-execute') {
|
||||
if (previousResult?.sessionId) {
|
||||
prompt = `/workflow-execute${yFlag} --resume-session="${previousResult.sessionId}"`;
|
||||
} else {
|
||||
prompt = `/workflow-execute${yFlag}`;
|
||||
}
|
||||
|
||||
} else if (skillName === 'workflow-test-fix') {
|
||||
if (previousResult?.sessionId) {
|
||||
prompt = `/workflow-test-fix${yFlag} "${previousResult.sessionId}"`;
|
||||
} else {
|
||||
prompt = `/workflow-test-fix${yFlag} "${sanitize(task.title)}"`;
|
||||
}
|
||||
|
||||
} else if (skillName === 'workflow-tdd-plan') {
|
||||
prompt = `/workflow-tdd-plan${yFlag} "${sanitize(task.title)}"`;
|
||||
|
||||
} else if (skillName === 'workflow:refactor-cycle') {
|
||||
prompt = `/workflow:refactor-cycle${yFlag} "${sanitize(task.title)}"`;
|
||||
|
||||
} else if (skillName === 'review-cycle') {
|
||||
if (previousResult?.sessionId) {
|
||||
prompt = `/review-cycle${yFlag} --session="${previousResult.sessionId}"`;
|
||||
} else {
|
||||
prompt = `/review-cycle${yFlag}`;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Generic fallback
|
||||
prompt = `/${skillName}${yFlag} "${sanitize(task.title)}"`;
|
||||
}
|
||||
|
||||
// Append task context
|
||||
prompt += `\n\nTask: ${task.title}\nDescription: ${task.description}`;
|
||||
if (task.context?.affected_files?.length > 0) {
|
||||
prompt += `\nAffected files: ${task.context.affected_files.join(', ')}`;
|
||||
}
|
||||
if (task.context?.acceptance_criteria?.length > 0) {
|
||||
prompt += `\nAcceptance criteria: ${task.context.acceptance_criteria.join('; ')}`;
|
||||
}
|
||||
|
||||
return prompt;
|
||||
}
|
||||
```
|
||||
|
||||
### sanitize & escapeForShell
|
||||
|
||||
```javascript
|
||||
function sanitize(text) {
|
||||
return text
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/\$/g, '\\$')
|
||||
.replace(/`/g, '\\`');
|
||||
}
|
||||
|
||||
function escapeForShell(prompt) {
|
||||
return prompt.replace(/'/g, "'\\''");
|
||||
}
|
||||
```
|
||||
|
||||
### parseCliOutput
|
||||
|
||||
```javascript
|
||||
function parseCliOutput(output) {
|
||||
// Extract session ID from CLI output (e.g., WFS-xxx, session-xxx)
|
||||
const sessionMatch = output.match(/(?:session|WFS|Session ID)[:\s]*([\w-]+)/i);
|
||||
const success = !/(?:error|failed|fatal)/i.test(output) || /completed|success/i.test(output);
|
||||
|
||||
return {
|
||||
success,
|
||||
sessionId: sessionMatch?.[1] || null,
|
||||
raw: output?.substring(0, 500)
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## CLI-Assisted Analysis
|
||||
|
||||
Same as `/idaw:run` — integrated at two points:
|
||||
|
||||
### Pre-Task Context Analysis
|
||||
For `bugfix`, `bugfix-hotfix`, `feature-complex` tasks: auto-invoke `ccw cli --tool gemini --mode analysis` before launching skill chain.
|
||||
|
||||
### Error Recovery with CLI Diagnosis
|
||||
When a skill's CLI execution fails: invoke diagnosis → retry once → if still fails, mark failed and advance.
|
||||
|
||||
```
|
||||
Skill CLI fails → CLI diagnosis (gemini) → Retry CLI → Still fails → mark failed → next task
|
||||
```
|
||||
|
||||
## State Flow
|
||||
|
||||
```
|
||||
Phase 4: Launch first skill
|
||||
↓
|
||||
ccw cli --tool claude --mode write (background)
|
||||
↓
|
||||
★ STOP — wait for hook callback
|
||||
↓
|
||||
Phase 5: handleStepCompletion()
|
||||
├─ Skill succeeded + more in chain → launch next skill → STOP
|
||||
├─ Skill succeeded + chain complete → git checkpoint → next task → STOP
|
||||
├─ Skill failed → CLI diagnosis → retry → STOP
|
||||
└─ All tasks done → Phase 6: Report
|
||||
```
|
||||
|
||||
## Session State (session.json)
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "IDA-fix-login-20260301",
|
||||
"mode": "coordinate",
|
||||
"cli_tool": "claude",
|
||||
"status": "running|waiting|completed|failed",
|
||||
"created_at": "ISO",
|
||||
"updated_at": "ISO",
|
||||
"tasks": ["IDAW-001", "IDAW-002"],
|
||||
"current_task": "IDAW-001",
|
||||
"current_skill_index": 0,
|
||||
"completed": [],
|
||||
"failed": [],
|
||||
"skipped": [],
|
||||
"prompts_used": [
|
||||
{
|
||||
"task_id": "IDAW-001",
|
||||
"skill_index": 0,
|
||||
"skill": "workflow-lite-plan",
|
||||
"prompt": "/workflow-lite-plan -y \"Fix login timeout\"",
|
||||
"timestamp": "ISO"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Differences from /idaw:run
|
||||
|
||||
| Aspect | /idaw:run | /idaw:run-coordinate |
|
||||
|--------|-----------|---------------------|
|
||||
| Execution | `Skill()` blocking in main process | `ccw cli` background + hook callback |
|
||||
| Context window | Shared (each skill uses main context) | Isolated (each CLI gets fresh context) |
|
||||
| Concurrency | Sequential blocking | Sequential non-blocking (hook-driven) |
|
||||
| State tracking | session.json + task.json | session.json + task.json + prompts_used |
|
||||
| Tool selection | N/A (Skill native) | `--tool claude\|gemini\|qwen` |
|
||||
| Resume | Via `/idaw:resume` (same) | Via `/idaw:resume` (same, detects mode) |
|
||||
| Best for | Short chains, interactive | Long chains, autonomous, context-heavy |
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# Execute all pending tasks via claude CLI
|
||||
/idaw:run-coordinate -y
|
||||
|
||||
# Use specific CLI tool
|
||||
/idaw:run-coordinate -y --tool gemini
|
||||
|
||||
# Execute specific tasks
|
||||
/idaw:run-coordinate --task IDAW-001,IDAW-003 --tool claude
|
||||
|
||||
# Dry run (show plan without executing)
|
||||
/idaw:run-coordinate --dry-run
|
||||
|
||||
# Interactive mode
|
||||
/idaw:run-coordinate
|
||||
```
|
||||
@@ -1,539 +0,0 @@
|
||||
---
|
||||
name: run
|
||||
description: IDAW orchestrator - execute task skill chains serially with git checkpoints
|
||||
argument-hint: "[-y|--yes] [--task <id>[,<id>,...]] [--dry-run]"
|
||||
allowed-tools: Skill(*), TodoWrite(*), AskUserQuestion(*), Read(*), Write(*), Bash(*), Glob(*)
|
||||
---
|
||||
|
||||
# IDAW Run Command (/idaw:run)
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--yes` or `-y`: Skip all confirmations, auto-skip on failure, proceed with dirty git.
|
||||
|
||||
## Skill Chain Mapping
|
||||
|
||||
```javascript
|
||||
const SKILL_CHAIN_MAP = {
|
||||
'bugfix': ['workflow-lite-plan', 'workflow-test-fix'],
|
||||
'bugfix-hotfix': ['workflow-lite-plan'],
|
||||
'feature': ['workflow-lite-plan', 'workflow-test-fix'],
|
||||
'feature-complex': ['workflow-plan', 'workflow-execute', 'workflow-test-fix'],
|
||||
'refactor': ['workflow:refactor-cycle'],
|
||||
'tdd': ['workflow-tdd-plan', 'workflow-execute'],
|
||||
'test': ['workflow-test-fix'],
|
||||
'test-fix': ['workflow-test-fix'],
|
||||
'review': ['review-cycle'],
|
||||
'docs': ['workflow-lite-plan']
|
||||
};
|
||||
```
|
||||
|
||||
## Task Type Inference
|
||||
|
||||
```javascript
|
||||
function inferTaskType(title, description) {
|
||||
const text = `${title} ${description}`.toLowerCase();
|
||||
if (/urgent|production|critical/.test(text) && /fix|bug/.test(text)) return 'bugfix-hotfix';
|
||||
if (/refactor|重构|tech.*debt/.test(text)) return 'refactor';
|
||||
if (/tdd|test-driven|test first/.test(text)) return 'tdd';
|
||||
if (/test fail|fix test|failing test/.test(text)) return 'test-fix';
|
||||
if (/generate test|写测试|add test/.test(text)) return 'test';
|
||||
if (/review|code review/.test(text)) return 'review';
|
||||
if (/docs|documentation|readme/.test(text)) return 'docs';
|
||||
if (/fix|bug|error|crash|fail/.test(text)) return 'bugfix';
|
||||
if (/complex|multi-module|architecture/.test(text)) return 'feature-complex';
|
||||
return 'feature';
|
||||
}
|
||||
```
|
||||
|
||||
## 6-Phase Execution
|
||||
|
||||
### Phase 1: Load Tasks
|
||||
|
||||
```javascript
|
||||
const args = $ARGUMENTS;
|
||||
const autoYes = /(-y|--yes)/.test(args);
|
||||
const dryRun = /--dry-run/.test(args);
|
||||
const taskFilter = args.match(/--task\s+([\w,-]+)/)?.[1]?.split(',') || null;
|
||||
|
||||
// Load task files
|
||||
const taskFiles = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
|
||||
|
||||
if (taskFiles.length === 0) {
|
||||
console.log('No IDAW tasks found. Use /idaw:add to create tasks.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse and filter
|
||||
let tasks = taskFiles.map(f => JSON.parse(Read(f)));
|
||||
|
||||
if (taskFilter) {
|
||||
tasks = tasks.filter(t => taskFilter.includes(t.id));
|
||||
} else {
|
||||
tasks = tasks.filter(t => t.status === 'pending');
|
||||
}
|
||||
|
||||
if (tasks.length === 0) {
|
||||
console.log('No pending tasks to execute. Use /idaw:add to add tasks or --task to specify IDs.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort: priority ASC (1=critical first), then ID ASC
|
||||
tasks.sort((a, b) => {
|
||||
if (a.priority !== b.priority) return a.priority - b.priority;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
```
|
||||
|
||||
### Phase 2: Session Setup
|
||||
|
||||
```javascript
|
||||
// Generate session ID: IDA-{slug}-YYYYMMDD
|
||||
const slug = tasks[0].title
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.substring(0, 20)
|
||||
.replace(/-$/, '');
|
||||
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
||||
let sessionId = `IDA-${slug}-${dateStr}`;
|
||||
|
||||
// Check collision
|
||||
const existingSession = Glob(`.workflow/.idaw/sessions/${sessionId}/session.json`);
|
||||
if (existingSession?.length > 0) {
|
||||
sessionId = `${sessionId}-2`;
|
||||
}
|
||||
|
||||
const sessionDir = `.workflow/.idaw/sessions/${sessionId}`;
|
||||
Bash(`mkdir -p "${sessionDir}"`);
|
||||
|
||||
const session = {
|
||||
session_id: sessionId,
|
||||
status: 'running',
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
tasks: tasks.map(t => t.id),
|
||||
current_task: null,
|
||||
completed: [],
|
||||
failed: [],
|
||||
skipped: []
|
||||
};
|
||||
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
// Initialize progress.md
|
||||
const progressHeader = `# IDAW Progress — ${sessionId}\nStarted: ${session.created_at}\n\n`;
|
||||
Write(`${sessionDir}/progress.md`, progressHeader);
|
||||
|
||||
// TodoWrite
|
||||
TodoWrite({
|
||||
todos: tasks.map((t, i) => ({
|
||||
content: `IDAW:[${i + 1}/${tasks.length}] ${t.title}`,
|
||||
status: i === 0 ? 'in_progress' : 'pending',
|
||||
activeForm: `Executing ${t.title}`
|
||||
}))
|
||||
});
|
||||
```
|
||||
|
||||
### Phase 3: Startup Protocol
|
||||
|
||||
```javascript
|
||||
// Check for existing running sessions
|
||||
const runningSessions = Glob('.workflow/.idaw/sessions/IDA-*/session.json')
|
||||
?.map(f => JSON.parse(Read(f)))
|
||||
.filter(s => s.status === 'running' && s.session_id !== sessionId) || [];
|
||||
|
||||
if (runningSessions.length > 0) {
|
||||
if (!autoYes) {
|
||||
const answer = AskUserQuestion({
|
||||
questions: [{
|
||||
question: `Found running session: ${runningSessions[0].session_id}. How to proceed?`,
|
||||
header: 'Conflict',
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: 'Resume existing', description: 'Use /idaw:resume instead' },
|
||||
{ label: 'Start fresh', description: 'Continue with new session' },
|
||||
{ label: 'Abort', description: 'Cancel this run' }
|
||||
]
|
||||
}]
|
||||
});
|
||||
if (answer.answers?.Conflict === 'Resume existing') {
|
||||
console.log(`Use: /idaw:resume ${runningSessions[0].session_id}`);
|
||||
return;
|
||||
}
|
||||
if (answer.answers?.Conflict === 'Abort') return;
|
||||
}
|
||||
// autoYes or "Start fresh": proceed
|
||||
}
|
||||
|
||||
// Check git status
|
||||
const gitStatus = Bash('git status --porcelain 2>/dev/null');
|
||||
if (gitStatus?.trim()) {
|
||||
if (!autoYes) {
|
||||
const answer = AskUserQuestion({
|
||||
questions: [{
|
||||
question: 'Working tree has uncommitted changes. How to proceed?',
|
||||
header: 'Git',
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: 'Continue', description: 'Proceed with dirty tree' },
|
||||
{ label: 'Stash', description: 'git stash before running' },
|
||||
{ label: 'Abort', description: 'Stop and handle manually' }
|
||||
]
|
||||
}]
|
||||
});
|
||||
if (answer.answers?.Git === 'Stash') {
|
||||
Bash('git stash push -m "idaw-pre-run"');
|
||||
}
|
||||
if (answer.answers?.Git === 'Abort') return;
|
||||
}
|
||||
// autoYes: proceed silently
|
||||
}
|
||||
|
||||
// Dry run: show plan and exit
|
||||
if (dryRun) {
|
||||
console.log(`# Dry Run — ${sessionId}\n`);
|
||||
for (const task of tasks) {
|
||||
const taskType = task.task_type || inferTaskType(task.title, task.description);
|
||||
const chain = task.skill_chain || SKILL_CHAIN_MAP[taskType] || SKILL_CHAIN_MAP['feature'];
|
||||
console.log(`## ${task.id}: ${task.title}`);
|
||||
console.log(` Type: ${taskType} | Priority: ${task.priority}`);
|
||||
console.log(` Chain: ${chain.join(' → ')}\n`);
|
||||
}
|
||||
console.log(`Total: ${tasks.length} tasks`);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Main Loop (serial, one task at a time)
|
||||
|
||||
```javascript
|
||||
for (let taskIdx = 0; taskIdx < tasks.length; taskIdx++) {
|
||||
const task = tasks[taskIdx];
|
||||
|
||||
// Skip completed/failed/skipped
|
||||
if (['completed', 'failed', 'skipped'].includes(task.status)) continue;
|
||||
|
||||
// Resolve skill chain
|
||||
const resolvedType = task.task_type || inferTaskType(task.title, task.description);
|
||||
const chain = task.skill_chain || SKILL_CHAIN_MAP[resolvedType] || SKILL_CHAIN_MAP['feature'];
|
||||
|
||||
// Update task status → in_progress
|
||||
task.status = 'in_progress';
|
||||
task.task_type = resolvedType; // persist inferred type
|
||||
task.execution.started_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
||||
|
||||
// Update session
|
||||
session.current_task = task.id;
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
console.log(`\n--- [${taskIdx + 1}/${tasks.length}] ${task.id}: ${task.title} ---`);
|
||||
console.log(`Chain: ${chain.join(' → ')}`);
|
||||
|
||||
// ━━━ Pre-Task CLI Context Analysis (for complex/bugfix tasks) ━━━
|
||||
if (['bugfix', 'bugfix-hotfix', 'feature-complex'].includes(resolvedType)) {
|
||||
console.log(` Pre-analysis: gathering context for ${resolvedType} task...`);
|
||||
const affectedFiles = (task.context?.affected_files || []).join(', ');
|
||||
const preAnalysisPrompt = `PURPOSE: Pre-analyze codebase context for IDAW task before execution.
|
||||
TASK: • Understand current state of: ${affectedFiles || 'files related to: ' + task.title} • Identify dependencies and risk areas • Note existing patterns to follow
|
||||
MODE: analysis
|
||||
CONTEXT: @**/*
|
||||
EXPECTED: Brief context summary (affected modules, dependencies, risk areas) in 3-5 bullet points
|
||||
CONSTRAINTS: Keep concise | Focus on execution-relevant context`;
|
||||
const preAnalysis = Bash(`ccw cli -p '${preAnalysisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis 2>&1 || echo "Pre-analysis skipped"`);
|
||||
task.execution.skill_results.push({
|
||||
skill: 'cli-pre-analysis',
|
||||
status: 'completed',
|
||||
context_summary: preAnalysis?.substring(0, 500),
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
// Execute each skill in chain
|
||||
let previousResult = null;
|
||||
let taskFailed = false;
|
||||
|
||||
for (let skillIdx = 0; skillIdx < chain.length; skillIdx++) {
|
||||
const skillName = chain[skillIdx];
|
||||
const skillArgs = assembleSkillArgs(skillName, task, previousResult, autoYes, skillIdx === 0);
|
||||
|
||||
console.log(` [${skillIdx + 1}/${chain.length}] ${skillName}`);
|
||||
|
||||
try {
|
||||
const result = Skill({ skill: skillName, args: skillArgs });
|
||||
previousResult = result;
|
||||
task.execution.skill_results.push({
|
||||
skill: skillName,
|
||||
status: 'completed',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
} catch (error) {
|
||||
// ━━━ CLI-Assisted Error Recovery ━━━
|
||||
// Step 1: Invoke CLI diagnosis (auto-invoke trigger: self-repair fails)
|
||||
console.log(` Diagnosing failure: ${skillName}...`);
|
||||
const diagnosisPrompt = `PURPOSE: Diagnose why skill "${skillName}" failed during IDAW task execution.
|
||||
TASK: • Analyze error: ${String(error).substring(0, 300)} • Check affected files: ${(task.context?.affected_files || []).join(', ') || 'unknown'} • Identify root cause • Suggest fix strategy
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Memory: IDAW task ${task.id}: ${task.title}
|
||||
EXPECTED: Root cause + actionable fix recommendation (1-2 sentences)
|
||||
CONSTRAINTS: Focus on actionable diagnosis`;
|
||||
const diagnosisResult = Bash(`ccw cli -p '${diagnosisPrompt.replace(/'/g, "'\\''")}' --tool gemini --mode analysis --rule analysis-diagnose-bug-root-cause 2>&1 || echo "CLI diagnosis unavailable"`);
|
||||
|
||||
task.execution.skill_results.push({
|
||||
skill: `cli-diagnosis:${skillName}`,
|
||||
status: 'completed',
|
||||
diagnosis: diagnosisResult?.substring(0, 500),
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Step 2: Retry with diagnosis context
|
||||
console.log(` Retry with diagnosis: ${skillName}`);
|
||||
try {
|
||||
const retryResult = Skill({ skill: skillName, args: skillArgs });
|
||||
previousResult = retryResult;
|
||||
task.execution.skill_results.push({
|
||||
skill: skillName,
|
||||
status: 'completed-retry-with-diagnosis',
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
} catch (retryError) {
|
||||
// Step 3: Failed after CLI-assisted retry
|
||||
task.execution.skill_results.push({
|
||||
skill: skillName,
|
||||
status: 'failed',
|
||||
error: String(retryError).substring(0, 200),
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
if (autoYes) {
|
||||
taskFailed = true;
|
||||
break;
|
||||
} else {
|
||||
const answer = AskUserQuestion({
|
||||
questions: [{
|
||||
question: `${skillName} failed after CLI diagnosis + retry: ${String(retryError).substring(0, 100)}. How to proceed?`,
|
||||
header: 'Error',
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: 'Skip task', description: 'Mark task as failed, continue to next' },
|
||||
{ label: 'Abort', description: 'Stop entire run' }
|
||||
]
|
||||
}]
|
||||
});
|
||||
if (answer.answers?.Error === 'Abort') {
|
||||
task.status = 'failed';
|
||||
task.execution.error = String(retryError).substring(0, 200);
|
||||
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
||||
session.failed.push(task.id);
|
||||
session.status = 'failed';
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
return;
|
||||
}
|
||||
taskFailed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 5: Checkpoint (per task) — inline
|
||||
if (taskFailed) {
|
||||
task.status = 'failed';
|
||||
task.execution.error = 'Skill chain failed after retry';
|
||||
task.execution.completed_at = new Date().toISOString();
|
||||
session.failed.push(task.id);
|
||||
} else {
|
||||
// Git commit checkpoint
|
||||
const commitMsg = `feat(idaw): ${task.title} [${task.id}]`;
|
||||
const diffCheck = Bash('git diff --stat HEAD 2>/dev/null || echo ""');
|
||||
const untrackedCheck = Bash('git ls-files --others --exclude-standard 2>/dev/null || echo ""');
|
||||
|
||||
if (diffCheck?.trim() || untrackedCheck?.trim()) {
|
||||
Bash('git add -A');
|
||||
const commitResult = Bash(`git commit -m "$(cat <<'EOF'\n${commitMsg}\nEOF\n)"`);
|
||||
const commitHash = Bash('git rev-parse --short HEAD 2>/dev/null')?.trim();
|
||||
task.execution.git_commit = commitHash;
|
||||
} else {
|
||||
task.execution.git_commit = 'no-commit';
|
||||
}
|
||||
|
||||
task.status = 'completed';
|
||||
task.execution.completed_at = new Date().toISOString();
|
||||
session.completed.push(task.id);
|
||||
}
|
||||
|
||||
// Write task + session state
|
||||
task.updated_at = new Date().toISOString();
|
||||
Write(`.workflow/.idaw/tasks/${task.id}.json`, JSON.stringify(task, null, 2));
|
||||
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
// Append to progress.md
|
||||
const duration = task.execution.started_at && task.execution.completed_at
|
||||
? formatDuration(new Date(task.execution.completed_at) - new Date(task.execution.started_at))
|
||||
: 'unknown';
|
||||
|
||||
const progressEntry = `## ${task.id} — ${task.title}\n` +
|
||||
`- Status: ${task.status}\n` +
|
||||
`- Type: ${task.task_type}\n` +
|
||||
`- Chain: ${chain.join(' → ')}\n` +
|
||||
`- Commit: ${task.execution.git_commit || '-'}\n` +
|
||||
`- Duration: ${duration}\n\n`;
|
||||
|
||||
const currentProgress = Read(`${sessionDir}/progress.md`);
|
||||
Write(`${sessionDir}/progress.md`, currentProgress + progressEntry);
|
||||
|
||||
// Update TodoWrite
|
||||
if (taskIdx + 1 < tasks.length) {
|
||||
TodoWrite({
|
||||
todos: tasks.map((t, i) => ({
|
||||
content: `IDAW:[${i + 1}/${tasks.length}] ${t.title}`,
|
||||
status: i < taskIdx + 1 ? 'completed' : (i === taskIdx + 1 ? 'in_progress' : 'pending'),
|
||||
activeForm: `Executing ${t.title}`
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 6: Report
|
||||
|
||||
```javascript
|
||||
session.status = session.failed.length > 0 && session.completed.length === 0 ? 'failed' : 'completed';
|
||||
session.current_task = null;
|
||||
session.updated_at = new Date().toISOString();
|
||||
Write(`${sessionDir}/session.json`, JSON.stringify(session, null, 2));
|
||||
|
||||
// Final progress summary
|
||||
const summary = `\n---\n## Summary\n` +
|
||||
`- Completed: ${session.completed.length}\n` +
|
||||
`- Failed: ${session.failed.length}\n` +
|
||||
`- Skipped: ${session.skipped.length}\n` +
|
||||
`- Total: ${tasks.length}\n`;
|
||||
|
||||
const finalProgress = Read(`${sessionDir}/progress.md`);
|
||||
Write(`${sessionDir}/progress.md`, finalProgress + summary);
|
||||
|
||||
// Display report
|
||||
console.log('\n=== IDAW Run Complete ===');
|
||||
console.log(`Session: ${sessionId}`);
|
||||
console.log(`Completed: ${session.completed.length}/${tasks.length}`);
|
||||
if (session.failed.length > 0) console.log(`Failed: ${session.failed.join(', ')}`);
|
||||
if (session.skipped.length > 0) console.log(`Skipped: ${session.skipped.join(', ')}`);
|
||||
|
||||
// List git commits
|
||||
for (const taskId of session.completed) {
|
||||
const t = JSON.parse(Read(`.workflow/.idaw/tasks/${taskId}.json`));
|
||||
if (t.execution.git_commit && t.execution.git_commit !== 'no-commit') {
|
||||
console.log(` ${t.execution.git_commit} ${t.title}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Helper Functions
|
||||
|
||||
### assembleSkillArgs
|
||||
|
||||
```javascript
|
||||
function assembleSkillArgs(skillName, task, previousResult, autoYes, isFirst) {
|
||||
let args = '';
|
||||
|
||||
if (isFirst) {
|
||||
// First skill: pass task goal — sanitize for shell safety
|
||||
const goal = `${task.title}\n${task.description}`
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/\$/g, '\\$')
|
||||
.replace(/`/g, '\\`');
|
||||
args = `"${goal}"`;
|
||||
|
||||
// bugfix-hotfix: add --hotfix
|
||||
if (task.task_type === 'bugfix-hotfix') {
|
||||
args += ' --hotfix';
|
||||
}
|
||||
} else if (previousResult?.session_id) {
|
||||
// Subsequent skills: chain session
|
||||
args = `--session="${previousResult.session_id}"`;
|
||||
}
|
||||
|
||||
// Propagate -y
|
||||
if (autoYes && !args.includes('-y') && !args.includes('--yes')) {
|
||||
args = args ? `${args} -y` : '-y';
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
```
|
||||
|
||||
### formatDuration
|
||||
|
||||
```javascript
|
||||
function formatDuration(ms) {
|
||||
const seconds = Math.floor(ms / 1000);
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainingSeconds = seconds % 60;
|
||||
if (minutes > 0) return `${minutes}m ${remainingSeconds}s`;
|
||||
return `${seconds}s`;
|
||||
}
|
||||
```
|
||||
|
||||
## CLI-Assisted Analysis
|
||||
|
||||
IDAW integrates `ccw cli` (Gemini) for intelligent analysis at two key points:
|
||||
|
||||
### Pre-Task Context Analysis
|
||||
|
||||
For `bugfix`, `bugfix-hotfix`, and `feature-complex` tasks, IDAW automatically invokes CLI analysis **before** executing the skill chain to gather codebase context:
|
||||
|
||||
```
|
||||
Task starts → CLI pre-analysis (gemini) → Context gathered → Skill chain executes
|
||||
```
|
||||
|
||||
- Identifies dependencies and risk areas
|
||||
- Notes existing patterns to follow
|
||||
- Results stored in `task.execution.skill_results` as `cli-pre-analysis`
|
||||
|
||||
### Error Recovery with CLI Diagnosis
|
||||
|
||||
When a skill fails, instead of blind retry, IDAW uses CLI-assisted diagnosis:
|
||||
|
||||
```
|
||||
Skill fails → CLI diagnosis (gemini, analysis-diagnose-bug-root-cause)
|
||||
→ Root cause identified → Retry with diagnosis context
|
||||
→ Still fails → Skip (autoYes) or Ask user (interactive)
|
||||
```
|
||||
|
||||
- Uses `--rule analysis-diagnose-bug-root-cause` template
|
||||
- Diagnosis results stored in `task.execution.skill_results` as `cli-diagnosis:{skill}`
|
||||
- Follows CLAUDE.md auto-invoke trigger pattern: "self-repair fails → invoke CLI analysis"
|
||||
|
||||
### Execution Flow (with CLI analysis)
|
||||
|
||||
```
|
||||
Phase 4 Main Loop (per task):
|
||||
├─ [bugfix/complex only] CLI pre-analysis → context summary
|
||||
├─ Skill 1: execute
|
||||
│ ├─ Success → next skill
|
||||
│ └─ Failure → CLI diagnosis → retry → success/fail
|
||||
├─ Skill 2: execute ...
|
||||
└─ Phase 5: git checkpoint
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# Execute all pending tasks
|
||||
/idaw:run -y
|
||||
|
||||
# Execute specific tasks
|
||||
/idaw:run --task IDAW-001,IDAW-003
|
||||
|
||||
# Dry run (show plan without executing)
|
||||
/idaw:run --dry-run
|
||||
|
||||
# Interactive mode (confirm at each step)
|
||||
/idaw:run
|
||||
```
|
||||
@@ -1,182 +0,0 @@
|
||||
---
|
||||
name: status
|
||||
description: View IDAW task and session progress
|
||||
argument-hint: "[session-id]"
|
||||
allowed-tools: Read(*), Glob(*), Bash(*)
|
||||
---
|
||||
|
||||
# IDAW Status Command (/idaw:status)
|
||||
|
||||
## Overview
|
||||
|
||||
Read-only command to view IDAW task queue and execution session progress.
|
||||
|
||||
## Implementation
|
||||
|
||||
### Phase 1: Determine View Mode
|
||||
|
||||
```javascript
|
||||
const sessionId = $ARGUMENTS?.trim();
|
||||
|
||||
if (sessionId) {
|
||||
// Specific session view
|
||||
showSession(sessionId);
|
||||
} else {
|
||||
// Overview: pending tasks + latest session
|
||||
showOverview();
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 2: Show Overview
|
||||
|
||||
```javascript
|
||||
function showOverview() {
|
||||
// 1. Load all tasks
|
||||
const taskFiles = Glob('.workflow/.idaw/tasks/IDAW-*.json') || [];
|
||||
|
||||
if (taskFiles.length === 0) {
|
||||
console.log('No IDAW tasks found. Use /idaw:add to create tasks.');
|
||||
return;
|
||||
}
|
||||
|
||||
const tasks = taskFiles.map(f => JSON.parse(Read(f)));
|
||||
|
||||
// 2. Group by status
|
||||
const byStatus = {
|
||||
pending: tasks.filter(t => t.status === 'pending'),
|
||||
in_progress: tasks.filter(t => t.status === 'in_progress'),
|
||||
completed: tasks.filter(t => t.status === 'completed'),
|
||||
failed: tasks.filter(t => t.status === 'failed'),
|
||||
skipped: tasks.filter(t => t.status === 'skipped')
|
||||
};
|
||||
|
||||
// 3. Display task summary table
|
||||
console.log('# IDAW Tasks\n');
|
||||
console.log('| ID | Title | Type | Priority | Status |');
|
||||
console.log('|----|-------|------|----------|--------|');
|
||||
|
||||
// Sort: priority ASC, then ID ASC
|
||||
const sorted = [...tasks].sort((a, b) => {
|
||||
if (a.priority !== b.priority) return a.priority - b.priority;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
|
||||
for (const t of sorted) {
|
||||
const type = t.task_type || '(infer)';
|
||||
console.log(`| ${t.id} | ${t.title.substring(0, 40)} | ${type} | ${t.priority} | ${t.status} |`);
|
||||
}
|
||||
|
||||
console.log(`\nTotal: ${tasks.length} | Pending: ${byStatus.pending.length} | Completed: ${byStatus.completed.length} | Failed: ${byStatus.failed.length}`);
|
||||
|
||||
// 4. Show latest session (if any)
|
||||
const sessionDirs = Glob('.workflow/.idaw/sessions/IDA-*/session.json') || [];
|
||||
if (sessionDirs.length > 0) {
|
||||
// Sort by modification time (newest first) — Glob returns sorted by mtime
|
||||
const latestSessionFile = sessionDirs[0];
|
||||
const session = JSON.parse(Read(latestSessionFile));
|
||||
console.log(`\n## Latest Session: ${session.session_id}`);
|
||||
console.log(`Status: ${session.status} | Tasks: ${session.tasks?.length || 0}`);
|
||||
console.log(`Completed: ${session.completed?.length || 0} | Failed: ${session.failed?.length || 0} | Skipped: ${session.skipped?.length || 0}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: Show Specific Session
|
||||
|
||||
```javascript
|
||||
function showSession(sessionId) {
|
||||
const sessionFile = `.workflow/.idaw/sessions/${sessionId}/session.json`;
|
||||
const progressFile = `.workflow/.idaw/sessions/${sessionId}/progress.md`;
|
||||
|
||||
// Try reading session
|
||||
try {
|
||||
const session = JSON.parse(Read(sessionFile));
|
||||
|
||||
console.log(`# IDAW Session: ${session.session_id}\n`);
|
||||
console.log(`Status: ${session.status}`);
|
||||
console.log(`Created: ${session.created_at}`);
|
||||
console.log(`Updated: ${session.updated_at}`);
|
||||
console.log(`Current Task: ${session.current_task || 'none'}\n`);
|
||||
|
||||
// Task detail table
|
||||
console.log('| ID | Title | Status | Commit |');
|
||||
console.log('|----|-------|--------|--------|');
|
||||
|
||||
for (const taskId of session.tasks) {
|
||||
const taskFile = `.workflow/.idaw/tasks/${taskId}.json`;
|
||||
try {
|
||||
const task = JSON.parse(Read(taskFile));
|
||||
const commit = task.execution?.git_commit?.substring(0, 7) || '-';
|
||||
console.log(`| ${task.id} | ${task.title.substring(0, 40)} | ${task.status} | ${commit} |`);
|
||||
} catch {
|
||||
console.log(`| ${taskId} | (file not found) | unknown | - |`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nCompleted: ${session.completed?.length || 0} | Failed: ${session.failed?.length || 0} | Skipped: ${session.skipped?.length || 0}`);
|
||||
|
||||
// Show progress.md if exists
|
||||
try {
|
||||
const progress = Read(progressFile);
|
||||
console.log('\n---\n');
|
||||
console.log(progress);
|
||||
} catch {
|
||||
// No progress file yet
|
||||
}
|
||||
|
||||
} catch {
|
||||
// Session not found — try listing all sessions
|
||||
console.log(`Session "${sessionId}" not found.\n`);
|
||||
listSessions();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: List All Sessions
|
||||
|
||||
```javascript
|
||||
function listSessions() {
|
||||
const sessionFiles = Glob('.workflow/.idaw/sessions/IDA-*/session.json') || [];
|
||||
|
||||
if (sessionFiles.length === 0) {
|
||||
console.log('No IDAW sessions found. Use /idaw:run to start execution.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('# IDAW Sessions\n');
|
||||
console.log('| Session ID | Status | Tasks | Completed | Failed |');
|
||||
console.log('|------------|--------|-------|-----------|--------|');
|
||||
|
||||
for (const f of sessionFiles) {
|
||||
try {
|
||||
const session = JSON.parse(Read(f));
|
||||
console.log(`| ${session.session_id} | ${session.status} | ${session.tasks?.length || 0} | ${session.completed?.length || 0} | ${session.failed?.length || 0} |`);
|
||||
} catch {
|
||||
// Skip malformed
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\nUse /idaw:status <session-id> for details.');
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# Show overview (pending tasks + latest session)
|
||||
/idaw:status
|
||||
|
||||
# Show specific session details
|
||||
/idaw:status IDA-auth-fix-20260301
|
||||
|
||||
# Output example:
|
||||
# IDAW Tasks
|
||||
#
|
||||
# | ID | Title | Type | Priority | Status |
|
||||
# |----------|------------------------------------|--------|----------|-----------|
|
||||
# | IDAW-001 | Fix auth token refresh | bugfix | 1 | completed |
|
||||
# | IDAW-002 | Add rate limiting | feature| 2 | pending |
|
||||
# | IDAW-003 | Refactor payment module | refact | 3 | pending |
|
||||
#
|
||||
# Total: 3 | Pending: 2 | Completed: 1 | Failed: 0
|
||||
```
|
||||
811
.claude/commands/workflow-tune.md
Normal file
811
.claude/commands/workflow-tune.md
Normal file
@@ -0,0 +1,811 @@
|
||||
---
|
||||
name: workflow-tune
|
||||
description: Workflow tuning - extract commands from reference docs or natural language, execute each via ccw cli --tool claude --mode write, then analyze artifacts via gemini. For testing how commands execute in Claude.
|
||||
argument-hint: "<file-path> <intent> | \"step1 | step2 | step3\" | \"skill-a,skill-b\" | --file workflow.json [--depth quick|standard|deep] [-y|--yes] [--auto-fix]"
|
||||
allowed-tools: Agent(*), AskUserQuestion(*), TaskCreate(*), TaskUpdate(*), TaskList(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
|
||||
---
|
||||
|
||||
# Workflow Tune
|
||||
|
||||
测试 Claude command/skill 的执行效果并优化。提取可执行命令,逐步通过 `ccw cli --tool claude` 执行,分析产物质量,生成优化建议。
|
||||
|
||||
## Tool Assignment
|
||||
|
||||
| Phase | Tool | Mode | Rule |
|
||||
|-------|------|------|------|
|
||||
| Execute | `claude` | `write` | `universal-rigorous-style` |
|
||||
| Analyze | `gemini` | `analysis` | `analysis-review-code-quality` |
|
||||
| Synthesize | `gemini` | `analysis` | `analysis-review-architecture` |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Input → Parse → GenTestTask → Confirm → Setup → [resolveCmd → readMeta → assemblePrompt → Execute → STOP → Analyze → STOP]×N → Synthesize → STOP → Report
|
||||
↑ ↑
|
||||
Claude 直接生成测试任务 prompt 中注入 test_task
|
||||
(无需 CLI 调用) 作为命令的执行输入
|
||||
```
|
||||
|
||||
## Input Formats
|
||||
|
||||
```
|
||||
1. --file workflow.json → JSON definition
|
||||
2. "cmd1 | cmd2 | cmd3" → pipe-separated commands
|
||||
3. "skill-a,skill-b,skill-c" → comma-separated skills
|
||||
4. natural language → semantic decomposition
|
||||
4a: <file-path> <intent> → extract commands from reference doc via LLM
|
||||
4b: <pure intent text> → intent-verb matching → ccw cli command assembly
|
||||
```
|
||||
|
||||
**ANTI-PATTERN**: Steps like `{ command: "分析 Phase 管线" }` are WRONG — descriptions, not commands. Correct: `{ command: "/workflow-lite-plan analyze auth module" }` or `{ command: "ccw cli -p '...' --tool claude --mode write" }`
|
||||
|
||||
## Utility: Shell Escaping
|
||||
|
||||
```javascript
|
||||
function escapeForShell(str) {
|
||||
// Replace single quotes with escaped version, wrap in single quotes
|
||||
return "'" + str.replace(/'/g, "'\\''") + "'";
|
||||
}
|
||||
```
|
||||
|
||||
## Phase 1: Setup
|
||||
|
||||
### Step 1.1: Parse Input + Preference Collection
|
||||
|
||||
```javascript
|
||||
const args = $ARGUMENTS.trim();
|
||||
const autoYes = /\b(-y|--yes)\b/.test(args);
|
||||
|
||||
// Preference collection (skip if -y)
|
||||
if (autoYes) {
|
||||
workflowPreferences = { autoYes: true, analysisDepth: 'standard', autoFix: false };
|
||||
} else {
|
||||
const prefResponse = AskUserQuestion({
|
||||
questions: [
|
||||
{ question: "选择调优配置:", header: "Tune Config", multiSelect: false,
|
||||
options: [
|
||||
{ label: "Quick (轻量分析)", description: "每步简要检查" },
|
||||
{ label: "Standard (标准分析) (Recommended)", description: "每步详细分析" },
|
||||
{ label: "Deep (深度分析)", description: "深度审查含架构建议" }
|
||||
]
|
||||
},
|
||||
{ question: "是否自动应用优化建议?", header: "Auto Fix", multiSelect: false,
|
||||
options: [
|
||||
{ label: "No (仅报告) (Recommended)", description: "只分析不修改" },
|
||||
{ label: "Yes (自动应用)", description: "自动应用高优先级建议" }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
const depthMap = { "Quick": "quick", "Standard": "standard", "Deep": "deep" };
|
||||
const selectedDepth = Object.keys(depthMap).find(k => prefResponse["Tune Config"].startsWith(k)) || "Standard";
|
||||
workflowPreferences = {
|
||||
autoYes: false,
|
||||
analysisDepth: depthMap[selectedDepth],
|
||||
autoFix: prefResponse["Auto Fix"].startsWith("Yes")
|
||||
};
|
||||
}
|
||||
|
||||
// Parse --depth override
|
||||
const depthMatch = args.match(/--depth\s+(quick|standard|deep)/);
|
||||
if (depthMatch) workflowPreferences.analysisDepth = depthMatch[1];
|
||||
|
||||
// ── Format Detection ──
|
||||
let steps = [], workflowName = 'unnamed-workflow', inputFormat = '';
|
||||
let projectScenario = ''; // ★ 统一虚构项目场景,所有步骤共享(在 Step 1.1a 生成)
|
||||
|
||||
const fileMatch = args.match(/--file\s+"?([^\s"]+)"?/);
|
||||
if (fileMatch) {
|
||||
const wfDef = JSON.parse(Read(fileMatch[1]));
|
||||
workflowName = wfDef.name || 'unnamed-workflow';
|
||||
projectScenario = wfDef.project_scenario || wfDef.description || '';
|
||||
steps = wfDef.steps;
|
||||
inputFormat = 'json';
|
||||
}
|
||||
else if (args.includes('|')) {
|
||||
const rawSteps = args.split(/(?:--context|--depth|-y|--yes|--auto-fix)\s+("[^"]*"|\S+)/)[0];
|
||||
steps = rawSteps.split('|').map((cmd, i) => ({
|
||||
name: `step-${i + 1}`,
|
||||
command: cmd.trim(),
|
||||
expected_artifacts: [], success_criteria: ''
|
||||
}));
|
||||
inputFormat = 'pipe';
|
||||
}
|
||||
else if (/^[\w-]+(,[\w-]+)+/.test(args.split(/\s/)[0])) {
|
||||
const skillNames = args.match(/^([^\s]+)/)[1].split(',');
|
||||
steps = skillNames.map(name => ({
|
||||
name, command: `/${name}`,
|
||||
expected_artifacts: [], success_criteria: ''
|
||||
}));
|
||||
inputFormat = 'skills';
|
||||
}
|
||||
else {
|
||||
inputFormat = 'natural-language';
|
||||
let naturalLanguageInput = args.replace(/--\w+\s+"[^"]*"/g, '').replace(/--\w+\s+\S+/g, '').replace(/-y|--yes/g, '').trim();
|
||||
const filePathPattern = /(?:[A-Za-z]:[\\\/][^\s,;]+|\/[^\s,;]+\.(?:md|txt|json|yaml|yml|toml)|\.\/?[^\s,;]+\.(?:md|txt|json|yaml|yml|toml))/g;
|
||||
const detectedPaths = naturalLanguageInput.match(filePathPattern) || [];
|
||||
let referenceDocContent = null, referenceDocPath = null;
|
||||
if (detectedPaths.length > 0) {
|
||||
referenceDocPath = detectedPaths[0];
|
||||
try {
|
||||
referenceDocContent = Read(referenceDocPath);
|
||||
naturalLanguageInput = naturalLanguageInput.replace(referenceDocPath, '').trim();
|
||||
} catch (e) { referenceDocContent = null; }
|
||||
}
|
||||
// → Mode 4a/4b in Step 1.1b
|
||||
}
|
||||
|
||||
// workflowContext 已移除 — 统一使用 projectScenario(在 Step 1.1a 生成)
|
||||
```
|
||||
|
||||
### Step 1.1a: Generate Test Task (测试任务直接生成)
|
||||
|
||||
> **核心概念**: 所有步骤共享一个**统一虚构项目场景**(如"在线书店网站"),每个命令根据自身能力获得该场景下的一个子任务。由当前 Claude 直接生成,不需要额外 CLI 调用。所有执行在独立沙箱目录中进行,不影响真实项目。
|
||||
|
||||
```javascript
|
||||
// ★ 测试任务直接生成 — 无需 CLI 调用
|
||||
// 来源优先级:
|
||||
// 1. JSON 定义中的 step.test_task 字段 (已有则跳过)
|
||||
// 2. 当前 Claude 直接生成
|
||||
|
||||
const stepsNeedTask = steps.filter(s => !s.test_task);
|
||||
|
||||
if (stepsNeedTask.length > 0) {
|
||||
// ── Step A: 生成统一项目场景 ──
|
||||
// 根据命令链的整体复杂度,选一个虚构项目作为测试场景
|
||||
// 场景必须:完全虚构、与当前工作空间无关、足够支撑所有步骤
|
||||
//
|
||||
// 场景池示例(根据步骤数量和类型选择合适规模):
|
||||
// 1-2 步: 小型项目 — "命令行 TODO 工具" "Markdown 转 HTML 工具" "天气查询 CLI"
|
||||
// 3-4 步: 中型项目 — "在线书店网站" "团队任务看板" "博客系统"
|
||||
// 5+ 步: 大型项目 — "多租户 SaaS 平台" "电商系统" "在线教育平台"
|
||||
|
||||
projectScenario = /* Claude 从上述池中选择或自创一个场景 */;
|
||||
// 例如: "在线书店网站 — 支持用户注册登录、书籍搜索浏览、购物车、订单管理、评论系统"
|
||||
|
||||
// ── Step B: 为每步生成子任务 ──
|
||||
for (const step of stepsNeedTask) {
|
||||
const cmdFile = resolveCommandFile(step.command);
|
||||
const cmdMeta = readCommandMeta(cmdFile);
|
||||
const cmdDesc = (cmdMeta?.description || step.command).toLowerCase();
|
||||
|
||||
// 根据命令类型分配场景下的子任务
|
||||
// 每个子任务必须按以下模板生成:
|
||||
//
|
||||
// ┌─────────────────────────────────────────────────┐
|
||||
// │ 项目: {projectScenario} │
|
||||
// │ 任务: {具体子任务描述} │
|
||||
// │ 功能点: │
|
||||
// │ 1. {功能点1 — 具体到接口/组件/模块} │
|
||||
// │ 2. {功能点2} │
|
||||
// │ 3. {功能点3} │
|
||||
// │ 技术约束: {语言/框架/架构要求} │
|
||||
// │ 验收标准: │
|
||||
// │ 1. {可验证的标准1} │
|
||||
// │ 2. {可验证的标准2} │
|
||||
// └─────────────────────────────────────────────────┘
|
||||
//
|
||||
// 命令类型 → 子任务映射:
|
||||
// plan/design → 架构设计任务: "为{场景}设计技术架构,包含模块划分、数据模型、API 设计"
|
||||
// implement → 功能实现任务: "实现{场景}的{某模块},包含{具体功能点}"
|
||||
// analyze/review→ 代码分析任务: "先在沙箱创建{场景}的{某模块}示例代码,然后分析其质量"
|
||||
// test → 测试任务: "为{场景}的{某模块}编写测试,覆盖{具体场景}"
|
||||
// fix/debug → 修复任务: "先在沙箱创建含已知 bug 的代码,然后诊断修复"
|
||||
// refactor → 重构任务: "先在沙箱创建可工作但需重构的代码,然后重构"
|
||||
|
||||
step.test_task = /* 按上述模板生成,必须包含:项目、任务、功能点、技术约束、验收标准 */;
|
||||
step.acceptance_criteria = /* 从 test_task 中提取 2-4 条可验证标准 */;
|
||||
step.complexity_level = /plan|design|architect/i.test(cmdDesc) ? 'high'
|
||||
: /test|lint|format/i.test(cmdDesc) ? 'low' : 'medium';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**模拟示例** — 输入 `workflow-lite-plan,workflow-lite-execute`:
|
||||
|
||||
```
|
||||
场景: 在线书店网站 — 支持用户注册登录、书籍搜索、购物车、订单管理
|
||||
|
||||
Step 1 (workflow-lite-plan → plan 类, high):
|
||||
项目: 在线书店网站
|
||||
任务: 为在线书店设计技术架构和实现计划
|
||||
功能点:
|
||||
1. 用户模块 — 注册、登录、个人信息管理
|
||||
2. 书籍模块 — 搜索、分类浏览、详情页
|
||||
3. 交易模块 — 购物车、下单、支付状态
|
||||
4. 数据模型 — User, Book, Order, CartItem 表结构设计
|
||||
技术约束: TypeScript + Express + SQLite, REST API
|
||||
验收标准:
|
||||
1. 输出包含模块划分和依赖关系
|
||||
2. 包含数据模型定义
|
||||
3. 包含 API 路由清单
|
||||
4. 包含实现步骤分解
|
||||
|
||||
Step 2 (workflow-lite-execute → implement 类, medium):
|
||||
项目: 在线书店网站
|
||||
任务: 根据 Step 1 的计划,实现书籍搜索和浏览模块
|
||||
功能点:
|
||||
1. GET /api/books — 分页列表,支持按标题/作者搜索
|
||||
2. GET /api/books/:id — 书籍详情
|
||||
3. GET /api/categories — 分类列表
|
||||
4. Book 数据模型 + seed 数据
|
||||
技术约束: TypeScript + Express + SQLite, 沿用 Step 1 架构
|
||||
验收标准:
|
||||
1. API 可正常调用返回 JSON
|
||||
2. 搜索支持模糊匹配
|
||||
3. 包含至少 5 条 seed 数据
|
||||
```
|
||||
|
||||
### Step 1.1b: Semantic Decomposition (Format 4 only)
|
||||
|
||||
#### Mode 4a: Reference Document → LLM Extraction
|
||||
|
||||
```javascript
|
||||
if (inputFormat === 'natural-language' && referenceDocContent) {
|
||||
const extractPrompt = `PURPOSE: Extract ACTUAL EXECUTABLE COMMANDS from the reference document. The user wants to TEST these commands by running them.
|
||||
|
||||
USER INTENT: ${naturalLanguageInput}
|
||||
REFERENCE DOCUMENT: ${referenceDocPath}
|
||||
|
||||
DOCUMENT CONTENT:
|
||||
${referenceDocContent}
|
||||
|
||||
CRITICAL RULES:
|
||||
- "command" field MUST be a real executable: slash command (/skill-name args), ccw cli call, or shell command
|
||||
- CORRECT: { "command": "/workflow-lite-plan analyze auth module" }
|
||||
- CORRECT: { "command": "ccw cli -p 'review code' --tool claude --mode write" }
|
||||
- WRONG: { "command": "分析 Phase 管线" } ← DESCRIPTION, not command
|
||||
- Default mode to "write"
|
||||
|
||||
EXPECTED OUTPUT (strict JSON):
|
||||
{
|
||||
"workflow_name": "<name>",
|
||||
"project_scenario": "<虚构项目场景>",
|
||||
"steps": [{ "name": "", "command": "<executable>", "expected_artifacts": [], "success_criteria": "" }]
|
||||
}`;
|
||||
|
||||
Bash({
|
||||
command: `ccw cli -p ${escapeForShell(extractPrompt)} --tool claude --mode write --rule universal-rigorous-style`,
|
||||
run_in_background: true, timeout: 300000
|
||||
});
|
||||
// ■ STOP — wait for hook callback, parse JSON → steps[]
|
||||
}
|
||||
```
|
||||
|
||||
#### Mode 4b: Pure Intent → Command Assembly
|
||||
|
||||
```javascript
|
||||
if (inputFormat === 'natural-language' && !referenceDocContent) {
|
||||
// Intent → rule mapping for ccw cli command generation
|
||||
const intentMap = [
|
||||
{ pattern: /分析|analyze|审查|inspect|scan/i, name: 'analyze', rule: 'analysis-analyze-code-patterns' },
|
||||
{ pattern: /评审|review|code.?review/i, name: 'review', rule: 'analysis-review-code-quality' },
|
||||
{ pattern: /诊断|debug|排查|diagnose/i, name: 'diagnose', rule: 'analysis-diagnose-bug-root-cause' },
|
||||
{ pattern: /安全|security|漏洞/i, name: 'security-audit', rule: 'analysis-assess-security-risks' },
|
||||
{ pattern: /性能|performance|perf/i, name: 'perf-analysis', rule: 'analysis-analyze-performance' },
|
||||
{ pattern: /架构|architecture/i, name: 'arch-review', rule: 'analysis-review-architecture' },
|
||||
{ pattern: /修复|fix|repair|解决/i, name: 'fix', rule: 'development-debug-runtime-issues' },
|
||||
{ pattern: /实现|implement|开发|create|新增/i, name: 'implement', rule: 'development-implement-feature' },
|
||||
{ pattern: /重构|refactor/i, name: 'refactor', rule: 'development-refactor-codebase' },
|
||||
{ pattern: /测试|test/i, name: 'test', rule: 'development-generate-tests' },
|
||||
{ pattern: /规划|plan|设计|design/i, name: 'plan', rule: 'planning-plan-architecture-design' },
|
||||
];
|
||||
|
||||
const segments = naturalLanguageInput
|
||||
.split(/[,,;;、]|(?:然后|接着|之后|最后|再|并|and then|then|finally|next)\s*/i)
|
||||
.map(s => s.trim()).filter(Boolean);
|
||||
|
||||
// ★ 将意图文本转化为完整的 ccw cli 命令
|
||||
steps = segments.map((segment, i) => {
|
||||
const matched = intentMap.find(m => m.pattern.test(segment));
|
||||
const rule = matched?.rule || 'universal-rigorous-style';
|
||||
// 组装真正可执行的命令
|
||||
const command = `ccw cli -p ${escapeForShell('PURPOSE: ' + segment + '\\nTASK: Execute based on intent\\nCONTEXT: @**/*')} --tool claude --mode write --rule ${rule}`;
|
||||
return {
|
||||
name: matched?.name || `step-${i + 1}`,
|
||||
command,
|
||||
original_intent: segment, // 保留原始意图用于分析
|
||||
expected_artifacts: [], success_criteria: ''
|
||||
};
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Step 1.1c: Execution Plan Confirmation
|
||||
|
||||
```javascript
|
||||
function generateCommandDoc(steps, workflowName, projectScenario, analysisDepth) {
|
||||
const stepTable = steps.map((s, i) => {
|
||||
const cmdPreview = s.command.length > 60 ? s.command.substring(0, 57) + '...' : s.command;
|
||||
const taskPreview = (s.test_task || '-').length > 40 ? s.test_task.substring(0, 37) + '...' : (s.test_task || '-');
|
||||
return `| ${i + 1} | ${s.name} | \`${cmdPreview}\` | ${taskPreview} |`;
|
||||
}).join('\n');
|
||||
|
||||
return `# Workflow Tune — Execution Plan\n\n**Workflow**: ${workflowName}\n**Test Project**: ${projectScenario}\n**Steps**: ${steps.length}\n**Depth**: ${analysisDepth}\n\n| # | Name | Command | Test Task |\n|---|------|---------|-----------|\n${stepTable}`;
|
||||
}
|
||||
|
||||
const commandDoc = generateCommandDoc(steps, workflowName, projectScenario, workflowPreferences.analysisDepth);
|
||||
|
||||
if (!workflowPreferences.autoYes) {
|
||||
const confirmation = AskUserQuestion({
|
||||
questions: [{
|
||||
question: commandDoc + "\n\n确认执行以上 Workflow 调优计划?", header: "Confirm Execution", multiSelect: false,
|
||||
options: [
|
||||
{ label: "Execute (确认执行)", description: "按计划开始执行" },
|
||||
{ label: "Cancel (取消)", description: "取消" }
|
||||
]
|
||||
}]
|
||||
});
|
||||
if (confirmation["Confirm Execution"].startsWith("Cancel")) return;
|
||||
}
|
||||
```
|
||||
|
||||
### Step 1.2: (Merged into Step 1.1a)
|
||||
|
||||
> Test requirements (acceptance_criteria) are now generated together with test_task in Step 1.1a, avoiding an extra CLI call.
|
||||
|
||||
### Step 1.3: Create Workspace + Sandbox Project
|
||||
|
||||
```javascript
|
||||
const ts = Date.now();
|
||||
const workDir = `.workflow/.scratchpad/workflow-tune-${ts}`;
|
||||
|
||||
// ★ 创建独立沙箱项目目录 — 所有命令执行在此目录中,不影响真实项目
|
||||
const sandboxDir = `${workDir}/sandbox`;
|
||||
Bash(`mkdir -p "${workDir}/steps" "${sandboxDir}"`);
|
||||
// 初始化沙箱为独立 git 仓库(部分命令依赖 git 环境)
|
||||
Bash(`cd "${sandboxDir}" && git init && echo "# Sandbox Project" > README.md && git add . && git commit -m "init sandbox"`);
|
||||
|
||||
for (let i = 0; i < steps.length; i++) Bash(`mkdir -p "${workDir}/steps/step-${i + 1}/artifacts"`);
|
||||
|
||||
Write(`${workDir}/command-doc.md`, commandDoc);
|
||||
|
||||
const initialState = {
|
||||
status: 'running', started_at: new Date().toISOString(),
|
||||
workflow_name: workflowName, project_scenario: projectScenario,
|
||||
analysis_depth: workflowPreferences.analysisDepth, auto_fix: workflowPreferences.autoFix,
|
||||
sandbox_dir: sandboxDir, // ★ 独立沙箱项目目录
|
||||
current_step: 0, // ★ State machine cursor
|
||||
current_phase: 'execute', // 'execute' | 'analyze'
|
||||
steps: steps.map((s, i) => ({
|
||||
...s, index: i, status: 'pending',
|
||||
test_task: s.test_task || '', // ★ 每步的测试任务
|
||||
execution: null, analysis: null,
|
||||
test_requirements: s.test_requirements || null
|
||||
})),
|
||||
gemini_session_id: null, // ★ Updated after each gemini callback
|
||||
work_dir: workDir,
|
||||
errors: [], error_count: 0, max_errors: 3
|
||||
};
|
||||
|
||||
Write(`${workDir}/workflow-state.json`, JSON.stringify(initialState, null, 2));
|
||||
Write(`${workDir}/process-log.md`, `# Process Log\n\n**Workflow**: ${workflowName}\n**Test Project**: ${projectScenario}\n**Steps**: ${steps.length}\n**Started**: ${new Date().toISOString()}\n\n---\n\n`);
|
||||
```
|
||||
|
||||
## Phase 2: Execute Step
|
||||
|
||||
### resolveCommandFile — Slash command → file path
|
||||
|
||||
```javascript
|
||||
function resolveCommandFile(command) {
|
||||
const cmdMatch = command.match(/^\/?([^\s]+)/);
|
||||
if (!cmdMatch) return null;
|
||||
const cmdName = cmdMatch[1];
|
||||
const cmdPath = cmdName.replace(/:/g, '/');
|
||||
|
||||
const searchRoots = ['.claude', '~/.claude'];
|
||||
|
||||
for (const root of searchRoots) {
|
||||
const candidates = [
|
||||
`${root}/commands/${cmdPath}.md`,
|
||||
`${root}/commands/${cmdPath}/index.md`,
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
try { Read(candidate, { limit: 1 }); return candidate; } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
for (const root of searchRoots) {
|
||||
const candidates = [
|
||||
`${root}/skills/${cmdName}/SKILL.md`,
|
||||
`${root}/skills/${cmdPath.replace(/\//g, '-')}/SKILL.md`,
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
try { Read(candidate, { limit: 1 }); return candidate; } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
### readCommandMeta — Read YAML frontmatter + body summary
|
||||
|
||||
```javascript
|
||||
function readCommandMeta(filePath) {
|
||||
if (!filePath) return null;
|
||||
|
||||
const content = Read(filePath);
|
||||
const meta = { filePath, name: '', description: '', argumentHint: '', allowedTools: '', bodySummary: '' };
|
||||
|
||||
const yamlMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
||||
if (yamlMatch) {
|
||||
const yaml = yamlMatch[1];
|
||||
const nameMatch = yaml.match(/^name:\s*(.+)$/m);
|
||||
const descMatch = yaml.match(/^description:\s*(.+)$/m);
|
||||
const hintMatch = yaml.match(/^argument-hint:\s*"?(.+?)"?\s*$/m);
|
||||
const toolsMatch = yaml.match(/^allowed-tools:\s*(.+)$/m);
|
||||
|
||||
if (nameMatch) meta.name = nameMatch[1].trim();
|
||||
if (descMatch) meta.description = descMatch[1].trim();
|
||||
if (hintMatch) meta.argumentHint = hintMatch[1].trim();
|
||||
if (toolsMatch) meta.allowedTools = toolsMatch[1].trim();
|
||||
}
|
||||
|
||||
const bodyStart = content.indexOf('---', content.indexOf('---') + 3);
|
||||
if (bodyStart !== -1) {
|
||||
const body = content.substring(bodyStart + 3).trim();
|
||||
meta.bodySummary = body.split('\n').slice(0, 30).join('\n');
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
```
|
||||
|
||||
### assembleStepPrompt — Build execution prompt from command metadata
|
||||
|
||||
```javascript
|
||||
function assembleStepPrompt(step, stepIdx, state) {
|
||||
// ── 1. Resolve command file + metadata ──
|
||||
const isSlashCmd = step.command.startsWith('/');
|
||||
const cmdFile = isSlashCmd ? resolveCommandFile(step.command) : null;
|
||||
const cmdMeta = readCommandMeta(cmdFile);
|
||||
const cmdArgs = isSlashCmd ? step.command.replace(/^\/?[^\s]+\s*/, '').trim() : '';
|
||||
|
||||
// ── 2. Prior/next step context ──
|
||||
const prevStep = stepIdx > 0 ? state.steps[stepIdx - 1] : null;
|
||||
const nextStep = stepIdx < state.steps.length - 1 ? state.steps[stepIdx + 1] : null;
|
||||
|
||||
const priorContext = prevStep
|
||||
? `PRIOR STEP: "${prevStep.name}" — ${prevStep.command}\n Status: ${prevStep.status} | Artifacts: ${prevStep.execution?.artifact_count || 0}`
|
||||
: 'PRIOR STEP: None (first step)';
|
||||
|
||||
const nextContext = nextStep
|
||||
? `NEXT STEP: "${nextStep.name}" — ${nextStep.command}\n Ensure output is consumable by next step`
|
||||
: 'NEXT STEP: None (last step)';
|
||||
|
||||
// ── 3. Acceptance criteria (from test_task generation) ──
|
||||
const criteria = step.acceptance_criteria || [];
|
||||
const testReqSection = criteria.length > 0
|
||||
? `ACCEPTANCE CRITERIA:\n${criteria.map((c, i) => ` ${i + 1}. ${c}`).join('\n')}`
|
||||
: '';
|
||||
|
||||
// ── 4. Test task — the concrete scenario to drive execution ──
|
||||
const testTask = step.test_task || '';
|
||||
const testTaskSection = testTask
|
||||
? `TEST TASK (用此任务驱动命令执行):\n ${testTask}`
|
||||
: '';
|
||||
|
||||
// ── 5. Build prompt based on whether command has metadata ──
|
||||
if (cmdMeta) {
|
||||
// Slash command with resolved file — rich context prompt
|
||||
return `PURPOSE: Execute workflow step "${step.name}" (${stepIdx + 1}/${state.steps.length}).
|
||||
|
||||
COMMAND DEFINITION:
|
||||
Name: ${cmdMeta.name}
|
||||
Description: ${cmdMeta.description}
|
||||
Argument Format: ${cmdMeta.argumentHint || 'none'}
|
||||
Allowed Tools: ${cmdMeta.allowedTools || 'default'}
|
||||
Source: ${cmdMeta.filePath}
|
||||
|
||||
COMMAND TO EXECUTE: ${step.command}
|
||||
ARGUMENTS: ${cmdArgs || '(no arguments)'}
|
||||
|
||||
${testTaskSection}
|
||||
|
||||
COMMAND REFERENCE (first 30 lines):
|
||||
${cmdMeta.bodySummary}
|
||||
|
||||
PROJECT: ${state.project_scenario}
|
||||
SANDBOX PROJECT: ${state.sandbox_dir}
|
||||
OUTPUT DIR: ${state.work_dir}/steps/step-${stepIdx + 1}
|
||||
|
||||
${priorContext}
|
||||
${nextContext}
|
||||
${testReqSection}
|
||||
|
||||
TASK: Execute the command as described in COMMAND DEFINITION, using TEST TASK as the input/scenario. Use the COMMAND REFERENCE to understand expected behavior. All work happens in the SANDBOX PROJECT directory (an isolated empty project, NOT the real workspace). Auto-confirm all prompts.
|
||||
CONSTRAINTS: Stay scoped to this step only. Follow the command's own execution flow. The TEST TASK is the real work — treat it as the $ARGUMENTS input to the command. Do NOT read/modify files outside SANDBOX PROJECT.`;
|
||||
|
||||
} else {
|
||||
// Shell command, ccw cli command, or unresolved command
|
||||
return `PURPOSE: Execute workflow step "${step.name}" (${stepIdx + 1}/${state.steps.length}).
|
||||
COMMAND: ${step.command}
|
||||
${testTaskSection}
|
||||
PROJECT: ${state.project_scenario}
|
||||
SANDBOX PROJECT: ${state.sandbox_dir}
|
||||
OUTPUT DIR: ${state.work_dir}/steps/step-${stepIdx + 1}
|
||||
|
||||
${priorContext}
|
||||
${nextContext}
|
||||
${testReqSection}
|
||||
|
||||
TASK: Execute the COMMAND above with TEST TASK as the input scenario. All work happens in the SANDBOX PROJECT directory (an isolated empty project). Auto-confirm all prompts.
|
||||
CONSTRAINTS: Stay scoped to this step only. The TEST TASK is the real work to execute. Do NOT read/modify files outside SANDBOX PROJECT.`;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step Execution
|
||||
|
||||
```javascript
|
||||
const stepIdx = state.current_step;
|
||||
const step = state.steps[stepIdx];
|
||||
const stepDir = `${state.work_dir}/steps/step-${stepIdx + 1}`;
|
||||
|
||||
// Pre-execution: snapshot sandbox directory files
|
||||
const preFiles = Bash(`find "${state.sandbox_dir}" -type f 2>/dev/null | sort`).stdout.trim();
|
||||
Write(`${stepDir}/pre-exec-snapshot.txt`, preFiles || '(empty)');
|
||||
|
||||
const startTime = Date.now();
|
||||
const prompt = assembleStepPrompt(step, stepIdx, state);
|
||||
|
||||
// ★ All steps execute via ccw cli --tool claude --mode write
|
||||
// ★ --cd 指向沙箱目录(独立项目),不影响真实工作空间
|
||||
Bash({
|
||||
command: `ccw cli -p ${escapeForShell(prompt)} --tool claude --mode write --rule universal-rigorous-style --cd "${state.sandbox_dir}"`,
|
||||
run_in_background: true, timeout: 600000
|
||||
});
|
||||
// ■ STOP — wait for hook callback
|
||||
```
|
||||
|
||||
### Post-Execute Callback Handler
|
||||
|
||||
```javascript
|
||||
// ★ This runs after receiving the ccw cli callback
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
// Collect artifacts by scanning sandbox (not git diff — sandbox is an independent project)
|
||||
const postFiles = Bash(`find "${state.sandbox_dir}" -type f -newer "${stepDir}/pre-exec-snapshot.txt" 2>/dev/null | sort`).stdout.trim();
|
||||
const newArtifacts = postFiles ? postFiles.split('\n').filter(f => !f.endsWith('.git/')) : [];
|
||||
|
||||
const artifactManifest = {
|
||||
step: step.name, step_index: stepIdx,
|
||||
success: true, duration_ms: duration,
|
||||
artifacts: newArtifacts.map(f => ({
|
||||
path: f,
|
||||
type: f.endsWith('.md') ? 'markdown' : f.endsWith('.json') ? 'json' : 'other'
|
||||
})),
|
||||
collected_at: new Date().toISOString()
|
||||
};
|
||||
Write(`${stepDir}/artifacts-manifest.json`, JSON.stringify(artifactManifest, null, 2));
|
||||
|
||||
// Update state
|
||||
state.steps[stepIdx].status = 'executed';
|
||||
state.steps[stepIdx].execution = {
|
||||
success: true, duration_ms: duration,
|
||||
artifact_count: newArtifacts.length
|
||||
};
|
||||
state.current_phase = 'analyze';
|
||||
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
|
||||
|
||||
// → Proceed to Phase 3 for this step
|
||||
```
|
||||
|
||||
## Phase 3: Analyze Step (per step, via gemini)
|
||||
|
||||
```javascript
|
||||
const manifest = JSON.parse(Read(`${stepDir}/artifacts-manifest.json`));
|
||||
|
||||
// Build artifact content for analysis
|
||||
let artifactSummary = '';
|
||||
if (state.analysis_depth === 'quick') {
|
||||
artifactSummary = manifest.artifacts.map(a => `- ${a.path} (${a.type})`).join('\n');
|
||||
} else {
|
||||
const maxLines = state.analysis_depth === 'deep' ? 300 : 150;
|
||||
artifactSummary = manifest.artifacts.map(a => {
|
||||
try { return `--- ${a.path} ---\n${Read(a.path, { limit: maxLines })}`; }
|
||||
catch { return `--- ${a.path} --- [unreadable]`; }
|
||||
}).join('\n\n');
|
||||
}
|
||||
|
||||
const criteria = step.acceptance_criteria || [];
|
||||
const testTaskDesc = step.test_task ? `TEST TASK: ${step.test_task}` : '';
|
||||
const criteriaSection = criteria.length > 0
|
||||
? `ACCEPTANCE CRITERIA:\n${criteria.map((c, i) => ` ${i + 1}. ${c}`).join('\n')}`
|
||||
: '';
|
||||
|
||||
const analysisPrompt = `PURPOSE: Evaluate execution quality of step "${step.name}" (${stepIdx + 1}/${state.steps.length}).
|
||||
WORKFLOW: ${state.workflow_name} — ${state.project_scenario}
|
||||
COMMAND: ${step.command}
|
||||
${testTaskDesc}
|
||||
${criteriaSection}
|
||||
EXECUTION: Duration ${step.execution.duration_ms}ms | Artifacts: ${manifest.artifacts.length}
|
||||
ARTIFACTS:\n${artifactSummary}
|
||||
EXPECTED OUTPUT (strict JSON):
|
||||
{ "quality_score": <0-100>, "requirement_match": { "pass": <bool>, "criteria_met": [], "criteria_missed": [], "fail_signals_detected": [] }, "execution_assessment": { "success": <bool>, "completeness": "", "notes": "" }, "artifact_assessment": { "count": <n>, "quality": "", "key_outputs": [], "missing_outputs": [] }, "issues": [{ "severity": "critical|high|medium|low", "description": "", "suggestion": "" }], "optimization_opportunities": [{ "area": "", "description": "", "impact": "high|medium|low" }], "step_summary": "" }`;
|
||||
|
||||
let cliCommand = `ccw cli -p ${escapeForShell(analysisPrompt)} --tool gemini --mode analysis --rule analysis-review-code-quality`;
|
||||
if (state.gemini_session_id) cliCommand += ` --resume ${state.gemini_session_id}`;
|
||||
Bash({ command: cliCommand, run_in_background: true, timeout: 300000 });
|
||||
// ■ STOP — wait for hook callback
|
||||
```
|
||||
|
||||
### Post-Analyze Callback Handler
|
||||
|
||||
```javascript
|
||||
// ★ Parse analysis result JSON from callback
|
||||
const analysisResult = /* parsed from callback output */;
|
||||
|
||||
// ★ Capture gemini session ID for resume chain
|
||||
// Session ID is in stderr: [CCW_EXEC_ID=gem-xxxxxx-xxxx]
|
||||
state.gemini_session_id = /* captured from callback exec_id */;
|
||||
|
||||
Write(`${stepDir}/step-${stepIdx + 1}-analysis.json`, JSON.stringify(analysisResult, null, 2));
|
||||
|
||||
// Update state
|
||||
state.steps[stepIdx].analysis = {
|
||||
quality_score: analysisResult.quality_score,
|
||||
requirement_pass: analysisResult.requirement_match?.pass,
|
||||
issue_count: (analysisResult.issues || []).length
|
||||
};
|
||||
state.steps[stepIdx].status = 'completed';
|
||||
|
||||
// Append to process log
|
||||
const logEntry = `## Step ${stepIdx + 1}: ${step.name}\n- Score: ${analysisResult.quality_score}/100\n- Req: ${analysisResult.requirement_match?.pass ? 'PASS' : 'FAIL'}\n- Issues: ${(analysisResult.issues || []).length}\n- Summary: ${analysisResult.step_summary}\n\n`;
|
||||
Edit(`${state.work_dir}/process-log.md`, /* append logEntry */);
|
||||
|
||||
// ★ Advance state machine
|
||||
state.current_step = stepIdx + 1;
|
||||
state.current_phase = 'execute';
|
||||
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
|
||||
|
||||
// ★ Decision: advance or synthesize
|
||||
if (state.current_step < state.steps.length) {
|
||||
// → Back to Phase 2 for next step
|
||||
} else {
|
||||
// → Phase 4: Synthesize
|
||||
}
|
||||
```
|
||||
|
||||
## Step Loop — State Machine
|
||||
|
||||
```
|
||||
NOT a sync for-loop. Each step follows this state machine:
|
||||
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ state.current_step = N, state.current_phase = X │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ phase='execute' → Phase 2 → ccw cli claude → STOP │
|
||||
│ callback → collect artifacts → phase='analyze' │
|
||||
│ phase='analyze' → Phase 3 → ccw cli gemini → STOP │
|
||||
│ callback → save analysis → current_step++ │
|
||||
│ if current_step < total → phase='execute' (loop) │
|
||||
│ else → Phase 4 (synthesize) │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
|
||||
Error handling:
|
||||
- Execute timeout → retry once, then mark failed, advance
|
||||
- Analyze failure → retry without --resume, then skip analysis
|
||||
- 3+ consecutive errors → terminate, jump to Phase 5 partial report
|
||||
```
|
||||
|
||||
## Phase 4: Synthesize (via gemini)
|
||||
|
||||
```javascript
|
||||
const stepAnalyses = state.steps.map((step, i) => {
|
||||
try { return { step: step.name, content: Read(`${state.work_dir}/steps/step-${i + 1}/step-${i + 1}-analysis.json`) }; }
|
||||
catch { return { step: step.name, content: '[Not available]' }; }
|
||||
});
|
||||
|
||||
const scores = state.steps.map(s => s.analysis?.quality_score).filter(Boolean);
|
||||
const avgScore = scores.length > 0 ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) : 0;
|
||||
|
||||
const synthesisPrompt = `PURPOSE: Synthesize all step analyses into holistic workflow assessment with actionable optimization plan.
|
||||
WORKFLOW: ${state.workflow_name} — ${state.project_scenario}
|
||||
Steps: ${state.steps.length} | Avg Quality: ${avgScore}/100
|
||||
STEP ANALYSES:\n${stepAnalyses.map(a => `### ${a.step}\n${a.content}`).join('\n\n---\n\n')}
|
||||
Evaluate: coherence across steps, handoff quality, redundancy, bottlenecks.
|
||||
EXPECTED OUTPUT (strict JSON):
|
||||
{ "workflow_score": <0-100>, "coherence": { "score": <0-100>, "assessment": "", "gaps": [] }, "bottlenecks": [{ "step": "", "issue": "", "suggestion": "" }], "per_step_improvements": [{ "step": "", "priority": "high|medium|low", "action": "" }], "workflow_improvements": [{ "area": "", "description": "", "impact": "high|medium|low" }], "summary": "" }`;
|
||||
|
||||
let cliCommand = `ccw cli -p ${escapeForShell(synthesisPrompt)} --tool gemini --mode analysis --rule analysis-review-architecture`;
|
||||
if (state.gemini_session_id) cliCommand += ` --resume ${state.gemini_session_id}`;
|
||||
Bash({ command: cliCommand, run_in_background: true, timeout: 300000 });
|
||||
// ■ STOP — wait for hook callback → parse JSON, write synthesis.json, update state
|
||||
```
|
||||
|
||||
## Phase 5: Report
|
||||
|
||||
```javascript
|
||||
const synthesis = JSON.parse(Read(`${state.work_dir}/synthesis.json`));
|
||||
const scores = state.steps.map(s => s.analysis?.quality_score).filter(Boolean);
|
||||
const avgScore = scores.length > 0 ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) : 0;
|
||||
const totalIssues = state.steps.reduce((sum, s) => sum + (s.analysis?.issue_count || 0), 0);
|
||||
|
||||
const stepTable = state.steps.map((s, i) => {
|
||||
const reqStr = s.analysis?.requirement_pass === true ? 'PASS' : s.analysis?.requirement_pass === false ? 'FAIL' : '-';
|
||||
return `| ${i + 1} | ${s.name} | ${s.execution?.success ? 'OK' : 'FAIL'} | ${reqStr} | ${s.analysis?.quality_score || '-'} | ${s.analysis?.issue_count || 0} |`;
|
||||
}).join('\n');
|
||||
|
||||
const improvements = (synthesis.per_step_improvements || [])
|
||||
.filter(imp => imp.priority === 'high')
|
||||
.map(imp => `- **${imp.step}**: ${imp.action}`)
|
||||
.join('\n');
|
||||
|
||||
const report = `# Workflow Tune Report
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Workflow | ${state.workflow_name} |
|
||||
| Test Project | ${state.project_scenario} |
|
||||
| Workflow Score | ${synthesis.workflow_score || avgScore}/100 |
|
||||
| Avg Step Score | ${avgScore}/100 |
|
||||
| Total Issues | ${totalIssues} |
|
||||
| Coherence | ${synthesis.coherence?.score || '-'}/100 |
|
||||
|
||||
## Step Results
|
||||
|
||||
| # | Step | Exec | Req | Quality | Issues |
|
||||
|---|------|------|-----|---------|--------|
|
||||
${stepTable}
|
||||
|
||||
## High Priority Improvements
|
||||
|
||||
${improvements || 'None'}
|
||||
|
||||
## Workflow-Level Improvements
|
||||
|
||||
${(synthesis.workflow_improvements || []).map(w => `- **${w.area}** (${w.impact}): ${w.description}`).join('\n') || 'None'}
|
||||
|
||||
## Bottlenecks
|
||||
|
||||
${(synthesis.bottlenecks || []).map(b => `- **${b.step}**: ${b.issue} → ${b.suggestion}`).join('\n') || 'None'}
|
||||
|
||||
## Summary
|
||||
|
||||
${synthesis.summary || 'N/A'}
|
||||
`;
|
||||
|
||||
Write(`${state.work_dir}/final-report.md`, report);
|
||||
state.status = 'completed';
|
||||
Write(`${state.work_dir}/workflow-state.json`, JSON.stringify(state, null, 2));
|
||||
|
||||
// Output report to user
|
||||
```
|
||||
|
||||
## Resume Chain
|
||||
|
||||
```
|
||||
Step 1 Execute → ccw cli claude --mode write --rule universal-rigorous-style --cd step-1/ → STOP → callback → artifacts
|
||||
Step 1 Analyze → ccw cli gemini --mode analysis --rule analysis-review-code-quality → STOP → callback → gemini_session_id = exec_id
|
||||
Step 2 Execute → ccw cli claude --mode write --rule universal-rigorous-style --cd step-2/ → STOP → callback → artifacts
|
||||
Step 2 Analyze → ccw cli gemini --mode analysis --resume gemini_session_id → STOP → callback → gemini_session_id = exec_id
|
||||
...
|
||||
Synthesize → ccw cli gemini --mode analysis --resume gemini_session_id → STOP → callback → synthesis
|
||||
Report → local generation (no CLI call)
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Phase | Error | Recovery |
|
||||
|-------|-------|----------|
|
||||
| Execute | CLI timeout | Retry once, then mark step failed and advance |
|
||||
| Execute | Command not found | Skip step, note in process-log |
|
||||
| Analyze | CLI fails | Retry without --resume, then skip analysis |
|
||||
| Synthesize | CLI fails | Generate report from step analyses only |
|
||||
| Any | 3+ consecutive errors | Terminate, produce partial report |
|
||||
|
||||
## Core Rules
|
||||
|
||||
1. **STOP After Each CLI Call**: Every `ccw cli` call runs in background — STOP output immediately, wait for hook callback
|
||||
2. **State Machine**: Advance via `current_step` + `current_phase`, never use sync loops for async operations
|
||||
3. **Test Task Drives Execution**: 每个命令必须有 test_task(完整需求说明),作为命令的 $ARGUMENTS 输入。test_task 由当前 Claude 直接根据命令链复杂度生成,不需要额外 CLI 调用
|
||||
4. **All Execution via claude**: `ccw cli --tool claude --mode write --rule universal-rigorous-style`
|
||||
5. **All Analysis via gemini**: `ccw cli --tool gemini --mode analysis`, chained via `--resume`
|
||||
6. **Session Capture**: After each gemini callback, capture exec_id → `gemini_session_id` for resume chain
|
||||
7. **Sandbox Isolation**: 所有命令在独立沙箱目录(`sandbox/`)中执行,使用虚构测试任务,不影响真实项目
|
||||
8. **Artifact Collection**: Scan sandbox filesystem (not git diff), compare pre/post snapshots
|
||||
9. **Prompt Assembly**: Every step goes through `assembleStepPrompt()` — resolves command file, reads YAML metadata, injects test_task, builds rich context
|
||||
10. **Auto-Confirm**: All prompts auto-confirmed, no blocking interactions during execution
|
||||
@@ -10,11 +10,11 @@ allowed-tools: TodoWrite(*), Agent(*), AskUserQuestion(*), Read(*), Grep(*), Glo
|
||||
When `--yes` or `-y`: Auto-confirm exploration decisions, use recommended analysis angles.
|
||||
|
||||
<purpose>
|
||||
Interactive collaborative analysis workflow combining codebase exploration (cli-explore-agent) with CLI-assisted analysis (Gemini/Codex). Produces a documented discussion timeline with evolving understanding, decision trails, and actionable conclusions.
|
||||
Interactive collaborative analysis workflow combining codebase exploration (cli-explore-agent), external research (workflow-research-agent), and CLI-assisted analysis (Gemini/Codex). Produces a documented discussion timeline with evolving understanding, decision trails, and actionable conclusions.
|
||||
|
||||
Invoked when user needs deep, multi-perspective analysis of a topic or codebase question — e.g., architecture review, implementation analysis, concept exploration, or decision evaluation.
|
||||
|
||||
Produces: `discussion.md` (evolving analysis document with TOC, rounds, narrative synthesis), `explorations.json`/`perspectives.json` (structured findings), `conclusions.json` (final synthesis with recommendations). All artifacts stored in `.workflow/.analysis/{session-id}/`.
|
||||
Produces: `discussion.md` (evolving analysis document with TOC, rounds, narrative synthesis), `explorations.json`/`perspectives.json` (structured findings), `research.json` (external research findings), `conclusions.json` (final synthesis with recommendations). All artifacts stored in `.workflow/.analysis/{session-id}/`.
|
||||
</purpose>
|
||||
|
||||
<conventions>
|
||||
@@ -72,16 +72,23 @@ All `AskUserQuestion` calls MUST comply:
|
||||
|
||||
**Principles**: Immediacy (record as-it-happens), Completeness (context+options+chosen+reason+rejected), Traceability (later phases trace back), Depth (capture reasoning, not just outcomes)
|
||||
|
||||
**Technical Solution Triggers** — record using Technical Solution Record Format when ANY of:
|
||||
- An implementation approach is described with specific files/patterns/code changes
|
||||
- Two or more alternatives are compared with trade-offs
|
||||
- User confirms, modifies, or rejects a proposed approach
|
||||
- A concrete code change strategy emerges (what to modify, how, why)
|
||||
|
||||
### Output Artifacts
|
||||
|
||||
| Phase | Artifact | Description |
|
||||
|-------|----------|-------------|
|
||||
| 1 | `discussion.md` | Initialized with TOC, Current Understanding block, timeline, metadata |
|
||||
| 1 | Session variables | Dimensions, focus areas, analysis depth |
|
||||
| 2 | `exploration-codebase.json` | Single codebase context from cli-explore-agent |
|
||||
| 2 | `explorations/*.json` | Multi-perspective codebase explorations (parallel, up to 4) |
|
||||
| 2 | `explorations.json` | Single perspective aggregated findings |
|
||||
| 2 | `perspectives.json` | Multi-perspective findings (up to 4) with synthesis |
|
||||
| 2 | `exploration-codebase.json` | Shared Layer 1 discovery (files, modules, patterns) — always created |
|
||||
| 2 | `explorations/*.json` | Per-perspective Layer 2-3 deep-dives (multi-perspective only, max 4) |
|
||||
| 2 | `research.json` | External research findings (best practices, API details, known issues) — from workflow-research-agent |
|
||||
| 2 | `explorations.json` | Single perspective aggregated findings (Layer 1 + CLI analysis + research) |
|
||||
| 2 | `perspectives.json` | Multi-perspective findings (Layer 1 shared + per-perspective deep-dives + research) with synthesis |
|
||||
| 2 | Updated `discussion.md` | Round 1 + Initial Intent Coverage Check + Current Understanding replaced |
|
||||
| 3 | Updated `discussion.md` | Round 2-N: feedback, insights, narrative synthesis; TOC + Current Understanding updated each round |
|
||||
| 4 | `conclusions.json` | Final synthesis with recommendations (incl. steps[] + review_status) |
|
||||
@@ -141,98 +148,192 @@ All `AskUserQuestion` calls MUST comply:
|
||||
<step name="cli_exploration">
|
||||
**Phase 2: Codebase exploration FIRST, then CLI analysis.**
|
||||
|
||||
**Step 1: Codebase Exploration** (cli-explore-agent, parallel up to 6)
|
||||
**Step 1: Codebase Exploration** (cli-explore-agent, 1 shared + N perspective-specific)
|
||||
|
||||
- **Single**: General codebase analysis -> `{sessionFolder}/exploration-codebase.json`
|
||||
- **Multi-perspective**: Parallel per-perspective -> `{sessionFolder}/explorations/{perspective}.json`
|
||||
- **Common tasks**: `ccw tool exec get_modules_by_depth '{}'`, keyword searches, read `.workflow/project-tech.json`
|
||||
Two-phase approach to avoid redundant file discovery:
|
||||
|
||||
**Phase A — Shared Discovery** (1 agent, always runs):
|
||||
One cli-explore-agent performs Layer 1 (breadth) for ALL perspectives -> `{sessionFolder}/exploration-codebase.json`
|
||||
|
||||
```javascript
|
||||
// Template for cli-explore-agent (single or per-perspective)
|
||||
// Shared Layer 1 discovery — runs ONCE regardless of perspective count
|
||||
Agent({
|
||||
subagent_type: "cli-explore-agent",
|
||||
run_in_background: false,
|
||||
description: `Explore codebase: ${topicSlug}`,
|
||||
description: `Discover codebase: ${topicSlug}`,
|
||||
prompt: `
|
||||
## Analysis Context
|
||||
Topic: ${topic_or_question}
|
||||
Dimensions: ${dimensions.join(', ')}
|
||||
// For multi-perspective, add: Perspective: ${perspective.name} - ${perspective.focus}
|
||||
Session: ${sessionFolder}
|
||||
|
||||
## MANDATORY FIRST STEPS
|
||||
1. Run: ccw tool exec get_modules_by_depth '{}'
|
||||
2. Read: .workflow/project-tech.json (if exists)
|
||||
|
||||
## Layered Exploration (MUST follow all 3 layers)
|
||||
|
||||
### Layer 1 — Module Discovery (Breadth)
|
||||
- Search by topic keywords, identify ALL relevant files
|
||||
- Map module boundaries and entry points -> relevant_files[] with annotations
|
||||
|
||||
### Layer 2 — Structure Tracing (Depth)
|
||||
- Top 3-5 key files: trace call chains 2-3 levels deep
|
||||
- Identify data flow paths and dependencies -> call_chains[], data_flows[]
|
||||
|
||||
### Layer 3 — Code Anchor Extraction (Detail)
|
||||
- Each key finding: extract code snippet (20-50 lines) with file:line
|
||||
- Annotate WHY this matters -> code_anchors[]
|
||||
## Layer 1 — Module Discovery (Breadth ONLY)
|
||||
- Search by topic keywords across ALL dimensions: ${dimensions.join(', ')}
|
||||
- Identify ALL relevant files, map module boundaries and entry points
|
||||
- Categorize files by dimension/perspective relevance
|
||||
- Output: relevant_files[] with annotations + dimension tags, initial patterns[]
|
||||
|
||||
## Output
|
||||
Write to: ${sessionFolder}/exploration-codebase.json
|
||||
// Multi-perspective: ${sessionFolder}/explorations/${perspective.name}.json
|
||||
|
||||
Schema: {relevant_files, patterns, key_findings, code_anchors: [{file, lines, snippet, significance}], call_chains: [{entry, chain, files}], questions_for_user, _metadata}
|
||||
Schema: {relevant_files: [{path, annotation, dimensions[]}], patterns[], module_map: {}, questions_for_user, _metadata}
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
**Step 2: CLI Analysis** (AFTER exploration)
|
||||
**Phase A2 — External Research** (parallel with Phase A, runs when topic involves technologies/patterns/APIs):
|
||||
|
||||
- **Single**: Comprehensive CLI analysis with exploration context
|
||||
- **Multi (up to 4)**: Parallel CLI calls per perspective
|
||||
Determine if external research would add value — skip for purely internal codebase questions (e.g., "how does module X work"), run for topics involving technology choices, best practices, architecture patterns, API usage, or comparison with industry standards.
|
||||
|
||||
```javascript
|
||||
// External research — runs in PARALLEL with Phase A codebase exploration
|
||||
// Skip if topic is purely internal codebase navigation
|
||||
const needsResearch = dimensions.some(d =>
|
||||
['architecture', 'comparison', 'decision', 'performance', 'security'].includes(d)
|
||||
) || topic_or_question.match(/best practice|pattern|vs|compare|approach|standard|library|framework/i)
|
||||
|
||||
if (needsResearch) {
|
||||
Agent({
|
||||
subagent_type: "workflow-research-agent",
|
||||
run_in_background: false,
|
||||
description: `Research: ${topicSlug}`,
|
||||
prompt: `
|
||||
## Research Objective
|
||||
Topic: ${topic_or_question}
|
||||
Mode: detail-verification
|
||||
Dimensions: ${dimensions.join(', ')}
|
||||
|
||||
## Focus
|
||||
${dimensions.includes('architecture') ? '- Architecture patterns and best practices for this domain' : ''}
|
||||
${dimensions.includes('performance') ? '- Performance benchmarks and optimization patterns' : ''}
|
||||
${dimensions.includes('security') ? '- Security best practices and known vulnerabilities' : ''}
|
||||
${dimensions.includes('comparison') ? '- Technology comparison and trade-off analysis' : ''}
|
||||
${dimensions.includes('decision') ? '- Decision frameworks and industry recommendations' : ''}
|
||||
- Verify assumptions about technologies/patterns involved
|
||||
- Known issues and pitfalls in this area
|
||||
- Recommended approaches with evidence
|
||||
|
||||
## Codebase Context (from Phase A if available)
|
||||
Tech stack: ${techStack || 'detect from project files'}
|
||||
Key patterns observed: ${sharedDiscovery?.patterns?.join(', ') || 'pending Phase A results'}
|
||||
|
||||
## Output
|
||||
Return structured markdown per your output format.
|
||||
Do NOT write files.
|
||||
`
|
||||
})
|
||||
// Parse research agent output → save to ${sessionFolder}/research.json
|
||||
// Schema: {topic, mode, findings[], best_practices[], alternatives[], pitfalls[], sources[], _metadata}
|
||||
}
|
||||
```
|
||||
|
||||
**Phase B — Perspective Deep-Dive** (PARALLEL, only for multi-perspective, max 4):
|
||||
Each perspective agent receives shared Layer 1 results, performs only Layer 2-3 on its relevant subset.
|
||||
Skip if single-perspective (single mode proceeds directly to Step 2 CLI analysis with Layer 1 results).
|
||||
|
||||
**CRITICAL — Parallel Execution**: Launch ALL perspective Agent() calls in the SAME response block so Claude Code executes them concurrently. Do NOT use a loop that waits for each agent before starting the next.
|
||||
|
||||
```javascript
|
||||
// Per-perspective Layer 2-3 — receives shared discovery, avoids re-scanning
|
||||
// Only runs in multi-perspective mode
|
||||
// PARALLEL: All Agent() calls MUST appear in ONE response — Claude Code runs them concurrently
|
||||
const sharedDiscovery = readJSON(`${sessionFolder}/exploration-codebase.json`)
|
||||
|
||||
// Prepare per-perspective file lists
|
||||
const perspectiveFileLists = Object.fromEntries(
|
||||
selectedPerspectives.map(p => [
|
||||
p.name,
|
||||
sharedDiscovery.relevant_files.filter(f => f.dimensions.includes(p.dimension))
|
||||
])
|
||||
)
|
||||
|
||||
// Launch ALL agents in a SINGLE response block (not sequentially):
|
||||
// Agent({ ..perspective1.. }) ← call 1
|
||||
// Agent({ ..perspective2.. }) ← call 2 (same response)
|
||||
// Agent({ ..perspective3.. }) ← call 3 (same response)
|
||||
|
||||
// Each agent call follows this template:
|
||||
Agent({
|
||||
subagent_type: "cli-explore-agent",
|
||||
run_in_background: false,
|
||||
description: `Deep-dive: ${perspective.name}`,
|
||||
prompt: `
|
||||
## Analysis Context
|
||||
Topic: ${topic_or_question}
|
||||
Perspective: ${perspective.name} - ${perspective.focus}
|
||||
Session: ${sessionFolder}
|
||||
|
||||
## SHARED DISCOVERY (Layer 1 already completed — DO NOT re-scan)
|
||||
Relevant files for this perspective:
|
||||
${perspectiveFileLists[perspective.name].map(f => `- ${f.path}: ${f.annotation}`).join('\n')}
|
||||
Patterns found: ${sharedDiscovery.patterns.join(', ')}
|
||||
|
||||
## Layer 2 — Structure Tracing (Depth)
|
||||
- From the relevant files above, pick top 3-5 key files for this perspective
|
||||
- Trace call chains 2-3 levels deep
|
||||
- Identify data flow paths and dependencies -> call_chains[], data_flows[]
|
||||
|
||||
## Layer 3 — Code Anchor Extraction (Detail)
|
||||
- Each key finding: extract code snippet (20-50 lines) with file:line
|
||||
- Annotate WHY this matters for ${perspective.name} -> code_anchors[]
|
||||
|
||||
## Output
|
||||
Write to: ${sessionFolder}/explorations/${perspective.name}.json
|
||||
Schema: {perspective, relevant_files, key_findings, code_anchors: [{file, lines, snippet, significance}], call_chains: [{entry, chain, files}], questions_for_user, _metadata}
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
**Step 2: CLI Deep Analysis** (AFTER exploration, single-perspective ONLY)
|
||||
|
||||
- **Single-perspective**: CLI does Layer 2-3 depth analysis (explore agent only did Layer 1)
|
||||
- **Multi-perspective**: SKIP this step — perspective agents in Step 1 Phase B already did Layer 2-3
|
||||
- Execution: `Bash` with `run_in_background: true`
|
||||
|
||||
```javascript
|
||||
// Build shared exploration context for CLI prompts
|
||||
const explorationContext = `
|
||||
PRIOR EXPLORATION CONTEXT:
|
||||
- Key files: ${explorationResults.relevant_files.slice(0,5).map(f => f.path).join(', ')}
|
||||
- Patterns: ${explorationResults.patterns.slice(0,3).join(', ')}
|
||||
- Findings: ${explorationResults.key_findings.slice(0,3).join(', ')}
|
||||
- Code anchors:
|
||||
${(explorationResults.code_anchors || []).slice(0,5).map(a => ` [${a.file}:${a.lines}] ${a.significance}\n \`\`\`\n ${a.snippet}\n \`\`\``).join('\n')}
|
||||
- Call chains: ${(explorationResults.call_chains || []).slice(0,3).map(c => `${c.entry} -> ${c.chain.join(' -> ')}`).join('; ')}`
|
||||
// ONLY for single-perspective mode — multi-perspective already has deep-dive agents
|
||||
if (selectedPerspectives.length <= 1) {
|
||||
const sharedDiscovery = readJSON(`${sessionFolder}/exploration-codebase.json`)
|
||||
const explorationContext = `
|
||||
PRIOR EXPLORATION (Layer 1 discovery):
|
||||
- Key files: ${sharedDiscovery.relevant_files.slice(0,8).map(f => `${f.path} (${f.annotation})`).join(', ')}
|
||||
- Patterns: ${sharedDiscovery.patterns.slice(0,5).join(', ')}
|
||||
- Module map: ${JSON.stringify(sharedDiscovery.module_map || {})}`
|
||||
|
||||
// Single perspective (for multi: loop selectedPerspectives with perspective.purpose/tasks/constraints)
|
||||
Bash({
|
||||
command: `ccw cli -p "
|
||||
PURPOSE: Analyze '${topic_or_question}' from ${dimensions.join(', ')} perspectives
|
||||
Success: Actionable insights with clear reasoning
|
||||
Bash({
|
||||
command: `ccw cli -p "
|
||||
PURPOSE: Deep analysis of '${topic_or_question}' — build on prior file discovery
|
||||
Success: Actionable insights with code evidence (anchors + call chains)
|
||||
|
||||
${explorationContext}
|
||||
|
||||
TASK:
|
||||
- Build on exploration findings — reference specific code anchors
|
||||
- Analyze common patterns and anti-patterns with code evidence
|
||||
- Highlight potential issues/opportunities with file:line references
|
||||
- From discovered files, trace call chains 2-3 levels deep for top 3-5 key files
|
||||
- Extract code snippets (20-50 lines) for each key finding with file:line
|
||||
- Identify patterns, anti-patterns, and potential issues with evidence
|
||||
- Generate discussion points for user clarification
|
||||
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Topic: ${topic_or_question}
|
||||
EXPECTED: Structured analysis with sections, insights tied to evidence, questions, recommendations
|
||||
CONSTRAINTS: Focus on ${dimensions.join(', ')}
|
||||
EXPECTED: Structured analysis with: key_findings[], code_anchors[{file,lines,snippet,significance}], call_chains[{entry,chain,files}], discussion_points[]
|
||||
CONSTRAINTS: Focus on ${dimensions.join(', ')} | Do NOT re-discover files — use provided file list
|
||||
" --tool gemini --mode analysis`,
|
||||
run_in_background: true
|
||||
})
|
||||
// STOP: Wait for hook callback before continuing
|
||||
// Multi-perspective: Same pattern per perspective with perspective.purpose/tasks/constraints/tool
|
||||
run_in_background: true
|
||||
})
|
||||
// STOP: Wait for hook callback before continuing
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: Aggregate Findings**
|
||||
- Consolidate explorations + CLI results
|
||||
- Consolidate explorations + CLI results + research findings (if research.json exists)
|
||||
- Merge research best_practices[] and pitfalls[] into discussion points
|
||||
- Cross-reference: flag gaps where codebase patterns diverge from research best practices
|
||||
- Multi: Extract synthesis (convergent themes, conflicting views, unique contributions)
|
||||
- Write to `explorations.json` (single) or `perspectives.json` (multi)
|
||||
- If research.json exists, add `external_research` section to explorations/perspectives with: key findings, best practices, codebase gaps
|
||||
|
||||
**Step 4: Update discussion.md** — Append Round 1 with sources, key findings, discussion points, open questions
|
||||
|
||||
@@ -243,18 +344,7 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
|
||||
- Present to user at beginning of Phase 3: "初始探索完成后,以下意图的覆盖情况:[list]。接下来的讨论将重点关注未覆盖的部分。"
|
||||
- Purpose: Early course correction — catch drift before spending multiple interactive rounds
|
||||
|
||||
**explorations.json Schema** (single):
|
||||
- `session_id`, `timestamp`, `topic`, `dimensions[]`
|
||||
- `sources[]`: {type, file/summary}
|
||||
- `key_findings[]`, `code_anchors[]`: {file, lines, snippet, significance}
|
||||
- `call_chains[]`: {entry, chain, files}
|
||||
- `discussion_points[]`, `open_questions[]`
|
||||
- `technical_solutions[]`: {round, solution, problem, rationale, alternatives, status: proposed|validated|rejected, evidence_refs[], next_action}
|
||||
|
||||
**perspectives.json Schema** (multi — extends explorations.json):
|
||||
- `perspectives[]`: [{name, tool, findings, insights, questions}]
|
||||
- `synthesis`: {convergent_themes, conflicting_views, unique_contributions}
|
||||
- code_anchors/call_chains include `perspective` field
|
||||
> All JSON schemas consolidated in `<schemas>` section below.
|
||||
|
||||
| Condition | Action |
|
||||
|-----------|--------|
|
||||
@@ -270,6 +360,22 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
|
||||
|
||||
**Guideline**: Delegate complex tasks to agents (cli-explore-agent) or CLI calls. Avoid direct analysis in main process.
|
||||
|
||||
**Cumulative Context Rule**: Every agent/CLI call in Phase 3 MUST include a summary of ALL prior exploration results to avoid re-discovering known information. Build `priorContext` before each call:
|
||||
```javascript
|
||||
// Build cumulative context from all prior explorations (Phase 2 + previous rounds)
|
||||
const allFindings = readJSON(`${sessionFolder}/explorations.json`) // or perspectives.json
|
||||
const priorContext = `
|
||||
## KNOWN FINDINGS (DO NOT re-discover)
|
||||
- Established files: ${allFindings.sources.map(s => s.file).join(', ')}
|
||||
- Key findings: ${allFindings.key_findings.join('; ')}
|
||||
- Code anchors: ${allFindings.code_anchors.slice(0,5).map(a => `${a.file}:${a.lines}`).join(', ')}
|
||||
- Call chains: ${allFindings.call_chains.slice(0,3).map(c => c.entry).join(', ')}
|
||||
- Open questions: ${allFindings.open_questions.join('; ')}
|
||||
|
||||
## NEW TASK: Focus ONLY on unexplored areas below.
|
||||
`
|
||||
```
|
||||
|
||||
**Loop** (max 5 rounds):
|
||||
|
||||
1. **Current Understanding Summary** (Round >= 2, BEFORE presenting new findings):
|
||||
@@ -280,28 +386,42 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
|
||||
|
||||
3. **Gather Feedback** (AskUserQuestion, single-select, header: "分析反馈"):
|
||||
- **继续深入**: Direction correct — deepen automatically or user specifies direction (combines agree+deepen and agree+suggest)
|
||||
- **外部研究**: Need external research on specific technology/pattern/best practice (spawns workflow-research-agent)
|
||||
- **调整方向**: Different focus or specific questions to address
|
||||
- **补充信息**: User has additional context, constraints, or corrections to provide
|
||||
- **分析完成**: Sufficient -> exit to Phase 4
|
||||
|
||||
4. **Process Response** (always record user choice + impact to discussion.md):
|
||||
|
||||
**Record-Before-Continue Rule**: Each path below MUST write findings and discussion synthesis to `discussion.md` BEFORE proceeding to Step 5. Specifically, after agent/CLI returns results:
|
||||
- Append the exploration results, reasoning, and any technical approaches discussed to the current round section
|
||||
- Apply **Technical Solution Triggers** (see Decision Recording Protocol) — if triggered, record using Technical Solution Record Format
|
||||
- **Ambiguity Check**: For each Technical Solution with Status `Proposed`, verify no unresolved alternatives remain. If a solution lists 2+ options without a chosen one (e.g., "A or B"), record as:
|
||||
```markdown
|
||||
> **⚠️ Ambiguity**: [Solution] has [N] unresolved alternatives: [list]
|
||||
> - **Needs**: [Decision criteria or exploration to resolve]
|
||||
```
|
||||
Surface unresolved ambiguities to user in the next feedback round.
|
||||
- Only THEN proceed to Step 5 for Current Understanding replacement and TOC update
|
||||
|
||||
**继续深入** -> Sub-question to choose direction (AskUserQuestion, single-select, header: "深入方向"):
|
||||
- Dynamically generate **max 3** context-driven options from: unresolved questions, low-confidence findings, unexplored dimensions, user-highlighted areas
|
||||
- Add **1** heuristic option that breaks current frame (e.g., "compare with best practices", "review from security perspective", "explore simpler alternatives")
|
||||
- Total: **max 4 options**. Each specifies: label, description, tool (cli-explore-agent for code-level / Gemini CLI for pattern-level), scope
|
||||
- **"Other" is auto-provided** by AskUserQuestion — covers user-specified custom direction (no need for separate "suggest next step" option)
|
||||
- Execute selected direction -> merge new code_anchors/call_chains -> record confirmed assumptions + deepen angle
|
||||
- Execute selected direction -> merge new code_anchors/call_chains into explorations.json -> **write exploration results, analysis reasoning, and any proposed approaches to discussion.md** -> record confirmed assumptions + deepen angle
|
||||
|
||||
**外部研究** -> Spawn workflow-research-agent for targeted research:
|
||||
- AskUserQuestion (header: "研究主题", freetext via "Other"): What specific technology/pattern/approach needs external research?
|
||||
- Spawn research agent with topic + current codebase context (from explorations.json)
|
||||
- Merge research findings into explorations.json `external_research` section
|
||||
- Update research.json with new findings (append, don't overwrite)
|
||||
- Record research findings as Key Findings in discussion.md
|
||||
|
||||
**调整方向** -> AskUserQuestion (header: "新方向", user selects or provides custom via "Other") -> new CLI exploration -> Record Decision (old vs new direction, reason, impact)
|
||||
|
||||
**补充信息** -> Capture user input, integrate into context, answer questions via CLI/analysis if needed -> Record corrections/additions + updated understanding
|
||||
|
||||
**分析完成** -> Exit loop -> Record why concluding
|
||||
|
||||
5. **Update discussion.md**:
|
||||
- **Append** Round N: user input, direction adjustment, Q&A, corrections, new insights
|
||||
- **Append Technical Solutions** — for every solution proposed, validated, or rejected this round, record immediately using Technical Solution Record Format in `#### Technical Solutions`
|
||||
5. **Update discussion.md** (after Record-Before-Continue writes are done):
|
||||
- **Replace** `## Current Understanding` block with latest consolidated understanding (follow Consolidation Rules)
|
||||
- **Update** `## Table of Contents` with links to new Round N sections
|
||||
|
||||
@@ -352,26 +472,50 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
|
||||
- **Gate**: ❌ Missed items must be either (a) addressed in additional round or (b) confirmed deferred by user
|
||||
- Add `intent_coverage[]` to conclusions.json
|
||||
|
||||
2. **Consolidate Insights**:
|
||||
2. **Findings-to-Recommendations Traceability** (MANDATORY before consolidation):
|
||||
- **Collect ALL actionable findings** from every round: key findings with actionable implications, technical solutions (proposed/validated), identified gaps (API-frontend gaps, missing features, design issues), corrected assumptions that imply fixes
|
||||
- **Map each finding → disposition**:
|
||||
| Disposition | Meaning |
|
||||
|-------------|---------|
|
||||
| `recommendation` | Converted to a numbered recommendation |
|
||||
| `absorbed` | Covered by another recommendation (specify which) |
|
||||
| `deferred` | Explicitly out-of-scope with reason |
|
||||
| `informational` | Pure insight, no action needed |
|
||||
- **Findings Coverage Matrix** (append to discussion.md):
|
||||
```markdown
|
||||
### Findings Coverage Matrix
|
||||
| # | Finding (Round) | Disposition | Target |
|
||||
|---|----------------|-------------|--------|
|
||||
| 1 | [finding summary] (R1) | recommendation | Rec #1 |
|
||||
| 2 | [finding summary] (R2) | absorbed | → Rec #1 |
|
||||
| 3 | [finding summary] (R2) | deferred | Reason: [why] |
|
||||
| 4 | [finding summary] (R1) | informational | — |
|
||||
```
|
||||
- **Gate**: Findings with `disposition = null` (unmapped) MUST be either assigned a disposition or added as new recommendations. Do NOT proceed to step 3 with unmapped findings.
|
||||
- Add `findings_coverage[]` to conclusions.json
|
||||
|
||||
3. **Consolidate Insights**:
|
||||
- Compile Decision Trail from all phases
|
||||
- Key conclusions with evidence + confidence (high/medium/low)
|
||||
- Recommendations with rationale + priority (high/medium/low) — **merge validated `technical_solutions[]` from explorations.json as high-priority recommendations**
|
||||
- Recommendations with rationale + priority (high/medium/low) — **merge validated `technical_solutions[]` from explorations.json as high-priority recommendations** — **ensure all `disposition = recommendation` findings from step 2 are represented**
|
||||
- **Solution Readiness Gate**: For each recommendation, check if all key choices are resolved. Flag `ambiguity_resolved: false` on any recommendation that still contains unresolved alternatives. Present unresolved items to user before proceeding to Step 4.
|
||||
- Open questions, follow-up suggestions
|
||||
- Decision summary linking conclusions back to decisions
|
||||
- Write to conclusions.json
|
||||
|
||||
3. **Final discussion.md Update**:
|
||||
4. **Final discussion.md Update**:
|
||||
- **Conclusions**: Summary, ranked key conclusions, prioritized recommendations, remaining questions
|
||||
- **Current Understanding (Final)**: What established, what clarified/corrected, key insights
|
||||
- **Decision Trail**: Critical decisions, direction changes timeline, trade-offs
|
||||
- **Findings Coverage Matrix**: From step 2 (already appended)
|
||||
- Session statistics: rounds, duration, sources, artifacts, decision count
|
||||
|
||||
4. **Display Conclusions Summary** — Present to user:
|
||||
5. **Display Conclusions Summary** — Present to user:
|
||||
- **Analysis Report**: summary, key conclusions (numbered, with confidence), recommendations (numbered, with priority + rationale + steps)
|
||||
- Open questions if any
|
||||
- Link to full report: `{sessionFolder}/discussion.md`
|
||||
|
||||
5. **Interactive Recommendation Review** (skip in auto mode):
|
||||
6. **Interactive Recommendation Review** (skip in auto mode):
|
||||
|
||||
Present all recommendations, then batch-confirm via **single AskUserQuestion call** (up to 4 questions):
|
||||
|
||||
@@ -392,7 +536,7 @@ CONSTRAINTS: Focus on ${dimensions.join(', ')}
|
||||
- Accepted: N items | Modified: N items | Rejected: N items
|
||||
- Only accepted/modified recommendations proceed to next step
|
||||
|
||||
6. **MANDATORY GATE: Next Step Selection** — workflow MUST NOT end without executing this step.
|
||||
7. **MANDATORY GATE: Next Step Selection** — workflow MUST NOT end without executing this step.
|
||||
|
||||
**TodoWrite**: Update `phase-4` -> `"completed"`, `next-step` -> `"in_progress"`
|
||||
|
||||
@@ -500,7 +644,45 @@ ${implScope.map((item, i) => `${i+1}. **${item.objective}** [${item.priority}]
|
||||
|
||||
**TodoWrite**: Update `next-step` -> `"completed"` after user selection is handled
|
||||
|
||||
**conclusions.json Schema**:
|
||||
> conclusions.json schema: see `<schemas>` section below.
|
||||
</step>
|
||||
|
||||
</process>
|
||||
|
||||
<schemas>
|
||||
|
||||
**exploration-codebase.json** (shared Layer 1):
|
||||
- `session_id`, `timestamp`, `topic`, `dimensions[]`
|
||||
- `relevant_files[]`: {path, annotation, dimensions[]}
|
||||
- `patterns[]`, `module_map`: {}
|
||||
- `questions_for_user[]`, `_metadata`
|
||||
|
||||
**research.json** (external research findings):
|
||||
- `topic`, `mode` (detail-verification|api-research|design-research), `timestamp`
|
||||
- `findings[]`: {finding, detail, confidence, source_url}
|
||||
- `best_practices[]`: {practice, rationale, source}
|
||||
- `alternatives[]`: {option, pros, cons, verdict}
|
||||
- `pitfalls[]`: {issue, mitigation, source}
|
||||
- `codebase_gaps[]`: {gap, current_approach, recommended_approach}
|
||||
- `sources[]`: {title, url, key_takeaway}
|
||||
- `_metadata`: {queries_executed, results_found}
|
||||
|
||||
**explorations.json** (single — Layer 1 + CLI analysis + research merged):
|
||||
- `session_id`, `timestamp`, `topic`, `dimensions[]`
|
||||
- `sources[]`: {type, file/summary}
|
||||
- `key_findings[]`, `code_anchors[]`: {file, lines, snippet, significance}
|
||||
- `call_chains[]`: {entry, chain, files}
|
||||
- `discussion_points[]`, `open_questions[]`
|
||||
- `technical_solutions[]`: {round, solution, problem, rationale, alternatives, status: proposed|validated|rejected, evidence_refs[], next_action}
|
||||
- `external_research`: {findings[], best_practices[], codebase_gaps[], sources[]} — merged from research.json if available
|
||||
|
||||
**perspectives.json** (multi — Layer 1 shared + per-perspective Layer 2-3 + research):
|
||||
- `shared_discovery`: {relevant_files[], patterns[], module_map}
|
||||
- `perspectives[]`: [{name, tool, findings, insights, questions, code_anchors[], call_chains[]}]
|
||||
- `external_research`: {findings[], best_practices[], codebase_gaps[], sources[]} — merged from research.json if available
|
||||
- `synthesis`: {convergent_themes, conflicting_views, unique_contributions}
|
||||
|
||||
**conclusions.json**:
|
||||
- `session_id`, `topic`, `completed`, `total_rounds`, `summary`
|
||||
- `key_conclusions[]`: {point, evidence, confidence, code_anchor_refs[]}
|
||||
- `code_anchors[]`: {file, lines, snippet, significance}
|
||||
@@ -510,9 +692,9 @@ ${implScope.map((item, i) => `${i+1}. **${item.objective}** [${item.priority}]
|
||||
- `decision_trail[]`: {round, decision, context, options_considered, chosen, rejected_reasons, reason, impact}
|
||||
- `narrative_trail[]`: {round, starting_point, key_progress, hypothesis_impact, updated_understanding, remaining_questions}
|
||||
- `intent_coverage[]`: {intent, status, where_addressed, notes}
|
||||
</step>
|
||||
- `findings_coverage[]`: {finding, round, disposition: recommendation|absorbed|deferred|informational, target, reason}
|
||||
|
||||
</process>
|
||||
</schemas>
|
||||
|
||||
<error_codes>
|
||||
|
||||
@@ -525,6 +707,8 @@ ${implScope.map((item, i) => `${i+1}. **${item.objective}** [${item.priority}]
|
||||
| E005 | error | No relevant findings from exploration — broaden search, ask user for clarification | cli_exploration |
|
||||
| E006 | warning | Session folder conflict — append timestamp suffix | session_init |
|
||||
| E007 | error | Gemini unavailable — fallback to Codex or manual analysis | cli_exploration |
|
||||
| E008 | warning | Research agent WebSearch failed — continue with codebase-only analysis, note limitation | cli_exploration |
|
||||
| E009 | warning | Research findings conflict with codebase patterns — flag as codebase_gaps for user review | cli_exploration |
|
||||
|
||||
</error_codes>
|
||||
|
||||
@@ -534,13 +718,16 @@ ${implScope.map((item, i) => `${i+1}. **${item.objective}** [${item.priority}]
|
||||
- [ ] Dimensions identified and user preferences captured (Phase 1)
|
||||
- [ ] discussion.md initialized with TOC, Current Understanding, metadata
|
||||
- [ ] Codebase exploration completed with code_anchors and call_chains (Phase 2)
|
||||
- [ ] External research executed if topic warrants it (architecture/comparison/decision/performance/security dimensions)
|
||||
- [ ] Research findings merged into explorations/perspectives with codebase_gaps flagged
|
||||
- [ ] CLI analysis executed and findings aggregated
|
||||
- [ ] Initial Intent Coverage Check appended to discussion.md
|
||||
- [ ] Interactive discussion rounds documented with narrative synthesis (Phase 3)
|
||||
- [ ] Intent Drift Check performed each round >= 2
|
||||
- [ ] All decisions recorded per Decision Recording Protocol
|
||||
- [ ] Intent Coverage Matrix verified in Phase 4
|
||||
- [ ] conclusions.json created with key_conclusions, recommendations, decision_trail
|
||||
- [ ] Findings Coverage Matrix completed — all actionable findings mapped to disposition (recommendation/absorbed/deferred/informational)
|
||||
- [ ] conclusions.json created with key_conclusions, recommendations, decision_trail, findings_coverage
|
||||
- [ ] discussion.md finalized with conclusions, Decision Trail, session statistics
|
||||
- [ ] Recommendation review completed (non-auto mode)
|
||||
- [ ] Next Step terminal gate executed — `next-step` todo is `"completed"`
|
||||
@@ -557,7 +744,7 @@ ${implScope.map((item, i) => `${i+1}. **${item.objective}** [${item.priority}]
|
||||
| **Business** | Codex | Value, ROI, stakeholder impact | Business implications |
|
||||
| **Domain Expert** | Gemini | Domain patterns, best practices, standards | Industry knowledge |
|
||||
|
||||
User multi-selects up to 4 in Phase 1, default: single comprehensive view.
|
||||
User multi-selects up to 4 in Phase 1. Default: if dimensions >= 2, pre-select Technical + Architectural; if dimensions == 1, single comprehensive view.
|
||||
|
||||
### Dimension-Direction Mapping
|
||||
|
||||
@@ -596,9 +783,6 @@ Present 2-3 top directions per dimension, allow multi-select + custom.
|
||||
| Preserve key learnings | Keep insights valuable for future reference |
|
||||
|
||||
</configuration>
|
||||
|
||||
> **Lite-plan handoff**: Phase 4「执行任务」builds structured `handoff-spec` JSON (implementation_scope with acceptance_criteria, code_anchors, key_findings) embedded in `## Prior Analysis` block. lite-plan parses `json:handoff-spec` to directly map scope items → tasks, skipping exploration and using acceptance_criteria as convergence.criteria.
|
||||
|
||||
---
|
||||
|
||||
**Now execute analyze-with-file for**: $ARGUMENTS
|
||||
|
||||
@@ -129,7 +129,7 @@ Task(
|
||||
Analyze project for workflow initialization and generate .workflow/project-tech.json.
|
||||
|
||||
## MANDATORY FIRST STEPS
|
||||
1. Execute: cat ~/.ccw/workflows/cli-templates/schemas/project-tech-schema.json (get schema reference)
|
||||
1. Execute: ccw tool exec json_builder '{"cmd":"info","schema":"tech"}' (get schema summary)
|
||||
2. Execute: ccw tool exec get_modules_by_depth '{}' (get project structure)
|
||||
|
||||
## Task
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
10. [质量控制规范](#10-质量控制规范)
|
||||
11. [最佳实践清单](#11-最佳实践清单)
|
||||
12. [示例模板](#12-示例模板)
|
||||
13. [Completion Status Protocol](#13-completion-status-protocol)
|
||||
14. [Escalation Protocol](#14-escalation-protocol)
|
||||
|
||||
---
|
||||
|
||||
@@ -665,6 +667,144 @@ Generate XXX through multi-phase analysis.
|
||||
|
||||
---
|
||||
|
||||
## 13. Completion Status Protocol
|
||||
|
||||
### 13.1 Status Definitions
|
||||
|
||||
Every Skill execution MUST terminate with one of the following four statuses:
|
||||
|
||||
| Status | Exit Code | Definition |
|
||||
|--------|-----------|------------|
|
||||
| **DONE** | 0 | All acceptance criteria met, outputs generated successfully |
|
||||
| **DONE_WITH_CONCERNS** | 0 | Completed but with warnings or non-blocking issues |
|
||||
| **BLOCKED** | 1 | Cannot proceed, requires external action or resource |
|
||||
| **NEEDS_CONTEXT** | 2 | Missing information needed to make a decision |
|
||||
|
||||
### 13.2 When to Use
|
||||
|
||||
| Status | Use When |
|
||||
|--------|----------|
|
||||
| **DONE** | All phases completed, quality gates passed, outputs validated |
|
||||
| **DONE_WITH_CONCERNS** | Core task completed but: deprecation warnings found, quality score 60-79%, non-critical checks failed, partial data used as fallback |
|
||||
| **BLOCKED** | Required file/service unavailable, dependency not installed, permission denied, prerequisite task not completed |
|
||||
| **NEEDS_CONTEXT** | Ambiguous user requirement, multiple valid interpretations, missing configuration value, unclear scope boundary |
|
||||
|
||||
### 13.3 Output Format
|
||||
|
||||
Each status MUST use the following structured output at the end of Skill execution:
|
||||
|
||||
```
|
||||
## STATUS: {DONE|DONE_WITH_CONCERNS|BLOCKED|NEEDS_CONTEXT}
|
||||
|
||||
**Summary**: {one-line description of outcome}
|
||||
|
||||
### Details
|
||||
{status-specific content — see below}
|
||||
|
||||
### Outputs
|
||||
- {list of files created/modified, if any}
|
||||
```
|
||||
|
||||
**DONE details**:
|
||||
```
|
||||
### Details
|
||||
- Phases completed: {N}/{N}
|
||||
- Quality score: {score}%
|
||||
- Key outputs: {list of primary deliverables}
|
||||
```
|
||||
|
||||
**DONE_WITH_CONCERNS details**:
|
||||
```
|
||||
### Details
|
||||
- Phases completed: {N}/{N}
|
||||
- Concerns:
|
||||
1. {concern description} — Impact: {low|medium} — Suggested fix: {action}
|
||||
2. ...
|
||||
```
|
||||
|
||||
**BLOCKED details**:
|
||||
```
|
||||
### Details
|
||||
- Blocked at: Phase {N}, Step {M}
|
||||
- Blocker: {specific description of what is blocking}
|
||||
- Need: {specific action or resource required to unblock}
|
||||
- Attempted: {what was tried before declaring blocked}
|
||||
```
|
||||
|
||||
**NEEDS_CONTEXT details**:
|
||||
```
|
||||
### Details
|
||||
- Paused at: Phase {N}, Step {M}
|
||||
- Questions:
|
||||
1. {specific question requiring user/caller input}
|
||||
2. ...
|
||||
- Context available: {what is already known}
|
||||
- Impact: {what cannot proceed without answers}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. Escalation Protocol
|
||||
|
||||
### 14.1 Three-Strike Rule
|
||||
|
||||
When a Skill encounters consecutive failures on the **same step**, the following escalation applies:
|
||||
|
||||
| Strike | Action |
|
||||
|--------|--------|
|
||||
| 1st failure | Log error, retry with adjusted approach |
|
||||
| 2nd failure | Log error, try alternative strategy |
|
||||
| 3rd failure | **STOP execution immediately**, output diagnostic dump, request human intervention |
|
||||
|
||||
### 14.2 Failure Tracking
|
||||
|
||||
Track failures per step, not globally. A success on any step resets that step's failure counter.
|
||||
|
||||
```
|
||||
Step failure counter:
|
||||
Phase 2, Step 3: [fail] [fail] [STOP] → escalate
|
||||
Phase 2, Step 4: [fail] [success] → counter reset, continue
|
||||
```
|
||||
|
||||
### 14.3 Diagnostic Dump Format
|
||||
|
||||
On the 3rd consecutive failure, output the following diagnostic block:
|
||||
|
||||
```
|
||||
## ESCALATION: 3-Strike Limit Reached
|
||||
|
||||
### Failed Step
|
||||
- Phase: {phase_number} — {phase_name}
|
||||
- Step: {step_number} — {step_name}
|
||||
|
||||
### Error History
|
||||
1. Attempt 1: {error message or description}
|
||||
Strategy: {what was tried}
|
||||
2. Attempt 2: {error message or description}
|
||||
Strategy: {alternative approach tried}
|
||||
3. Attempt 3: {error message or description}
|
||||
Strategy: {final approach tried}
|
||||
|
||||
### Current State
|
||||
- Last successful phase/step: {phase.step}
|
||||
- Files generated so far: {list}
|
||||
- Files touched in failed attempts: {list}
|
||||
|
||||
### Diagnosis
|
||||
- Likely root cause: {assessment}
|
||||
- Suggested human action: {specific recommendation}
|
||||
```
|
||||
|
||||
### 14.4 Post-Escalation Behavior
|
||||
|
||||
After outputting the diagnostic dump:
|
||||
1. Set Skill status to **BLOCKED** (see Section 13)
|
||||
2. Do NOT attempt further retries
|
||||
3. Preserve all intermediate outputs for debugging
|
||||
4. Wait for human intervention before resuming
|
||||
|
||||
---
|
||||
|
||||
## 附录 A: 设计对比
|
||||
|
||||
| 设计点 | software-manual | copyright-docs |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: brainstorm
|
||||
description: Unified brainstorming skill with dual-mode operation - auto pipeline and single role analysis. Triggers on "brainstorm", "头脑风暴".
|
||||
description: Unified brainstorming skill with dual-mode operation — auto mode (framework generation, parallel multi-role analysis, cross-role synthesis) and single role analysis. Triggers on "brainstorm", "头脑风暴".
|
||||
allowed-tools: Skill(*), Agent(conceptual-planning-agent, context-search-agent), AskUserQuestion(*), TodoWrite(*), Read(*), Write(*), Edit(*), Glob(*), Bash(*)
|
||||
---
|
||||
|
||||
|
||||
110
.claude/skills/investigate/SKILL.md
Normal file
110
.claude/skills/investigate/SKILL.md
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
name: investigate
|
||||
description: Systematic debugging with Iron Law methodology. 5-phase investigation from evidence collection to verified fix. Triggers on "investigate", "debug", "root cause".
|
||||
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
||||
---
|
||||
|
||||
# Investigate
|
||||
|
||||
Systematic debugging skill that enforces the Iron Law: never fix without a confirmed root cause. Produces a structured debug report with full evidence chain, minimal fix, and regression test.
|
||||
|
||||
## Iron Law Principle
|
||||
|
||||
**No fix without confirmed root cause.** Every investigation follows a strict evidence chain:
|
||||
1. Reproduce the bug with concrete evidence
|
||||
2. Analyze patterns to assess scope
|
||||
3. Form and test hypotheses (max 3 strikes)
|
||||
4. Implement minimal fix ONLY after root cause is confirmed
|
||||
5. Verify fix and generate structured report
|
||||
|
||||
Violation of the Iron Law (skipping to Phase 4 without Phase 3 confirmation) is prohibited.
|
||||
|
||||
## Key Design Principles
|
||||
|
||||
1. **Evidence-First**: Collect before theorizing. Logs, stack traces, and reproduction steps are mandatory inputs.
|
||||
2. **Minimal Fix**: Change only what is necessary. Refactoring is not debugging.
|
||||
3. **3-Strike Escalation**: If 3 consecutive hypothesis tests fail, STOP and escalate with a diagnostic dump.
|
||||
4. **Regression Coverage**: Every fix must include a test that fails without the fix and passes with it.
|
||||
5. **Structured Output**: All findings are recorded in machine-readable JSON for future reference.
|
||||
|
||||
## Execution Flow
|
||||
|
||||
```
|
||||
Phase 1: Root Cause Investigation
|
||||
Reproduce bug, collect evidence (errors, logs, traces)
|
||||
Use ccw cli --tool gemini --mode analysis for initial diagnosis
|
||||
Output: investigation-report.json
|
||||
|
|
||||
v
|
||||
Phase 2: Pattern Analysis
|
||||
Search codebase for similar patterns (same error, module, antipattern)
|
||||
Assess scope: isolated vs systemic
|
||||
Output: pattern-analysis section in report
|
||||
|
|
||||
v
|
||||
Phase 3: Hypothesis Testing
|
||||
Form max 3 hypotheses from evidence
|
||||
Test each with minimal read-only probes
|
||||
3-strike rule: STOP and escalate on 3 consecutive failures
|
||||
Output: confirmed root cause with evidence chain
|
||||
|
|
||||
v
|
||||
Phase 4: Implementation [GATE: requires Phase 3 confirmed root cause]
|
||||
Implement minimal fix
|
||||
Add regression test
|
||||
Verify fix resolves reproduction case
|
||||
|
|
||||
v
|
||||
Phase 5: Verification & Report
|
||||
Run full test suite
|
||||
Check for regressions
|
||||
Generate structured debug report to .workflow/.debug/
|
||||
```
|
||||
|
||||
## Directory Setup
|
||||
|
||||
```bash
|
||||
mkdir -p .workflow/.debug
|
||||
```
|
||||
|
||||
## Output Structure
|
||||
|
||||
```
|
||||
.workflow/.debug/
|
||||
debug-report-{YYYY-MM-DD}-{slug}.json # Structured debug report
|
||||
```
|
||||
|
||||
## Completion Status Protocol
|
||||
|
||||
This skill follows the Completion Status Protocol defined in `_shared/SKILL-DESIGN-SPEC.md` sections 13-14.
|
||||
|
||||
| Status | When |
|
||||
|--------|------|
|
||||
| **DONE** | Root cause confirmed, fix applied, regression test passes, no regressions |
|
||||
| **DONE_WITH_CONCERNS** | Fix applied but partial test coverage or minor warnings |
|
||||
| **BLOCKED** | Cannot reproduce bug, or 3-strike escalation triggered in Phase 3 |
|
||||
| **NEEDS_CONTEXT** | Missing reproduction steps, unclear error conditions |
|
||||
|
||||
## Reference Documents
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| [phases/01-root-cause-investigation.md](phases/01-root-cause-investigation.md) | Evidence collection and reproduction |
|
||||
| [phases/02-pattern-analysis.md](phases/02-pattern-analysis.md) | Codebase pattern search and scope assessment |
|
||||
| [phases/03-hypothesis-testing.md](phases/03-hypothesis-testing.md) | Hypothesis formation, testing, and 3-strike rule |
|
||||
| [phases/04-implementation.md](phases/04-implementation.md) | Minimal fix with Iron Law gate |
|
||||
| [phases/05-verification-report.md](phases/05-verification-report.md) | Test suite, regression check, report generation |
|
||||
| [specs/iron-law.md](specs/iron-law.md) | Iron Law rules definition |
|
||||
| [specs/debug-report-format.md](specs/debug-report-format.md) | Structured debug report JSON schema |
|
||||
|
||||
## CLI Integration
|
||||
|
||||
This skill leverages `ccw cli` for multi-model analysis at key points:
|
||||
|
||||
| Phase | CLI Usage | Mode |
|
||||
|-------|-----------|------|
|
||||
| Phase 1 | Initial diagnosis from error evidence | `--mode analysis` |
|
||||
| Phase 2 | Cross-file pattern search | `--mode analysis` |
|
||||
| Phase 3 | Hypothesis validation assistance | `--mode analysis` |
|
||||
|
||||
All CLI calls use `--mode analysis` (read-only). No write-mode CLI calls during investigation phases 1-3.
|
||||
132
.claude/skills/investigate/phases/01-root-cause-investigation.md
Normal file
132
.claude/skills/investigate/phases/01-root-cause-investigation.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Phase 1: Root Cause Investigation
|
||||
|
||||
Reproduce the bug and collect all available evidence before forming any theories.
|
||||
|
||||
## Objective
|
||||
|
||||
- Reproduce the bug with concrete, observable symptoms
|
||||
- Collect all evidence: error messages, logs, stack traces, affected files
|
||||
- Establish a baseline understanding of what goes wrong and where
|
||||
- Use CLI analysis for initial diagnosis
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Understand the Bug Report
|
||||
|
||||
Parse the user's description to extract:
|
||||
- **Symptom**: What observable behavior is wrong?
|
||||
- **Expected**: What should happen instead?
|
||||
- **Context**: When/where does it occur? (specific input, environment, timing)
|
||||
|
||||
```javascript
|
||||
const bugReport = {
|
||||
symptom: "extracted from user description",
|
||||
expected_behavior: "what should happen",
|
||||
context: "when/where it occurs",
|
||||
user_provided_files: ["files mentioned by user"],
|
||||
user_provided_errors: ["error messages provided"]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Reproduce the Bug
|
||||
|
||||
Attempt to reproduce using the most direct method available:
|
||||
|
||||
1. **Run the failing test** (if one exists):
|
||||
```bash
|
||||
# Identify and run the specific failing test
|
||||
```
|
||||
|
||||
2. **Run the failing command** (if CLI/script):
|
||||
```bash
|
||||
# Execute the command that triggers the bug
|
||||
```
|
||||
|
||||
3. **Read error-producing code path** (if reproduction requires complex setup):
|
||||
- Use `Grep` to find the error message in source code
|
||||
- Use `Read` to trace the code path that produces the error
|
||||
- Document the theoretical reproduction path
|
||||
|
||||
**If reproduction fails**: Document what was attempted. The investigation can continue with static analysis, but note this as a concern.
|
||||
|
||||
### Step 3: Collect Evidence
|
||||
|
||||
Gather all available evidence using project tools:
|
||||
|
||||
```javascript
|
||||
// 1. Find error messages in source
|
||||
Grep({ pattern: "error message text", path: "src/" })
|
||||
|
||||
// 2. Find related log output
|
||||
Grep({ pattern: "relevant log pattern", path: "." })
|
||||
|
||||
// 3. Read stack trace files or test output
|
||||
Read({ file_path: "path/to/failing-test-output" })
|
||||
|
||||
// 4. Identify affected files and modules
|
||||
Glob({ pattern: "**/*relevant-module*" })
|
||||
```
|
||||
|
||||
### Step 4: Initial Diagnosis via CLI Analysis
|
||||
|
||||
Use `ccw cli` for a broader diagnostic perspective:
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Diagnose root cause of bug from collected evidence
|
||||
TASK: Analyze error context | Trace data flow | Identify suspicious code patterns
|
||||
MODE: analysis
|
||||
CONTEXT: @{affected_files} | Evidence: {error_messages_and_traces}
|
||||
EXPECTED: Top 3 likely root causes ranked by evidence strength
|
||||
CONSTRAINTS: Read-only analysis | Focus on {affected_module}" \
|
||||
--tool gemini --mode analysis
|
||||
```
|
||||
|
||||
### Step 5: Write Investigation Report
|
||||
|
||||
Generate `investigation-report.json` in memory (carried to next phase):
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": 1,
|
||||
"bug_description": "concise description of the bug",
|
||||
"reproduction": {
|
||||
"reproducible": true,
|
||||
"steps": [
|
||||
"step 1: ...",
|
||||
"step 2: ...",
|
||||
"step 3: observe error"
|
||||
],
|
||||
"reproduction_method": "test|command|static_analysis"
|
||||
},
|
||||
"evidence": {
|
||||
"error_messages": ["exact error text"],
|
||||
"stack_traces": ["relevant stack trace"],
|
||||
"affected_files": ["file1.ts", "file2.ts"],
|
||||
"affected_modules": ["module-name"],
|
||||
"log_output": ["relevant log lines"]
|
||||
},
|
||||
"initial_diagnosis": {
|
||||
"cli_tool_used": "gemini",
|
||||
"top_suspects": [
|
||||
{ "description": "suspect 1", "evidence_strength": "strong|moderate|weak", "files": [] }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **Data**: `investigation-report` (in-memory, passed to Phase 2)
|
||||
- **Format**: JSON structure as defined above
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Bug symptom clearly documented
|
||||
- [ ] Reproduction attempted (success or documented failure)
|
||||
- [ ] At least one piece of concrete evidence collected (error message, stack trace, or failing test)
|
||||
- [ ] Affected files identified
|
||||
- [ ] Initial diagnosis generated
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 2: Pattern Analysis](02-pattern-analysis.md) with the investigation report.
|
||||
126
.claude/skills/investigate/phases/02-pattern-analysis.md
Normal file
126
.claude/skills/investigate/phases/02-pattern-analysis.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Phase 2: Pattern Analysis
|
||||
|
||||
Search for similar patterns in the codebase to determine if the bug is isolated or systemic.
|
||||
|
||||
## Objective
|
||||
|
||||
- Search for similar error patterns, antipatterns, or code smells across the codebase
|
||||
- Determine if the bug is an isolated incident or part of a systemic issue
|
||||
- Identify related code that may be affected by the same root cause
|
||||
- Refine the scope of the investigation
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Search for Similar Error Patterns
|
||||
|
||||
Look for the same error type or message elsewhere in the codebase:
|
||||
|
||||
```javascript
|
||||
// Search for identical or similar error messages
|
||||
Grep({ pattern: "error_message_fragment", path: "src/", output_mode: "content", context: 3 })
|
||||
|
||||
// Search for the same exception/error type
|
||||
Grep({ pattern: "ErrorClassName|error_code", path: "src/", output_mode: "files_with_matches" })
|
||||
|
||||
// Search for similar error handling patterns
|
||||
Grep({ pattern: "catch.*{similar_pattern}", path: "src/", output_mode: "content" })
|
||||
```
|
||||
|
||||
### Step 2: Search for Same Antipattern
|
||||
|
||||
If the initial diagnosis suggests a coding antipattern, search for it globally:
|
||||
|
||||
```javascript
|
||||
// Examples of antipattern searches:
|
||||
// Missing null checks
|
||||
Grep({ pattern: "variable\\.property", path: "src/", glob: "*.ts" })
|
||||
|
||||
// Unchecked async operations
|
||||
Grep({ pattern: "async.*without.*await", path: "src/" })
|
||||
|
||||
// Direct mutation of shared state
|
||||
Grep({ pattern: "shared_state_pattern", path: "src/" })
|
||||
```
|
||||
|
||||
### Step 3: Module-Level Analysis
|
||||
|
||||
Examine the affected module for structural issues:
|
||||
|
||||
```javascript
|
||||
// List all files in the affected module
|
||||
Glob({ pattern: "src/affected-module/**/*" })
|
||||
|
||||
// Check imports and dependencies
|
||||
Grep({ pattern: "import.*from.*affected-module", path: "src/" })
|
||||
|
||||
// Check for circular dependencies or unusual patterns
|
||||
Grep({ pattern: "require.*affected-module", path: "src/" })
|
||||
```
|
||||
|
||||
### Step 4: CLI Cross-File Pattern Analysis (Optional)
|
||||
|
||||
For complex patterns that span multiple files, use CLI analysis:
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Identify all instances of antipattern across codebase; success = complete scope map
|
||||
TASK: Search for pattern '{antipattern_description}' | Map all occurrences | Assess systemic risk
|
||||
MODE: analysis
|
||||
CONTEXT: @src/**/*.{ext} | Bug in {module}, pattern: {pattern_description}
|
||||
EXPECTED: List of all files with same pattern, risk assessment per occurrence
|
||||
CONSTRAINTS: Focus on {antipattern} pattern only | Ignore test files for scope" \
|
||||
--tool gemini --mode analysis
|
||||
```
|
||||
|
||||
### Step 5: Scope Assessment
|
||||
|
||||
Classify the bug scope based on findings:
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": 2,
|
||||
"pattern_analysis": {
|
||||
"scope": "isolated|module-wide|systemic",
|
||||
"similar_occurrences": [
|
||||
{
|
||||
"file": "path/to/file.ts",
|
||||
"line": 42,
|
||||
"pattern": "description of similar pattern",
|
||||
"risk": "same_bug|potential_bug|safe"
|
||||
}
|
||||
],
|
||||
"total_occurrences": 1,
|
||||
"affected_modules": ["module-name"],
|
||||
"antipattern_identified": "description or null",
|
||||
"scope_justification": "why this scope classification"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Scope Definitions**:
|
||||
- **isolated**: Bug exists in a single location, no similar patterns found
|
||||
- **module-wide**: Same pattern exists in multiple files within the same module
|
||||
- **systemic**: Pattern spans multiple modules, may require broader fix
|
||||
|
||||
## Output
|
||||
|
||||
- **Data**: `pattern-analysis` section added to investigation report (in-memory)
|
||||
- **Format**: JSON structure as defined above
|
||||
|
||||
## Decision Point
|
||||
|
||||
| Scope | Action |
|
||||
|-------|--------|
|
||||
| isolated | Proceed to Phase 3 with narrow focus |
|
||||
| module-wide | Proceed to Phase 3, note all occurrences for Phase 4 fix |
|
||||
| systemic | Proceed to Phase 3, but flag for potential multi-phase fix or separate tracking |
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] At least 3 search queries executed against the codebase
|
||||
- [ ] Scope classified as isolated, module-wide, or systemic
|
||||
- [ ] Similar occurrences documented with file:line references
|
||||
- [ ] Scope justification provided with evidence
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 3: Hypothesis Testing](03-hypothesis-testing.md) with the pattern analysis results.
|
||||
177
.claude/skills/investigate/phases/03-hypothesis-testing.md
Normal file
177
.claude/skills/investigate/phases/03-hypothesis-testing.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# Phase 3: Hypothesis Testing
|
||||
|
||||
Form hypotheses from evidence and test each one. Enforce the 3-strike escalation rule.
|
||||
|
||||
## Objective
|
||||
|
||||
- Form a maximum of 3 hypotheses from Phase 1-2 evidence
|
||||
- Test each hypothesis with minimal, read-only probes
|
||||
- Confirm or reject each hypothesis with concrete evidence
|
||||
- Enforce 3-strike rule: STOP and escalate after 3 consecutive test failures
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Form Hypotheses
|
||||
|
||||
Using evidence from Phase 1 (investigation report) and Phase 2 (pattern analysis), form up to 3 ranked hypotheses:
|
||||
|
||||
```json
|
||||
{
|
||||
"hypotheses": [
|
||||
{
|
||||
"id": "H1",
|
||||
"description": "The root cause is X because evidence Y",
|
||||
"evidence_supporting": ["evidence item 1", "evidence item 2"],
|
||||
"predicted_behavior": "If H1 is correct, then we should observe Z",
|
||||
"test_method": "How to verify: read file X line Y, check value Z",
|
||||
"confidence": "high|medium|low"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Hypothesis Formation Rules**:
|
||||
- Each hypothesis must cite at least one piece of evidence from Phase 1-2
|
||||
- Each hypothesis must have a testable prediction
|
||||
- Rank by confidence (high first)
|
||||
- Maximum 3 hypotheses per investigation
|
||||
|
||||
### Step 2: Test Hypotheses Sequentially
|
||||
|
||||
Test each hypothesis starting from highest confidence. Use read-only probes:
|
||||
|
||||
**Allowed test methods**:
|
||||
- `Read` a specific file and check a specific value or condition
|
||||
- `Grep` for a pattern that would confirm or deny the hypothesis
|
||||
- `Bash` to run a specific test or command that reveals the condition
|
||||
- Temporarily add a log statement to observe runtime behavior (revert after)
|
||||
|
||||
**Prohibited during testing**:
|
||||
- Modifying production code (save that for Phase 4)
|
||||
- Changing multiple things at once
|
||||
- Running the full test suite (targeted checks only)
|
||||
|
||||
```javascript
|
||||
// Example hypothesis test
|
||||
// H1: "Function X receives null because caller Y doesn't check return value"
|
||||
const evidence = Read({ file_path: "src/caller.ts" })
|
||||
// Check: Does caller Y use the return value without null check?
|
||||
// Result: Confirmed / Rejected with specific evidence
|
||||
```
|
||||
|
||||
### Step 3: Record Test Results
|
||||
|
||||
For each hypothesis test:
|
||||
|
||||
```json
|
||||
{
|
||||
"hypothesis_tests": [
|
||||
{
|
||||
"id": "H1",
|
||||
"test_performed": "Read src/caller.ts:42 - checked null handling",
|
||||
"result": "confirmed|rejected|inconclusive",
|
||||
"evidence": "specific observation that confirms or rejects",
|
||||
"files_checked": ["src/caller.ts:42-55"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: 3-Strike Escalation Rule
|
||||
|
||||
Track consecutive test failures. A "failure" means the test was inconclusive or the hypothesis was rejected AND no actionable insight was gained.
|
||||
|
||||
```
|
||||
Strike Counter:
|
||||
[H1 rejected, no insight] → Strike 1
|
||||
[H2 rejected, no insight] → Strike 2
|
||||
[H3 rejected, no insight] → Strike 3 → STOP
|
||||
```
|
||||
|
||||
**Important**: A rejected hypothesis that provides useful insight (narrows the search) does NOT count as a strike. Only truly unproductive tests count.
|
||||
|
||||
**On 3rd Strike — STOP and Escalate**:
|
||||
|
||||
```
|
||||
## ESCALATION: 3-Strike Limit Reached
|
||||
|
||||
### Failed Step
|
||||
- Phase: 3 — Hypothesis Testing
|
||||
- Step: Hypothesis test #{N}
|
||||
|
||||
### Error History
|
||||
1. Attempt 1: H1 — {description}
|
||||
Test: {what was checked}
|
||||
Result: {rejected/inconclusive} — {why}
|
||||
2. Attempt 2: H2 — {description}
|
||||
Test: {what was checked}
|
||||
Result: {rejected/inconclusive} — {why}
|
||||
3. Attempt 3: H3 — {description}
|
||||
Test: {what was checked}
|
||||
Result: {rejected/inconclusive} — {why}
|
||||
|
||||
### Current State
|
||||
- Evidence collected: {summary from Phase 1-2}
|
||||
- Hypotheses tested: {list}
|
||||
- Files examined: {list}
|
||||
|
||||
### Diagnosis
|
||||
- Likely root cause area: {best guess based on all evidence}
|
||||
- Suggested human action: {specific recommendation — e.g., "Add logging to X", "Check runtime config Y", "Reproduce in debugger at Z"}
|
||||
|
||||
### Diagnostic Dump
|
||||
{Full investigation-report.json content}
|
||||
```
|
||||
|
||||
After escalation, set status to **BLOCKED** per Completion Status Protocol.
|
||||
|
||||
### Step 5: Confirm Root Cause
|
||||
|
||||
If a hypothesis is confirmed, document the confirmed root cause:
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": 3,
|
||||
"confirmed_root_cause": {
|
||||
"hypothesis_id": "H1",
|
||||
"description": "Root cause description with full evidence chain",
|
||||
"evidence_chain": [
|
||||
"Phase 1: Error message X observed in Y",
|
||||
"Phase 2: Same pattern found in 3 other files",
|
||||
"Phase 3: H1 confirmed — null check missing at file.ts:42"
|
||||
],
|
||||
"affected_code": {
|
||||
"file": "path/to/file.ts",
|
||||
"line_range": "42-55",
|
||||
"function": "functionName"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **Data**: `hypothesis-tests` and `confirmed_root_cause` added to investigation report (in-memory)
|
||||
- **Format**: JSON structure as defined above
|
||||
|
||||
## Gate for Phase 4
|
||||
|
||||
**Phase 4 can ONLY proceed if `confirmed_root_cause` is present.** This is the Iron Law gate.
|
||||
|
||||
| Outcome | Next Step |
|
||||
|---------|-----------|
|
||||
| Root cause confirmed | Proceed to [Phase 4: Implementation](04-implementation.md) |
|
||||
| 3-strike escalation | STOP, output diagnostic dump, status = BLOCKED |
|
||||
| Partial insight | Re-form hypotheses with new evidence (stays in Phase 3) |
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Maximum 3 hypotheses formed, each with cited evidence
|
||||
- [ ] Each hypothesis tested with a specific, documented probe
|
||||
- [ ] Test results recorded with concrete evidence
|
||||
- [ ] 3-strike counter maintained correctly
|
||||
- [ ] Root cause confirmed with full evidence chain OR escalation triggered
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 4: Implementation](04-implementation.md) ONLY with confirmed root cause.
|
||||
139
.claude/skills/investigate/phases/04-implementation.md
Normal file
139
.claude/skills/investigate/phases/04-implementation.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Phase 4: Implementation
|
||||
|
||||
Implement the minimal fix and add a regression test. Iron Law gate enforced.
|
||||
|
||||
## Objective
|
||||
|
||||
- Verify Iron Law gate: confirmed root cause MUST exist from Phase 3
|
||||
- Implement the minimal fix that addresses the confirmed root cause
|
||||
- Add a regression test that fails without the fix and passes with it
|
||||
- Verify the fix resolves the original reproduction case
|
||||
|
||||
## Iron Law Gate Check
|
||||
|
||||
**MANDATORY**: Before any code modification, verify:
|
||||
|
||||
```javascript
|
||||
if (!investigation_report.confirmed_root_cause) {
|
||||
// VIOLATION: Cannot proceed without confirmed root cause
|
||||
// Return to Phase 3 or escalate
|
||||
throw new Error("Iron Law violation: No confirmed root cause. Return to Phase 3.")
|
||||
}
|
||||
|
||||
console.log(`Root cause confirmed: ${investigation_report.confirmed_root_cause.description}`)
|
||||
console.log(`Evidence chain: ${investigation_report.confirmed_root_cause.evidence_chain.length} items`)
|
||||
console.log(`Affected code: ${investigation_report.confirmed_root_cause.affected_code.file}:${investigation_report.confirmed_root_cause.affected_code.line_range}`)
|
||||
```
|
||||
|
||||
If the gate check fails, do NOT proceed. Return status **BLOCKED** with reason "Iron Law: no confirmed root cause".
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Plan the Minimal Fix
|
||||
|
||||
Define the fix scope BEFORE writing any code:
|
||||
|
||||
```json
|
||||
{
|
||||
"fix_plan": {
|
||||
"description": "What the fix does and why",
|
||||
"changes": [
|
||||
{
|
||||
"file": "path/to/file.ts",
|
||||
"change_type": "modify|add|remove",
|
||||
"description": "specific change description",
|
||||
"lines_affected": "42-45"
|
||||
}
|
||||
],
|
||||
"total_files_changed": 1,
|
||||
"total_lines_changed": "estimated"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Minimal Fix Rules** (from [specs/iron-law.md](../specs/iron-law.md)):
|
||||
- Change only what is necessary to fix the confirmed root cause
|
||||
- Do not refactor surrounding code
|
||||
- Do not add features
|
||||
- Do not change formatting or style of unrelated code
|
||||
- If the fix requires changes to more than 3 files, document justification
|
||||
|
||||
### Step 2: Implement the Fix
|
||||
|
||||
Apply the planned changes using `Edit` tool:
|
||||
|
||||
```javascript
|
||||
Edit({
|
||||
file_path: "path/to/affected/file.ts",
|
||||
old_string: "buggy code",
|
||||
new_string: "fixed code"
|
||||
})
|
||||
```
|
||||
|
||||
### Step 3: Add Regression Test
|
||||
|
||||
Create or modify a test that:
|
||||
1. **Fails** without the fix (tests the exact bug condition)
|
||||
2. **Passes** with the fix
|
||||
|
||||
```javascript
|
||||
// Identify existing test file for the module
|
||||
Glob({ pattern: "**/*.test.{ts,js,py}" })
|
||||
// or
|
||||
Glob({ pattern: "**/test_*.py" })
|
||||
|
||||
// Add regression test
|
||||
// Test name should reference the bug: "should handle null return from X"
|
||||
// Test should exercise the exact code path that caused the bug
|
||||
```
|
||||
|
||||
**Regression test requirements**:
|
||||
- Test name clearly describes the bug scenario
|
||||
- Test exercises the specific code path identified in root cause
|
||||
- Test is deterministic (no flaky timing, external dependencies)
|
||||
- Test is placed in the appropriate test file for the module
|
||||
|
||||
### Step 4: Verify Fix Against Reproduction
|
||||
|
||||
Re-run the original reproduction case from Phase 1:
|
||||
|
||||
```bash
|
||||
# Run the specific failing test/command from Phase 1
|
||||
# It should now pass
|
||||
```
|
||||
|
||||
Record the verification result:
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": 4,
|
||||
"fix_applied": {
|
||||
"description": "what was fixed",
|
||||
"files_changed": ["path/to/file.ts"],
|
||||
"lines_changed": 3,
|
||||
"regression_test": {
|
||||
"file": "path/to/test.ts",
|
||||
"test_name": "should handle null return from X",
|
||||
"status": "added|modified"
|
||||
},
|
||||
"reproduction_verified": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **Data**: `fix_applied` section added to investigation report (in-memory)
|
||||
- **Artifacts**: Modified source files and test files
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Iron Law gate passed: confirmed root cause exists
|
||||
- [ ] Fix is minimal: only necessary changes made
|
||||
- [ ] Regression test added that covers the specific bug
|
||||
- [ ] Original reproduction case passes with the fix
|
||||
- [ ] No unrelated code changes included
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 5: Verification & Report](05-verification-report.md) to run full test suite and generate report.
|
||||
153
.claude/skills/investigate/phases/05-verification-report.md
Normal file
153
.claude/skills/investigate/phases/05-verification-report.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Phase 5: Verification & Report
|
||||
|
||||
Run full test suite, check for regressions, and generate the structured debug report.
|
||||
|
||||
## Objective
|
||||
|
||||
- Run the full test suite to verify no regressions were introduced
|
||||
- Generate a structured debug report for future reference
|
||||
- Output the report to `.workflow/.debug/` directory
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Run Full Test Suite
|
||||
|
||||
```bash
|
||||
# Detect and run the project's test framework
|
||||
# npm test / pytest / go test / cargo test / etc.
|
||||
```
|
||||
|
||||
Record results:
|
||||
|
||||
```json
|
||||
{
|
||||
"test_results": {
|
||||
"total": 0,
|
||||
"passed": 0,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"regression_test_passed": true,
|
||||
"new_failures": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**If new failures are found**:
|
||||
- Check if the failures are related to the fix
|
||||
- If related: the fix introduced a regression — return to Phase 4 to adjust
|
||||
- If unrelated: document as pre-existing failures, proceed with report
|
||||
|
||||
### Step 2: Regression Check
|
||||
|
||||
Verify specifically:
|
||||
1. The new regression test passes
|
||||
2. All tests that passed before the fix still pass
|
||||
3. No new warnings or errors in test output
|
||||
|
||||
### Step 3: Generate Structured Debug Report
|
||||
|
||||
Create the report following the schema in [specs/debug-report-format.md](../specs/debug-report-format.md):
|
||||
|
||||
```bash
|
||||
mkdir -p .workflow/.debug
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"bug_description": "concise description of the bug",
|
||||
"reproduction_steps": [
|
||||
"step 1",
|
||||
"step 2",
|
||||
"step 3: observe error"
|
||||
],
|
||||
"root_cause": "confirmed root cause description with technical detail",
|
||||
"evidence_chain": [
|
||||
"Phase 1: error message X observed in module Y",
|
||||
"Phase 2: pattern analysis found N similar occurrences",
|
||||
"Phase 3: hypothesis H1 confirmed — specific condition at file:line"
|
||||
],
|
||||
"fix_description": "what was changed and why",
|
||||
"files_changed": [
|
||||
{
|
||||
"path": "src/module/file.ts",
|
||||
"change_type": "modify",
|
||||
"description": "added null check before property access"
|
||||
}
|
||||
],
|
||||
"tests_added": [
|
||||
{
|
||||
"file": "src/module/__tests__/file.test.ts",
|
||||
"test_name": "should handle null return from X",
|
||||
"type": "regression"
|
||||
}
|
||||
],
|
||||
"regression_check_result": {
|
||||
"passed": true,
|
||||
"total_tests": 0,
|
||||
"new_failures": [],
|
||||
"pre_existing_failures": []
|
||||
},
|
||||
"completion_status": "DONE|DONE_WITH_CONCERNS|BLOCKED",
|
||||
"concerns": [],
|
||||
"timestamp": "ISO-8601",
|
||||
"investigation_duration_phases": 5
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Write Report File
|
||||
|
||||
```javascript
|
||||
const slug = bugDescription.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
|
||||
const dateStr = new Date().toISOString().substring(0, 10)
|
||||
const reportPath = `.workflow/.debug/debug-report-${dateStr}-${slug}.json`
|
||||
|
||||
Write({ file_path: reportPath, content: JSON.stringify(report, null, 2) })
|
||||
```
|
||||
|
||||
### Step 5: Output Completion Status
|
||||
|
||||
Follow the Completion Status Protocol from `_shared/SKILL-DESIGN-SPEC.md` section 13:
|
||||
|
||||
**DONE**:
|
||||
```
|
||||
## STATUS: DONE
|
||||
|
||||
**Summary**: Fixed {bug_description} — root cause was {root_cause_summary}
|
||||
|
||||
### Details
|
||||
- Phases completed: 5/5
|
||||
- Root cause: {confirmed_root_cause}
|
||||
- Fix: {fix_description}
|
||||
- Regression test: {test_name} in {test_file}
|
||||
|
||||
### Outputs
|
||||
- Debug report: {reportPath}
|
||||
- Files changed: {list}
|
||||
- Tests added: {list}
|
||||
```
|
||||
|
||||
**DONE_WITH_CONCERNS**:
|
||||
```
|
||||
## STATUS: DONE_WITH_CONCERNS
|
||||
|
||||
**Summary**: Fixed {bug_description} with concerns
|
||||
|
||||
### Details
|
||||
- Phases completed: 5/5
|
||||
- Concerns:
|
||||
1. {concern} — Impact: {low|medium} — Suggested fix: {action}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **File**: `debug-report-{YYYY-MM-DD}-{slug}.json`
|
||||
- **Location**: `.workflow/.debug/`
|
||||
- **Format**: JSON (see [specs/debug-report-format.md](../specs/debug-report-format.md))
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- [ ] Full test suite executed
|
||||
- [ ] Regression test specifically verified
|
||||
- [ ] No new test failures introduced (or documented if pre-existing)
|
||||
- [ ] Debug report written to `.workflow/.debug/`
|
||||
- [ ] Completion status output follows protocol
|
||||
226
.claude/skills/investigate/specs/debug-report-format.md
Normal file
226
.claude/skills/investigate/specs/debug-report-format.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Debug Report Format
|
||||
|
||||
Defines the structured JSON schema for debug reports generated by the investigate skill.
|
||||
|
||||
## When to Use
|
||||
|
||||
| Phase | Usage | Section |
|
||||
|-------|-------|---------|
|
||||
| Phase 5 | Generate final report | Full schema |
|
||||
| Phase 3 (escalation) | Diagnostic dump includes partial report | Partial schema |
|
||||
|
||||
---
|
||||
|
||||
## JSON Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Debug Report",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"bug_description",
|
||||
"reproduction_steps",
|
||||
"root_cause",
|
||||
"evidence_chain",
|
||||
"fix_description",
|
||||
"files_changed",
|
||||
"tests_added",
|
||||
"regression_check_result",
|
||||
"completion_status"
|
||||
],
|
||||
"properties": {
|
||||
"bug_description": {
|
||||
"type": "string",
|
||||
"description": "Concise description of the bug symptom",
|
||||
"minLength": 10
|
||||
},
|
||||
"reproduction_steps": {
|
||||
"type": "array",
|
||||
"description": "Ordered steps to reproduce the bug",
|
||||
"items": { "type": "string" },
|
||||
"minItems": 1
|
||||
},
|
||||
"root_cause": {
|
||||
"type": "string",
|
||||
"description": "Confirmed root cause with technical detail",
|
||||
"minLength": 20
|
||||
},
|
||||
"evidence_chain": {
|
||||
"type": "array",
|
||||
"description": "Ordered evidence from Phase 1 through Phase 3, each prefixed with phase number",
|
||||
"items": { "type": "string" },
|
||||
"minItems": 1
|
||||
},
|
||||
"fix_description": {
|
||||
"type": "string",
|
||||
"description": "What was changed and why",
|
||||
"minLength": 10
|
||||
},
|
||||
"files_changed": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["path", "change_type", "description"],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Relative file path"
|
||||
},
|
||||
"change_type": {
|
||||
"type": "string",
|
||||
"enum": ["add", "modify", "remove"]
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Brief description of changes to this file"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tests_added": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["file", "test_name", "type"],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Test file path"
|
||||
},
|
||||
"test_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the test function or describe block"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["regression", "unit", "integration"],
|
||||
"description": "Type of test added"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"regression_check_result": {
|
||||
"type": "object",
|
||||
"required": ["passed", "total_tests"],
|
||||
"properties": {
|
||||
"passed": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the full test suite passed"
|
||||
},
|
||||
"total_tests": {
|
||||
"type": "integer",
|
||||
"description": "Total number of tests executed"
|
||||
},
|
||||
"new_failures": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Tests that failed after the fix but passed before"
|
||||
},
|
||||
"pre_existing_failures": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Tests that were already failing before the investigation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"completion_status": {
|
||||
"type": "string",
|
||||
"enum": ["DONE", "DONE_WITH_CONCERNS", "BLOCKED"],
|
||||
"description": "Final status per Completion Status Protocol"
|
||||
},
|
||||
"concerns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": { "type": "string" },
|
||||
"impact": { "type": "string", "enum": ["low", "medium"] },
|
||||
"suggested_action": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"description": "Non-blocking concerns (populated when status is DONE_WITH_CONCERNS)"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO-8601 timestamp of report generation"
|
||||
},
|
||||
"investigation_duration_phases": {
|
||||
"type": "integer",
|
||||
"description": "Number of phases completed (1-5)",
|
||||
"minimum": 1,
|
||||
"maximum": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Field Descriptions
|
||||
|
||||
| Field | Source Phase | Description |
|
||||
|-------|-------------|-------------|
|
||||
| `bug_description` | Phase 1 | User-reported symptom, one sentence |
|
||||
| `reproduction_steps` | Phase 1 | Ordered steps to trigger the bug |
|
||||
| `root_cause` | Phase 3 | Confirmed cause with file:line reference |
|
||||
| `evidence_chain` | Phase 1-3 | Each item prefixed with "Phase N:" |
|
||||
| `fix_description` | Phase 4 | What code was changed and why |
|
||||
| `files_changed` | Phase 4 | Each file with change type and description |
|
||||
| `tests_added` | Phase 4 | Regression tests covering the bug |
|
||||
| `regression_check_result` | Phase 5 | Full test suite results |
|
||||
| `completion_status` | Phase 5 | Final status per protocol |
|
||||
| `concerns` | Phase 5 | Non-blocking issues (if any) |
|
||||
| `timestamp` | Phase 5 | When report was generated |
|
||||
| `investigation_duration_phases` | Phase 5 | How many phases were completed |
|
||||
|
||||
## Example Report
|
||||
|
||||
```json
|
||||
{
|
||||
"bug_description": "API returns 500 when user profile has null display_name",
|
||||
"reproduction_steps": [
|
||||
"Create user account without setting display_name",
|
||||
"Call GET /api/users/:id/profile",
|
||||
"Observe 500 Internal Server Error"
|
||||
],
|
||||
"root_cause": "ProfileSerializer.format() calls displayName.trim() without null check at src/serializers/profile.ts:42",
|
||||
"evidence_chain": [
|
||||
"Phase 1: TypeError: Cannot read properties of null (reading 'trim') in server logs",
|
||||
"Phase 2: Same pattern in 2 other serializers (address.ts:28, company.ts:35)",
|
||||
"Phase 3: H1 confirmed — displayName field is nullable in DB but serializer assumes non-null"
|
||||
],
|
||||
"fix_description": "Added null-safe access for displayName in ProfileSerializer.format()",
|
||||
"files_changed": [
|
||||
{
|
||||
"path": "src/serializers/profile.ts",
|
||||
"change_type": "modify",
|
||||
"description": "Added optional chaining for displayName.trim() call"
|
||||
}
|
||||
],
|
||||
"tests_added": [
|
||||
{
|
||||
"file": "src/serializers/__tests__/profile.test.ts",
|
||||
"test_name": "should handle null display_name without error",
|
||||
"type": "regression"
|
||||
}
|
||||
],
|
||||
"regression_check_result": {
|
||||
"passed": true,
|
||||
"total_tests": 142,
|
||||
"new_failures": [],
|
||||
"pre_existing_failures": []
|
||||
},
|
||||
"completion_status": "DONE",
|
||||
"concerns": [],
|
||||
"timestamp": "2026-03-29T15:30:00+08:00",
|
||||
"investigation_duration_phases": 5
|
||||
}
|
||||
```
|
||||
|
||||
## Output Location
|
||||
|
||||
Reports are written to: `.workflow/.debug/debug-report-{YYYY-MM-DD}-{slug}.json`
|
||||
|
||||
Where:
|
||||
- `{YYYY-MM-DD}` is the investigation date
|
||||
- `{slug}` is derived from the bug description (lowercase, hyphens, max 40 chars)
|
||||
101
.claude/skills/investigate/specs/iron-law.md
Normal file
101
.claude/skills/investigate/specs/iron-law.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Iron Law of Debugging
|
||||
|
||||
The Iron Law defines the non-negotiable rules that govern every investigation performed by this skill. These rules exist to prevent symptom-fixing and ensure durable, evidence-based solutions.
|
||||
|
||||
## When to Use
|
||||
|
||||
| Phase | Usage | Section |
|
||||
|-------|-------|---------|
|
||||
| Phase 3 | Hypothesis must produce confirmed root cause before proceeding | Rule 1 |
|
||||
| Phase 1 | Reproduction must produce observable evidence | Rule 2 |
|
||||
| Phase 4 | Fix scope must be minimal | Rule 3 |
|
||||
| Phase 4 | Regression test is mandatory | Rule 4 |
|
||||
| Phase 3 | 3 consecutive unproductive hypothesis failures trigger escalation | Rule 5 |
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
### Rule 1: Never Fix Without Confirmed Root Cause
|
||||
|
||||
**Statement**: No code modification is permitted until a root cause has been confirmed through hypothesis testing with concrete evidence.
|
||||
|
||||
**Enforcement**: Phase 4 begins with an Iron Law gate check. If `confirmed_root_cause` is absent from the investigation report, Phase 4 is blocked.
|
||||
|
||||
**Rationale**: Fixing symptoms without understanding the cause leads to:
|
||||
- Incomplete fixes that break under different conditions
|
||||
- Masking of deeper issues
|
||||
- Wasted investigation time when the bug recurs
|
||||
|
||||
### Rule 2: Evidence Must Be Reproducible
|
||||
|
||||
**Statement**: The bug must be reproducible through documented steps, or if not reproducible, the evidence must be sufficient to identify the root cause through static analysis.
|
||||
|
||||
**Enforcement**: Phase 1 documents reproduction steps and evidence. If reproduction fails, this is flagged as a concern but does not block investigation if sufficient static evidence exists.
|
||||
|
||||
**Acceptable evidence types**:
|
||||
- Failing test case
|
||||
- Error message with stack trace
|
||||
- Log output showing the failure
|
||||
- Code path analysis showing the defect condition
|
||||
|
||||
### Rule 3: Fix Must Be Minimal
|
||||
|
||||
**Statement**: The fix must change only what is necessary to address the confirmed root cause. No refactoring, no feature additions, no style changes to unrelated code.
|
||||
|
||||
**Enforcement**: Phase 4 requires a fix plan before implementation. Changes exceeding 3 files require written justification.
|
||||
|
||||
**What counts as minimal**:
|
||||
- Adding a missing null check
|
||||
- Fixing an incorrect condition
|
||||
- Correcting a wrong variable reference
|
||||
- Adding a missing import or dependency
|
||||
|
||||
**What is NOT minimal**:
|
||||
- Refactoring the function "while we're here"
|
||||
- Renaming variables for clarity
|
||||
- Adding error handling to unrelated code paths
|
||||
- Reformatting surrounding code
|
||||
|
||||
### Rule 4: Regression Test Required
|
||||
|
||||
**Statement**: Every fix must include a test that:
|
||||
1. Fails when the fix is reverted (proves it tests the bug)
|
||||
2. Passes when the fix is applied (proves the fix works)
|
||||
|
||||
**Enforcement**: Phase 4 requires a regression test before the phase is marked complete.
|
||||
|
||||
**Test requirements**:
|
||||
- Test name clearly references the bug scenario
|
||||
- Test exercises the exact code path of the root cause
|
||||
- Test is deterministic (no timing dependencies, no external services)
|
||||
- Test is placed in the appropriate test file for the affected module
|
||||
|
||||
### Rule 5: 3-Strike Escalation on Hypothesis Failure
|
||||
|
||||
**Statement**: If 3 consecutive hypothesis tests produce no actionable insight, the investigation must STOP and escalate with a full diagnostic dump.
|
||||
|
||||
**Enforcement**: Phase 3 tracks a strike counter. On the 3rd consecutive unproductive failure, execution halts and outputs the escalation block.
|
||||
|
||||
**What counts as a strike**:
|
||||
- Hypothesis rejected AND no new insight gained
|
||||
- Test was inconclusive AND no narrowing of search space
|
||||
|
||||
**What does NOT count as a strike**:
|
||||
- Hypothesis rejected BUT new evidence narrows the search
|
||||
- Hypothesis rejected BUT reveals a different potential cause
|
||||
- Test inconclusive BUT identifies a new area to investigate
|
||||
|
||||
**Post-escalation**: Status set to BLOCKED. No further automated investigation. Preserve all intermediate outputs for human review.
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
Before completing any investigation, verify:
|
||||
|
||||
- [ ] Rule 1: Root cause confirmed before any fix was applied
|
||||
- [ ] Rule 2: Bug reproduction documented (or static evidence justified)
|
||||
- [ ] Rule 3: Fix changes only necessary code (file count, line count documented)
|
||||
- [ ] Rule 4: Regression test exists and passes
|
||||
- [ ] Rule 5: No more than 3 consecutive unproductive hypothesis tests (or escalation triggered)
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: review-cycle
|
||||
description: Unified multi-dimensional code review with automated fix orchestration. Routes to session-based (git changes), module-based (path patterns), or fix mode. Triggers on "workflow:review-cycle", "workflow:review-session-cycle", "workflow:review-module-cycle", "workflow:review-cycle-fix".
|
||||
description: "Unified multi-dimensional code review with automated fix orchestration. Routes to session-based (git changes), module-based (path patterns), or fix mode. Triggers on \"workflow:review-cycle\", \"workflow:review-session-cycle\", \"workflow:review-module-cycle\", \"workflow:review-cycle-fix\"."
|
||||
allowed-tools: Agent, AskUserQuestion, TaskCreate, TaskUpdate, TaskList, Read, Write, Edit, Bash, Glob, Grep, Skill
|
||||
---
|
||||
|
||||
|
||||
@@ -401,7 +401,7 @@ Task(
|
||||
1. Read review state: ${reviewStateJsonPath}
|
||||
2. Get target files: Read resolved_files from review-state.json
|
||||
3. Validate file access: bash(ls -la ${targetFiles.join(' ')})
|
||||
4. Execute: cat ~/.ccw/workflows/cli-templates/schemas/review-dimension-results-schema.json (get output schema reference)
|
||||
4. Execute: ccw tool exec json_builder '{"cmd":"info","schema":"review-dim"}' (get output schema summary)
|
||||
5. Read: .workflow/project-tech.json (technology stack and architecture context)
|
||||
6. Read: .workflow/specs/*.md (user-defined constraints and conventions to validate against)
|
||||
|
||||
@@ -456,7 +456,7 @@ Task(
|
||||
${getDimensionGuidance(dimension)}
|
||||
|
||||
## Success Criteria
|
||||
- [ ] Schema obtained via cat review-dimension-results-schema.json
|
||||
- [ ] Schema obtained via json_builder info
|
||||
- [ ] All target files analyzed for ${dimension} concerns
|
||||
- [ ] All findings include file:line references with code snippets
|
||||
- [ ] Severity assessment follows established criteria (see reference)
|
||||
@@ -505,7 +505,7 @@ Task(
|
||||
2. Read affected file: ${file}
|
||||
3. Identify related code: bash(grep -r "import.*${basename(file)}" ${projectDir}/src --include="*.ts")
|
||||
4. Read test files: bash(find ${projectDir}/tests -name "*${basename(file, '.ts')}*" -type f)
|
||||
5. Execute: cat ~/.ccw/workflows/cli-templates/schemas/review-deep-dive-results-schema.json (get output schema reference)
|
||||
5. Execute: ccw tool exec json_builder '{"cmd":"info","schema":"review-deep"}' (get output schema summary)
|
||||
6. Read: .workflow/project-tech.json (technology stack and architecture context)
|
||||
7. Read: .workflow/specs/*.md (user-defined constraints for remediation compliance)
|
||||
|
||||
@@ -538,7 +538,7 @@ Task(
|
||||
- Impact assessment and rollback strategy
|
||||
|
||||
## Success Criteria
|
||||
- [ ] Schema obtained via cat review-deep-dive-results-schema.json
|
||||
- [ ] Schema obtained via json_builder info
|
||||
- [ ] Root cause clearly identified with supporting evidence
|
||||
- [ ] Remediation plan is step-by-step actionable with exact file:line references
|
||||
- [ ] Each step includes specific commands and validation tests
|
||||
|
||||
@@ -412,7 +412,7 @@ Task(
|
||||
2. Read completed task summaries: bash(find ${summariesDir} -name "IMPL-*.md" -type f)
|
||||
3. Get changed files: bash(cd ${workflowDir} && git log --since="${sessionCreatedAt}" --name-only --pretty=format: | sort -u)
|
||||
4. Read review state: ${reviewStateJsonPath}
|
||||
5. Execute: cat ~/.ccw/workflows/cli-templates/schemas/review-dimension-results-schema.json (get output schema reference)
|
||||
5. Execute: ccw tool exec json_builder '{"cmd":"info","schema":"review-dim"}' (get output schema summary)
|
||||
6. Read: .workflow/project-tech.json (technology stack and architecture context)
|
||||
7. Read: .workflow/specs/*.md (user-defined constraints and conventions to validate against)
|
||||
|
||||
@@ -467,7 +467,7 @@ Task(
|
||||
${getDimensionGuidance(dimension)}
|
||||
|
||||
## Success Criteria
|
||||
- [ ] Schema obtained via cat review-dimension-results-schema.json
|
||||
- [ ] Schema obtained via json_builder info
|
||||
- [ ] All changed files analyzed for ${dimension} concerns
|
||||
- [ ] All findings include file:line references with code snippets
|
||||
- [ ] Severity assessment follows established criteria (see reference)
|
||||
@@ -516,7 +516,7 @@ Task(
|
||||
2. Read affected file: ${file}
|
||||
3. Identify related code: bash(grep -r "import.*${basename(file)}" ${workflowDir}/src --include="*.ts")
|
||||
4. Read test files: bash(find ${workflowDir}/tests -name "*${basename(file, '.ts')}*" -type f)
|
||||
5. Execute: cat ~/.ccw/workflows/cli-templates/schemas/review-deep-dive-results-schema.json (get output schema reference)
|
||||
5. Execute: ccw tool exec json_builder '{"cmd":"info","schema":"review-deep"}' (get output schema summary)
|
||||
6. Read: .workflow/project-tech.json (technology stack and architecture context)
|
||||
7. Read: .workflow/specs/*.md (user-defined constraints for remediation compliance)
|
||||
|
||||
@@ -550,7 +550,7 @@ Task(
|
||||
- Impact assessment and rollback strategy
|
||||
|
||||
## Success Criteria
|
||||
- [ ] Schema obtained via cat review-deep-dive-results-schema.json
|
||||
- [ ] Schema obtained via json_builder info
|
||||
- [ ] Root cause clearly identified with supporting evidence
|
||||
- [ ] Remediation plan is step-by-step actionable with exact file:line references
|
||||
- [ ] Each step includes specific commands and validation tests
|
||||
|
||||
125
.claude/skills/security-audit/SKILL.md
Normal file
125
.claude/skills/security-audit/SKILL.md
Normal file
@@ -0,0 +1,125 @@
|
||||
---
|
||||
name: security-audit
|
||||
description: OWASP Top 10 and STRIDE security auditing with supply chain analysis. Triggers on "security audit", "security scan", "cso".
|
||||
allowed-tools: Read, Write, Bash, Glob, Grep
|
||||
---
|
||||
|
||||
# Security Audit
|
||||
|
||||
4-phase security audit covering supply chain risks, OWASP Top 10 code review, STRIDE threat modeling, and trend-tracked reporting. Produces structured JSON findings in `.workflow/.security/`.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
+-------------------------------------------------------------------+
|
||||
| Phase 1: Supply Chain Scan |
|
||||
| -> Dependency audit, secrets detection, CI/CD review, LLM risks |
|
||||
| -> Output: supply-chain-report.json |
|
||||
+-----------------------------------+-------------------------------+
|
||||
|
|
||||
+-----------------------------------v-------------------------------+
|
||||
| Phase 2: OWASP Review |
|
||||
| -> OWASP Top 10 2021 code-level analysis via ccw cli |
|
||||
| -> Output: owasp-findings.json |
|
||||
+-----------------------------------+-------------------------------+
|
||||
|
|
||||
+-----------------------------------v-------------------------------+
|
||||
| Phase 3: Threat Modeling (STRIDE) |
|
||||
| -> 6 threat categories mapped to architecture components |
|
||||
| -> Output: threat-model.json |
|
||||
+-----------------------------------+-------------------------------+
|
||||
|
|
||||
+-----------------------------------v-------------------------------+
|
||||
| Phase 4: Report & Tracking |
|
||||
| -> Score calculation, trend comparison, dated report |
|
||||
| -> Output: .workflow/.security/audit-report-{date}.json |
|
||||
+-------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## Key Design Principles
|
||||
|
||||
1. **Infrastructure-first**: Phase 1 catches low-hanging fruit (leaked secrets, vulnerable deps) before deeper analysis
|
||||
2. **Standards-based**: OWASP Top 10 2021 and STRIDE provide systematic coverage
|
||||
3. **Scoring gates**: Daily quick-scan must score 8/10; comprehensive audit minimum 2/10 for initial baseline
|
||||
4. **Trend tracking**: Each audit compares against prior results in `.workflow/.security/`
|
||||
|
||||
## Execution Flow
|
||||
|
||||
### Quick-Scan Mode (daily)
|
||||
|
||||
Run Phase 1 only. Must score >= 8/10 to pass.
|
||||
|
||||
### Comprehensive Mode (full audit)
|
||||
|
||||
Run all 4 phases sequentially. Initial baseline minimum 2/10.
|
||||
|
||||
### Phase Sequence
|
||||
|
||||
1. **Phase 1: Supply Chain Scan** -- [phases/01-supply-chain-scan.md](phases/01-supply-chain-scan.md)
|
||||
- Dependency audit (npm audit / pip-audit / safety check)
|
||||
- Secrets detection (API keys, tokens, passwords in source)
|
||||
- CI/CD config review (injection risks in workflow YAML)
|
||||
- LLM/AI prompt injection check
|
||||
2. **Phase 2: OWASP Review** -- [phases/02-owasp-review.md](phases/02-owasp-review.md)
|
||||
- Systematic OWASP Top 10 2021 code review
|
||||
- Uses `ccw cli --tool gemini --mode analysis --rule analysis-assess-security-risks`
|
||||
3. **Phase 3: Threat Modeling** -- [phases/03-threat-modeling.md](phases/03-threat-modeling.md)
|
||||
- STRIDE threat model mapped to architecture components
|
||||
- Trust boundary identification and attack surface assessment
|
||||
4. **Phase 4: Report & Tracking** -- [phases/04-report-tracking.md](phases/04-report-tracking.md)
|
||||
- Score calculation with severity weights
|
||||
- Trend comparison with previous audits
|
||||
- Date-stamped report to `.workflow/.security/`
|
||||
|
||||
## Scoring Overview
|
||||
|
||||
See [specs/scoring-gates.md](specs/scoring-gates.md) for full specification.
|
||||
|
||||
| Severity | Weight | Example |
|
||||
|----------|--------|---------|
|
||||
| Critical | 10 | RCE, SQL injection, leaked credentials |
|
||||
| High | 7 | Broken auth, SSRF, privilege escalation |
|
||||
| Medium | 4 | XSS, CSRF, verbose error messages |
|
||||
| Low | 1 | Missing headers, informational disclosures |
|
||||
|
||||
**Gates**: Daily quick-scan >= 8/10, Comprehensive initial >= 2/10.
|
||||
|
||||
## Directory Setup
|
||||
|
||||
```bash
|
||||
mkdir -p .workflow/.security
|
||||
WORK_DIR=".workflow/.security"
|
||||
```
|
||||
|
||||
## Output Structure
|
||||
|
||||
```
|
||||
.workflow/.security/
|
||||
audit-report-{YYYY-MM-DD}.json # Dated audit report
|
||||
supply-chain-report.json # Latest supply chain scan
|
||||
owasp-findings.json # Latest OWASP findings
|
||||
threat-model.json # Latest STRIDE threat model
|
||||
```
|
||||
|
||||
## Reference Documents
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| [phases/01-supply-chain-scan.md](phases/01-supply-chain-scan.md) | Dependency, secrets, CI/CD, LLM risk scan |
|
||||
| [phases/02-owasp-review.md](phases/02-owasp-review.md) | OWASP Top 10 2021 code review |
|
||||
| [phases/03-threat-modeling.md](phases/03-threat-modeling.md) | STRIDE threat modeling |
|
||||
| [phases/04-report-tracking.md](phases/04-report-tracking.md) | Report generation and trend tracking |
|
||||
| [specs/scoring-gates.md](specs/scoring-gates.md) | Scoring system and quality gates |
|
||||
| [specs/owasp-checklist.md](specs/owasp-checklist.md) | OWASP Top 10 detection patterns |
|
||||
|
||||
## Completion Status Protocol
|
||||
|
||||
This skill follows the Completion Status Protocol defined in `_shared/SKILL-DESIGN-SPEC.md` sections 13-14.
|
||||
|
||||
Possible termination statuses:
|
||||
- **DONE**: All phases completed, score calculated, report generated
|
||||
- **DONE_WITH_CONCERNS**: Audit completed but findings exceed acceptable thresholds
|
||||
- **BLOCKED**: Required tools unavailable (e.g., npm/pip not installed), permission denied
|
||||
- **NEEDS_CONTEXT**: Ambiguous project scope, unclear trust boundaries
|
||||
|
||||
Escalation follows the Three-Strike Rule (section 14) per step.
|
||||
139
.claude/skills/security-audit/phases/01-supply-chain-scan.md
Normal file
139
.claude/skills/security-audit/phases/01-supply-chain-scan.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Phase 1: Supply Chain Scan
|
||||
|
||||
Detect low-hanging security risks in dependencies, secrets, CI/CD pipelines, and LLM/AI integrations.
|
||||
|
||||
## Objective
|
||||
|
||||
- Audit third-party dependencies for known vulnerabilities
|
||||
- Scan source code for leaked secrets and credentials
|
||||
- Review CI/CD configuration for injection risks
|
||||
- Check for LLM/AI prompt injection vulnerabilities
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Dependency Audit
|
||||
|
||||
Detect package manager and run appropriate audit tool.
|
||||
|
||||
```bash
|
||||
# Node.js projects
|
||||
if [ -f package-lock.json ] || [ -f yarn.lock ]; then
|
||||
npm audit --json > "${WORK_DIR}/npm-audit-raw.json" 2>&1 || true
|
||||
fi
|
||||
|
||||
# Python projects
|
||||
if [ -f requirements.txt ] || [ -f pyproject.toml ]; then
|
||||
pip-audit --format json --output "${WORK_DIR}/pip-audit-raw.json" 2>&1 || true
|
||||
# Fallback: safety check
|
||||
safety check --json > "${WORK_DIR}/safety-raw.json" 2>&1 || true
|
||||
fi
|
||||
|
||||
# Go projects
|
||||
if [ -f go.sum ]; then
|
||||
govulncheck ./... 2>&1 | tee "${WORK_DIR}/govulncheck-raw.txt" || true
|
||||
fi
|
||||
```
|
||||
|
||||
If audit tools are not installed, log as INFO finding and continue.
|
||||
|
||||
### Step 2: Secrets Detection
|
||||
|
||||
Scan source files for hardcoded secrets using regex patterns.
|
||||
|
||||
```bash
|
||||
# High-confidence patterns (case-insensitive)
|
||||
grep -rniE \
|
||||
'(api[_-]?key|api[_-]?secret|access[_-]?token|auth[_-]?token|secret[_-]?key)\s*[:=]\s*["\x27][A-Za-z0-9+/=_-]{16,}' \
|
||||
--include='*.ts' --include='*.js' --include='*.py' --include='*.go' \
|
||||
--include='*.java' --include='*.rb' --include='*.env' --include='*.yml' \
|
||||
--include='*.yaml' --include='*.json' --include='*.toml' --include='*.cfg' \
|
||||
. || true
|
||||
|
||||
# AWS patterns
|
||||
grep -rniE '(AKIA[0-9A-Z]{16}|aws[_-]?secret[_-]?access[_-]?key)' . || true
|
||||
|
||||
# Private keys
|
||||
grep -rniE '-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----' . || true
|
||||
|
||||
# Connection strings with passwords
|
||||
grep -rniE '(mongodb|postgres|mysql|redis)://[^:]+:[^@]+@' . || true
|
||||
|
||||
# JWT tokens (hardcoded)
|
||||
grep -rniE 'eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}' . || true
|
||||
```
|
||||
|
||||
Exclude: `node_modules/`, `.git/`, `dist/`, `build/`, `__pycache__/`, `*.lock`, `*.min.js`.
|
||||
|
||||
### Step 3: CI/CD Config Review
|
||||
|
||||
Check GitHub Actions and other CI/CD configs for injection risks.
|
||||
|
||||
```bash
|
||||
# Find workflow files
|
||||
find .github/workflows -name '*.yml' -o -name '*.yaml' 2>/dev/null
|
||||
|
||||
# Check for expression injection in run: blocks
|
||||
# Dangerous: ${{ github.event.pull_request.title }} in run:
|
||||
grep -rn '\${{.*github\.event\.' .github/workflows/ 2>/dev/null || true
|
||||
|
||||
# Check for pull_request_target with checkout of PR code
|
||||
grep -rn 'pull_request_target' .github/workflows/ 2>/dev/null || true
|
||||
|
||||
# Check for use of deprecated/vulnerable actions
|
||||
grep -rn 'actions/checkout@v1\|actions/checkout@v2' .github/workflows/ 2>/dev/null || true
|
||||
|
||||
# Check for secrets passed to untrusted contexts
|
||||
grep -rn 'secrets\.' .github/workflows/ 2>/dev/null || true
|
||||
```
|
||||
|
||||
### Step 4: LLM/AI Prompt Injection Check
|
||||
|
||||
Scan for patterns indicating prompt injection risk in LLM integrations.
|
||||
|
||||
```bash
|
||||
# User input concatenated directly into prompts
|
||||
grep -rniE '(prompt|system_message|messages)\s*[+=].*\b(user_input|request\.(body|query|params)|req\.)' \
|
||||
--include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
|
||||
# Template strings with user data in LLM calls
|
||||
grep -rniE '(openai|anthropic|llm|chat|completion)\.' \
|
||||
--include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
|
||||
# Check for missing input sanitization before LLM calls
|
||||
grep -rniE 'f".*{.*}.*".*\.(chat|complete|generate)' \
|
||||
--include='*.py' . || true
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **File**: `supply-chain-report.json`
|
||||
- **Location**: `${WORK_DIR}/supply-chain-report.json`
|
||||
- **Format**: JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": "supply-chain-scan",
|
||||
"timestamp": "ISO-8601",
|
||||
"findings": [
|
||||
{
|
||||
"category": "dependency|secret|cicd|llm",
|
||||
"severity": "critical|high|medium|low",
|
||||
"title": "Finding title",
|
||||
"description": "Detailed description",
|
||||
"file": "path/to/file",
|
||||
"line": 42,
|
||||
"evidence": "matched text or context",
|
||||
"remediation": "How to fix"
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"total": 0,
|
||||
"by_severity": { "critical": 0, "high": 0, "medium": 0, "low": 0 },
|
||||
"by_category": { "dependency": 0, "secret": 0, "cicd": 0, "llm": 0 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 2: OWASP Review](02-owasp-review.md) with supply chain findings as context.
|
||||
156
.claude/skills/security-audit/phases/02-owasp-review.md
Normal file
156
.claude/skills/security-audit/phases/02-owasp-review.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Phase 2: OWASP Review
|
||||
|
||||
Systematic code-level review against OWASP Top 10 2021 categories.
|
||||
|
||||
## Objective
|
||||
|
||||
- Review codebase against all 10 OWASP Top 10 2021 categories
|
||||
- Use CCW CLI multi-model analysis for comprehensive coverage
|
||||
- Produce structured findings with file:line references and remediation steps
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Phase 1 supply-chain-report.json (provides dependency context)
|
||||
- Read [specs/owasp-checklist.md](../specs/owasp-checklist.md) for detection patterns
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Identify Target Scope
|
||||
|
||||
```bash
|
||||
# Identify source directories (exclude deps, build, test fixtures)
|
||||
# Focus on: API routes, auth modules, data access, input handlers
|
||||
find . -type f \( -name '*.ts' -o -name '*.js' -o -name '*.py' -o -name '*.go' -o -name '*.java' \) \
|
||||
! -path '*/node_modules/*' ! -path '*/dist/*' ! -path '*/.git/*' \
|
||||
! -path '*/build/*' ! -path '*/__pycache__/*' ! -path '*/vendor/*' \
|
||||
| head -200
|
||||
```
|
||||
|
||||
### Step 2: CCW CLI Analysis
|
||||
|
||||
Run multi-model security analysis using the security risks rule template.
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: OWASP Top 10 2021 security audit of this codebase.
|
||||
Systematically check each OWASP category:
|
||||
A01 Broken Access Control | A02 Cryptographic Failures | A03 Injection |
|
||||
A04 Insecure Design | A05 Security Misconfiguration | A06 Vulnerable Components |
|
||||
A07 Identification/Auth Failures | A08 Software/Data Integrity Failures |
|
||||
A09 Security Logging/Monitoring Failures | A10 SSRF
|
||||
|
||||
TASK: For each OWASP category, scan relevant code patterns, identify vulnerabilities with file:line references, classify severity, provide remediation.
|
||||
|
||||
MODE: analysis
|
||||
|
||||
CONTEXT: @src/**/* @**/*.config.* @**/*.env.example
|
||||
|
||||
EXPECTED: JSON-structured findings per OWASP category with severity, file:line, evidence, remediation.
|
||||
|
||||
CONSTRAINTS: Code-level analysis only | Every finding must have file:line reference | Focus on real vulnerabilities not theoretical risks
|
||||
" --tool gemini --mode analysis --rule analysis-assess-security-risks
|
||||
```
|
||||
|
||||
### Step 3: Manual Pattern Scanning
|
||||
|
||||
Supplement CLI analysis with targeted pattern scans per OWASP category. Reference [specs/owasp-checklist.md](../specs/owasp-checklist.md) for full pattern list.
|
||||
|
||||
**A01 - Broken Access Control**:
|
||||
```bash
|
||||
# Missing auth middleware on routes
|
||||
grep -rn 'app\.\(get\|post\|put\|delete\|patch\)(' --include='*.ts' --include='*.js' . | grep -v 'auth\|middleware\|protect'
|
||||
# Direct object references without ownership check
|
||||
grep -rn 'params\.id\|req\.params\.' --include='*.ts' --include='*.js' . || true
|
||||
```
|
||||
|
||||
**A03 - Injection**:
|
||||
```bash
|
||||
# SQL string concatenation
|
||||
grep -rniE '(query|execute|raw)\s*\(\s*[`"'\'']\s*SELECT.*\+\s*|f".*SELECT.*{' --include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
# Command injection
|
||||
grep -rniE '(exec|spawn|system|popen|subprocess)\s*\(' --include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
```
|
||||
|
||||
**A05 - Security Misconfiguration**:
|
||||
```bash
|
||||
# Debug mode enabled
|
||||
grep -rniE '(DEBUG|debug)\s*[:=]\s*(true|True|1|"true")' --include='*.env' --include='*.py' --include='*.ts' --include='*.json' . || true
|
||||
# CORS wildcard
|
||||
grep -rniE "cors.*\*|Access-Control-Allow-Origin.*\*" --include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
```
|
||||
|
||||
**A07 - Identification and Authentication Failures**:
|
||||
```bash
|
||||
# Weak password patterns
|
||||
grep -rniE 'password.*length.*[0-5][^0-9]|minlength.*[0-5][^0-9]' --include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
# Hardcoded credentials
|
||||
grep -rniE '(password|passwd|pwd)\s*[:=]\s*["\x27][^"\x27]{3,}' --include='*.ts' --include='*.js' --include='*.py' --include='*.env' . || true
|
||||
```
|
||||
|
||||
### Step 4: Consolidate Findings
|
||||
|
||||
Merge CLI analysis results and manual pattern scan results. Deduplicate and classify by OWASP category.
|
||||
|
||||
## OWASP Top 10 2021 Categories
|
||||
|
||||
| ID | Category | Key Checks |
|
||||
|----|----------|------------|
|
||||
| A01 | Broken Access Control | Missing auth, IDOR, path traversal, CORS |
|
||||
| A02 | Cryptographic Failures | Weak algorithms, plaintext storage, missing TLS |
|
||||
| A03 | Injection | SQL, NoSQL, OS command, LDAP, XPath injection |
|
||||
| A04 | Insecure Design | Missing threat modeling, insecure business logic |
|
||||
| A05 | Security Misconfiguration | Debug enabled, default creds, verbose errors |
|
||||
| A06 | Vulnerable and Outdated Components | Known CVEs in dependencies (from Phase 1) |
|
||||
| A07 | Identification and Authentication Failures | Weak passwords, missing MFA, session issues |
|
||||
| A08 | Software and Data Integrity Failures | Unsigned updates, insecure deserialization, CI/CD |
|
||||
| A09 | Security Logging and Monitoring Failures | Missing audit logs, no alerting, insufficient logging |
|
||||
| A10 | Server-Side Request Forgery (SSRF) | Unvalidated URLs, internal resource access |
|
||||
|
||||
## Output
|
||||
|
||||
- **File**: `owasp-findings.json`
|
||||
- **Location**: `${WORK_DIR}/owasp-findings.json`
|
||||
- **Format**: JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": "owasp-review",
|
||||
"timestamp": "ISO-8601",
|
||||
"owasp_version": "2021",
|
||||
"findings": [
|
||||
{
|
||||
"owasp_id": "A01",
|
||||
"owasp_category": "Broken Access Control",
|
||||
"severity": "critical|high|medium|low",
|
||||
"title": "Finding title",
|
||||
"description": "Detailed description",
|
||||
"file": "path/to/file",
|
||||
"line": 42,
|
||||
"evidence": "code snippet or pattern match",
|
||||
"remediation": "Specific fix recommendation",
|
||||
"cwe": "CWE-XXX"
|
||||
}
|
||||
],
|
||||
"coverage": {
|
||||
"A01": "checked|not_applicable",
|
||||
"A02": "checked|not_applicable",
|
||||
"A03": "checked|not_applicable",
|
||||
"A04": "checked|not_applicable",
|
||||
"A05": "checked|not_applicable",
|
||||
"A06": "checked|not_applicable",
|
||||
"A07": "checked|not_applicable",
|
||||
"A08": "checked|not_applicable",
|
||||
"A09": "checked|not_applicable",
|
||||
"A10": "checked|not_applicable"
|
||||
},
|
||||
"summary": {
|
||||
"total": 0,
|
||||
"by_severity": { "critical": 0, "high": 0, "medium": 0, "low": 0 },
|
||||
"categories_checked": 10,
|
||||
"categories_with_findings": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 3: Threat Modeling](03-threat-modeling.md) with OWASP findings as input for STRIDE analysis.
|
||||
180
.claude/skills/security-audit/phases/03-threat-modeling.md
Normal file
180
.claude/skills/security-audit/phases/03-threat-modeling.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Phase 3: Threat Modeling (STRIDE)
|
||||
|
||||
Map STRIDE threat categories to architecture components, identify trust boundaries, and assess attack surface.
|
||||
|
||||
## Objective
|
||||
|
||||
- Apply the STRIDE threat model to the project architecture
|
||||
- Identify trust boundaries between system components
|
||||
- Assess attack surface area per component
|
||||
- Cross-reference with Phase 1 and Phase 2 findings
|
||||
|
||||
## STRIDE Categories
|
||||
|
||||
| Category | Threat | Question | Typical Targets |
|
||||
|----------|--------|----------|-----------------|
|
||||
| **S** - Spoofing | Identity impersonation | Can an attacker pretend to be someone else? | Auth endpoints, API keys, session tokens |
|
||||
| **T** - Tampering | Data modification | Can data be modified in transit or at rest? | Request bodies, database records, config files |
|
||||
| **R** - Repudiation | Deniable actions | Can a user deny performing an action? | Audit logs, transaction records, user actions |
|
||||
| **I** - Information Disclosure | Data leakage | Can sensitive data be exposed? | Error messages, logs, API responses, storage |
|
||||
| **D** - Denial of Service | Availability disruption | Can the system be made unavailable? | API endpoints, resource-intensive operations |
|
||||
| **E** - Elevation of Privilege | Unauthorized access | Can a user gain higher privileges? | Role checks, admin routes, permission logic |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Architecture Component Discovery
|
||||
|
||||
Identify major system components by scanning project structure.
|
||||
|
||||
```bash
|
||||
# Identify entry points (API routes, CLI commands, event handlers)
|
||||
grep -rlE '(app\.(get|post|put|delete|patch|use)|router\.|@app\.route|@router\.)' \
|
||||
--include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
|
||||
# Identify data stores (database connections, file storage)
|
||||
grep -rlE '(createConnection|mongoose\.connect|sqlite|redis|S3|createClient)' \
|
||||
--include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
|
||||
# Identify external service integrations
|
||||
grep -rlE '(fetch|axios|http\.request|requests\.(get|post)|urllib)' \
|
||||
--include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
|
||||
# Identify auth/session components
|
||||
grep -rlE '(jwt|passport|session|oauth|bcrypt|argon2|crypto)' \
|
||||
--include='*.ts' --include='*.js' --include='*.py' . || true
|
||||
```
|
||||
|
||||
### Step 2: Trust Boundary Identification
|
||||
|
||||
Map trust boundaries in the system:
|
||||
|
||||
1. **External boundary**: User/browser <-> Application server
|
||||
2. **Service boundary**: Application <-> External APIs/services
|
||||
3. **Data boundary**: Application <-> Database/storage
|
||||
4. **Internal boundary**: Public routes <-> Authenticated routes <-> Admin routes
|
||||
5. **Process boundary**: Main process <-> Worker/subprocess
|
||||
|
||||
For each boundary, document:
|
||||
- What crosses the boundary (data types, credentials)
|
||||
- How the boundary is enforced (middleware, TLS, auth)
|
||||
- What happens when enforcement fails
|
||||
|
||||
### Step 3: STRIDE per Component
|
||||
|
||||
For each discovered component, systematically evaluate all 6 STRIDE categories:
|
||||
|
||||
**Spoofing Analysis**:
|
||||
- Are authentication mechanisms in place at all entry points?
|
||||
- Can API keys or tokens be forged or replayed?
|
||||
- Are session tokens properly validated and rotated?
|
||||
|
||||
**Tampering Analysis**:
|
||||
- Is input validation applied before processing?
|
||||
- Are database queries parameterized?
|
||||
- Can request bodies or headers be manipulated to alter behavior?
|
||||
- Are file uploads validated for type and content?
|
||||
|
||||
**Repudiation Analysis**:
|
||||
- Are user actions logged with sufficient detail (who, what, when)?
|
||||
- Are logs tamper-proof or centralized?
|
||||
- Can critical operations (payments, deletions) be traced to a user?
|
||||
|
||||
**Information Disclosure Analysis**:
|
||||
- Do error responses leak stack traces or internal paths?
|
||||
- Are sensitive fields (passwords, tokens) excluded from logs and API responses?
|
||||
- Is PII properly handled (encryption at rest, masking in logs)?
|
||||
- Do debug endpoints or verbose modes expose internals?
|
||||
|
||||
**Denial of Service Analysis**:
|
||||
- Are rate limits applied to public endpoints?
|
||||
- Can resource-intensive operations be triggered without limits?
|
||||
- Are file upload sizes bounded?
|
||||
- Are database queries bounded (pagination, timeouts)?
|
||||
|
||||
**Elevation of Privilege Analysis**:
|
||||
- Are role/permission checks applied consistently?
|
||||
- Can horizontal privilege escalation occur (accessing other users' data)?
|
||||
- Can vertical escalation occur (user -> admin)?
|
||||
- Are admin/debug routes properly protected?
|
||||
|
||||
### Step 4: Attack Surface Assessment
|
||||
|
||||
Quantify the attack surface:
|
||||
|
||||
```
|
||||
Attack Surface = Sum of:
|
||||
- Number of public API endpoints
|
||||
- Number of external service integrations
|
||||
- Number of user-controllable input points
|
||||
- Number of privileged operations
|
||||
- Number of data stores with sensitive content
|
||||
```
|
||||
|
||||
Rate each component:
|
||||
- **High exposure**: Public-facing, handles sensitive data, complex logic
|
||||
- **Medium exposure**: Authenticated access, moderate data sensitivity
|
||||
- **Low exposure**: Internal only, no sensitive data, simple operations
|
||||
|
||||
## Output
|
||||
|
||||
- **File**: `threat-model.json`
|
||||
- **Location**: `${WORK_DIR}/threat-model.json`
|
||||
- **Format**: JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": "threat-modeling",
|
||||
"timestamp": "ISO-8601",
|
||||
"framework": "STRIDE",
|
||||
"components": [
|
||||
{
|
||||
"name": "Component name",
|
||||
"type": "api_endpoint|data_store|external_service|auth_module|worker",
|
||||
"files": ["path/to/file.ts"],
|
||||
"exposure": "high|medium|low",
|
||||
"trust_boundaries": ["external", "data"],
|
||||
"threats": {
|
||||
"spoofing": {
|
||||
"applicable": true,
|
||||
"findings": ["Description of threat"],
|
||||
"mitigations": ["Existing mitigation"],
|
||||
"gaps": ["Missing mitigation"]
|
||||
},
|
||||
"tampering": { "applicable": true, "findings": [], "mitigations": [], "gaps": [] },
|
||||
"repudiation": { "applicable": true, "findings": [], "mitigations": [], "gaps": [] },
|
||||
"information_disclosure": { "applicable": true, "findings": [], "mitigations": [], "gaps": [] },
|
||||
"denial_of_service": { "applicable": true, "findings": [], "mitigations": [], "gaps": [] },
|
||||
"elevation_of_privilege": { "applicable": true, "findings": [], "mitigations": [], "gaps": [] }
|
||||
}
|
||||
}
|
||||
],
|
||||
"trust_boundaries": [
|
||||
{
|
||||
"name": "Boundary name",
|
||||
"from": "Component A",
|
||||
"to": "Component B",
|
||||
"enforcement": "TLS|auth_middleware|API_key",
|
||||
"data_crossing": ["request bodies", "credentials"],
|
||||
"risk_level": "high|medium|low"
|
||||
}
|
||||
],
|
||||
"attack_surface": {
|
||||
"public_endpoints": 0,
|
||||
"external_integrations": 0,
|
||||
"input_points": 0,
|
||||
"privileged_operations": 0,
|
||||
"sensitive_data_stores": 0,
|
||||
"total_score": 0
|
||||
},
|
||||
"summary": {
|
||||
"components_analyzed": 0,
|
||||
"threats_identified": 0,
|
||||
"by_stride": { "S": 0, "T": 0, "R": 0, "I": 0, "D": 0, "E": 0 },
|
||||
"high_exposure_components": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
Proceed to [Phase 4: Report & Tracking](04-report-tracking.md) with the threat model to generate the final scored audit report.
|
||||
177
.claude/skills/security-audit/phases/04-report-tracking.md
Normal file
177
.claude/skills/security-audit/phases/04-report-tracking.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# Phase 4: Report & Tracking
|
||||
|
||||
Generate scored audit report, compare with previous audits, and track trends.
|
||||
|
||||
## Objective
|
||||
|
||||
- Calculate security score from all phase findings
|
||||
- Compare with previous audit results (if available)
|
||||
- Generate date-stamped report in `.workflow/.security/`
|
||||
- Track improvement or regression trends
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Phase 1: `supply-chain-report.json`
|
||||
- Phase 2: `owasp-findings.json`
|
||||
- Phase 3: `threat-model.json`
|
||||
- Previous audit: `.workflow/.security/audit-report-*.json` (optional)
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Aggregate Findings
|
||||
|
||||
Collect all findings from phases 1-3 and classify by severity.
|
||||
|
||||
```
|
||||
All findings =
|
||||
supply-chain-report.findings
|
||||
+ owasp-findings.findings
|
||||
+ threat-model threats (where gaps exist)
|
||||
```
|
||||
|
||||
### Step 2: Calculate Score
|
||||
|
||||
Apply scoring formula from [specs/scoring-gates.md](../specs/scoring-gates.md):
|
||||
|
||||
```
|
||||
Base score = 10.0
|
||||
|
||||
For each finding:
|
||||
penalty = severity_weight / total_files_scanned
|
||||
- Critical: weight = 10 (each critical finding has outsized impact)
|
||||
- High: weight = 7
|
||||
- Medium: weight = 4
|
||||
- Low: weight = 1
|
||||
|
||||
Weighted penalty = SUM(finding_weight * count_per_severity) / normalization_factor
|
||||
Final score = max(0, 10.0 - weighted_penalty)
|
||||
|
||||
Normalization factor = max(10, total_files_scanned)
|
||||
```
|
||||
|
||||
**Score interpretation**:
|
||||
|
||||
| Score | Rating | Meaning |
|
||||
|-------|--------|---------|
|
||||
| 9-10 | Excellent | Minimal risk, production-ready |
|
||||
| 7-8 | Good | Acceptable risk, minor improvements needed |
|
||||
| 5-6 | Fair | Notable risks, remediation recommended |
|
||||
| 3-4 | Poor | Significant risks, remediation required |
|
||||
| 0-2 | Critical | Severe vulnerabilities, immediate action needed |
|
||||
|
||||
### Step 3: Gate Evaluation
|
||||
|
||||
**Daily quick-scan gate** (Phase 1 only):
|
||||
- PASS: score >= 8/10
|
||||
- FAIL: score < 8/10 -- block deployment or flag for review
|
||||
|
||||
**Comprehensive audit gate** (all phases):
|
||||
- For initial/baseline: PASS if score >= 2/10 (establishes baseline)
|
||||
- For subsequent: PASS if score >= previous_score (no regression)
|
||||
- Target: score >= 7/10 for production readiness
|
||||
|
||||
### Step 4: Trend Comparison
|
||||
|
||||
```bash
|
||||
# Find previous audit reports
|
||||
ls -t .workflow/.security/audit-report-*.json 2>/dev/null | head -5
|
||||
```
|
||||
|
||||
Compare current vs. previous:
|
||||
- Delta per OWASP category
|
||||
- Delta per STRIDE category
|
||||
- New findings vs. resolved findings
|
||||
- Overall score trend
|
||||
|
||||
### Step 5: Generate Report
|
||||
|
||||
Write the final report with all consolidated data.
|
||||
|
||||
## Output
|
||||
|
||||
- **File**: `audit-report-{YYYY-MM-DD}.json`
|
||||
- **Location**: `.workflow/.security/audit-report-{YYYY-MM-DD}.json`
|
||||
- **Format**: JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"report": "security-audit",
|
||||
"version": "1.0",
|
||||
"timestamp": "ISO-8601",
|
||||
"date": "YYYY-MM-DD",
|
||||
"mode": "comprehensive|quick-scan",
|
||||
"score": {
|
||||
"overall": 7.5,
|
||||
"rating": "Good",
|
||||
"gate": "PASS|FAIL",
|
||||
"gate_threshold": 8
|
||||
},
|
||||
"findings_summary": {
|
||||
"total": 0,
|
||||
"by_severity": { "critical": 0, "high": 0, "medium": 0, "low": 0 },
|
||||
"by_phase": {
|
||||
"supply_chain": 0,
|
||||
"owasp": 0,
|
||||
"stride": 0
|
||||
},
|
||||
"by_owasp": {
|
||||
"A01": 0, "A02": 0, "A03": 0, "A04": 0, "A05": 0,
|
||||
"A06": 0, "A07": 0, "A08": 0, "A09": 0, "A10": 0
|
||||
},
|
||||
"by_stride": { "S": 0, "T": 0, "R": 0, "I": 0, "D": 0, "E": 0 }
|
||||
},
|
||||
"top_risks": [
|
||||
{
|
||||
"rank": 1,
|
||||
"title": "Most critical finding",
|
||||
"severity": "critical",
|
||||
"source_phase": "owasp",
|
||||
"remediation": "How to fix",
|
||||
"effort": "low|medium|high"
|
||||
}
|
||||
],
|
||||
"trend": {
|
||||
"previous_date": "YYYY-MM-DD or null",
|
||||
"previous_score": 0,
|
||||
"score_delta": 0,
|
||||
"new_findings": 0,
|
||||
"resolved_findings": 0,
|
||||
"direction": "improving|stable|regressing|baseline"
|
||||
},
|
||||
"phases_completed": ["supply-chain-scan", "owasp-review", "threat-modeling", "report-tracking"],
|
||||
"files_scanned": 0,
|
||||
"remediation_priority": [
|
||||
{
|
||||
"priority": 1,
|
||||
"finding": "Finding title",
|
||||
"effort": "low",
|
||||
"impact": "high",
|
||||
"recommendation": "Specific action"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Report Storage
|
||||
|
||||
```bash
|
||||
# Ensure directory exists
|
||||
mkdir -p .workflow/.security
|
||||
|
||||
# Write report with date stamp
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
cp "${WORK_DIR}/audit-report.json" ".workflow/.security/audit-report-${DATE}.json"
|
||||
|
||||
# Also maintain latest copies of phase outputs
|
||||
cp "${WORK_DIR}/supply-chain-report.json" ".workflow/.security/" 2>/dev/null || true
|
||||
cp "${WORK_DIR}/owasp-findings.json" ".workflow/.security/" 2>/dev/null || true
|
||||
cp "${WORK_DIR}/threat-model.json" ".workflow/.security/" 2>/dev/null || true
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
After report generation, output skill completion status per the Completion Status Protocol:
|
||||
|
||||
- **DONE**: All phases completed, report generated, score calculated
|
||||
- **DONE_WITH_CONCERNS**: Report generated but score below target or regression detected
|
||||
- **BLOCKED**: Phase data missing or corrupted
|
||||
442
.claude/skills/security-audit/specs/owasp-checklist.md
Normal file
442
.claude/skills/security-audit/specs/owasp-checklist.md
Normal file
@@ -0,0 +1,442 @@
|
||||
# OWASP Top 10 2021 Checklist
|
||||
|
||||
Code-level detection patterns, vulnerable code examples, and remediation templates for each OWASP category.
|
||||
|
||||
## When to Use
|
||||
|
||||
| Phase | Usage | Section |
|
||||
|-------|-------|---------|
|
||||
| Phase 2 | Reference during OWASP code review | All categories |
|
||||
| Phase 4 | Classify findings by OWASP category | Category IDs |
|
||||
|
||||
---
|
||||
|
||||
## A01: Broken Access Control
|
||||
|
||||
**CWE**: CWE-200, CWE-284, CWE-285, CWE-352, CWE-639
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# Missing auth middleware on route handlers
|
||||
grep -rnE 'app\.(get|post|put|delete|patch)\s*\(\s*["\x27/]' --include='*.ts' --include='*.js' .
|
||||
# Then verify each route has auth middleware
|
||||
|
||||
# Direct object reference without ownership check
|
||||
grep -rnE 'findById\(.*params|findOne\(.*params|\.get\(.*id' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# Path traversal patterns
|
||||
grep -rnE '(readFile|writeFile|createReadStream|open)\s*\(.*req\.' --include='*.ts' --include='*.js' .
|
||||
grep -rnE 'os\.path\.join\(.*request\.' --include='*.py' .
|
||||
|
||||
# Missing CORS restrictions
|
||||
grep -rnE 'Access-Control-Allow-Origin.*\*|cors\(\s*\)' --include='*.ts' --include='*.js' .
|
||||
```
|
||||
|
||||
### Vulnerable Code Example
|
||||
|
||||
```javascript
|
||||
// BAD: No ownership check
|
||||
app.get('/api/documents/:id', auth, async (req, res) => {
|
||||
const doc = await Document.findById(req.params.id); // Any user can access any doc
|
||||
res.json(doc);
|
||||
});
|
||||
```
|
||||
|
||||
### Remediation
|
||||
|
||||
```javascript
|
||||
// GOOD: Ownership check
|
||||
app.get('/api/documents/:id', auth, async (req, res) => {
|
||||
const doc = await Document.findOne({ _id: req.params.id, owner: req.user.id });
|
||||
if (!doc) return res.status(404).json({ error: 'Not found' });
|
||||
res.json(doc);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## A02: Cryptographic Failures
|
||||
|
||||
**CWE**: CWE-259, CWE-327, CWE-331, CWE-798
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# Weak hash algorithms
|
||||
grep -rniE '(md5|sha1)\s*\(' --include='*.ts' --include='*.js' --include='*.py' --include='*.java' .
|
||||
|
||||
# Plaintext password storage
|
||||
grep -rniE 'password\s*[:=]\s*.*\.(body|query|params)' --include='*.ts' --include='*.js' .
|
||||
|
||||
# Hardcoded encryption keys
|
||||
grep -rniE '(encrypt|cipher|secret|key)\s*[:=]\s*["\x27][A-Za-z0-9+/=]{8,}' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# HTTP (not HTTPS) for sensitive operations
|
||||
grep -rniE 'http://.*\.(api|auth|login|payment)' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# Missing encryption at rest
|
||||
grep -rniE '(password|ssn|credit.?card|social.?security)' --include='*.sql' --include='*.prisma' --include='*.schema' .
|
||||
```
|
||||
|
||||
### Vulnerable Code Example
|
||||
|
||||
```python
|
||||
# BAD: MD5 for password hashing
|
||||
import hashlib
|
||||
password_hash = hashlib.md5(password.encode()).hexdigest()
|
||||
```
|
||||
|
||||
### Remediation
|
||||
|
||||
```python
|
||||
# GOOD: bcrypt with proper work factor
|
||||
import bcrypt
|
||||
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## A03: Injection
|
||||
|
||||
**CWE**: CWE-20, CWE-74, CWE-79, CWE-89
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# SQL string concatenation/interpolation
|
||||
grep -rniE "(query|execute|raw)\s*\(\s*[\`\"'].*(\+|\$\{|%s|\.format)" --include='*.ts' --include='*.js' --include='*.py' .
|
||||
grep -rniE "f[\"'].*SELECT.*\{" --include='*.py' .
|
||||
|
||||
# NoSQL injection
|
||||
grep -rniE '\$where|\$regex.*req\.' --include='*.ts' --include='*.js' .
|
||||
grep -rniE 'find\(\s*\{.*req\.(body|query|params)' --include='*.ts' --include='*.js' .
|
||||
|
||||
# OS command injection
|
||||
grep -rniE '(child_process|exec|execSync|spawn|system|popen|subprocess)\s*\(.*req\.' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# XPath/LDAP injection
|
||||
grep -rniE '(xpath|ldap).*\+.*req\.' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# Template injection
|
||||
grep -rniE '(render_template_string|Template\(.*req\.|eval\(.*req\.)' --include='*.py' --include='*.js' .
|
||||
```
|
||||
|
||||
### Vulnerable Code Example
|
||||
|
||||
```javascript
|
||||
// BAD: SQL string concatenation
|
||||
const result = await db.query(`SELECT * FROM users WHERE id = ${req.params.id}`);
|
||||
```
|
||||
|
||||
### Remediation
|
||||
|
||||
```javascript
|
||||
// GOOD: Parameterized query
|
||||
const result = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## A04: Insecure Design
|
||||
|
||||
**CWE**: CWE-209, CWE-256, CWE-501, CWE-522
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# Missing rate limiting on auth endpoints
|
||||
grep -rniE '(login|register|reset.?password|forgot.?password)' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
# Then check if rate limiting middleware is applied
|
||||
|
||||
# No account lockout mechanism
|
||||
grep -rniE 'failed.?login|login.?attempt|max.?retries' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# Business logic without validation
|
||||
grep -rniE '(transfer|withdraw|purchase|delete.?account)' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
# Then check for confirmation/validation steps
|
||||
```
|
||||
|
||||
### Checks
|
||||
|
||||
- [ ] Authentication flows have rate limiting
|
||||
- [ ] Account lockout after N failed attempts
|
||||
- [ ] Multi-step operations have proper state validation
|
||||
- [ ] Business-critical operations require confirmation
|
||||
- [ ] Threat modeling has been performed (see Phase 3)
|
||||
|
||||
### Remediation
|
||||
|
||||
Implement defense-in-depth: rate limiting, input validation, business logic validation, and multi-step confirmation for critical operations.
|
||||
|
||||
---
|
||||
|
||||
## A05: Security Misconfiguration
|
||||
|
||||
**CWE**: CWE-2, CWE-11, CWE-13, CWE-15, CWE-16, CWE-388
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# Debug mode enabled
|
||||
grep -rniE '(DEBUG|NODE_ENV)\s*[:=]\s*(true|True|1|"development"|"debug")' \
|
||||
--include='*.env' --include='*.env.*' --include='*.py' --include='*.json' --include='*.yaml' .
|
||||
|
||||
# Default credentials
|
||||
grep -rniE '(admin|root|test|default).*[:=].*password' --include='*.env' --include='*.yaml' --include='*.json' --include='*.py' .
|
||||
|
||||
# Verbose error responses (stack traces to client)
|
||||
grep -rniE '(stack|stackTrace|traceback).*res\.(json|send)|app\.use.*err.*stack' --include='*.ts' --include='*.js' .
|
||||
|
||||
# Missing security headers
|
||||
grep -rniE '(helmet|X-Frame-Options|X-Content-Type-Options|Strict-Transport-Security)' --include='*.ts' --include='*.js' .
|
||||
|
||||
# Directory listing enabled
|
||||
grep -rniE 'autoindex\s+on|directory.?listing|serveStatic.*index.*false' --include='*.conf' --include='*.ts' --include='*.js' .
|
||||
|
||||
# Unnecessary features/services
|
||||
grep -rniE '(graphiql|playground|swagger-ui).*true' --include='*.ts' --include='*.js' --include='*.py' --include='*.yaml' .
|
||||
```
|
||||
|
||||
### Vulnerable Code Example
|
||||
|
||||
```javascript
|
||||
// BAD: Stack trace in error response
|
||||
app.use((err, req, res, next) => {
|
||||
res.status(500).json({ error: err.message, stack: err.stack });
|
||||
});
|
||||
```
|
||||
|
||||
### Remediation
|
||||
|
||||
```javascript
|
||||
// GOOD: Generic error response in production
|
||||
app.use((err, req, res, next) => {
|
||||
console.error(err.stack); // Log internally
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## A06: Vulnerable and Outdated Components
|
||||
|
||||
**CWE**: CWE-1104
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# Check dependency lock files age
|
||||
ls -la package-lock.json yarn.lock requirements.txt Pipfile.lock go.sum 2>/dev/null
|
||||
|
||||
# Run package audits (from Phase 1)
|
||||
npm audit --json 2>/dev/null
|
||||
pip-audit --format json 2>/dev/null
|
||||
|
||||
# Check for pinned vs unpinned dependencies
|
||||
grep -E ':\s*"\^|:\s*"~|:\s*"\*|>=\s' package.json 2>/dev/null
|
||||
grep -E '^[a-zA-Z].*[^=]==[^=]' requirements.txt 2>/dev/null # Good: pinned
|
||||
grep -E '^[a-zA-Z].*>=|^[a-zA-Z][^=]*$' requirements.txt 2>/dev/null # Bad: unpinned
|
||||
```
|
||||
|
||||
### Checks
|
||||
|
||||
- [ ] All dependencies have pinned versions
|
||||
- [ ] No known CVEs in dependencies (via audit tools)
|
||||
- [ ] Dependencies are actively maintained (not abandoned)
|
||||
- [ ] Lock files are committed to version control
|
||||
|
||||
### Remediation
|
||||
|
||||
Run `npm audit fix` or `pip install --upgrade` for vulnerable packages. Pin all dependency versions. Set up automated dependency scanning (Dependabot, Renovate).
|
||||
|
||||
---
|
||||
|
||||
## A07: Identification and Authentication Failures
|
||||
|
||||
**CWE**: CWE-255, CWE-259, CWE-287, CWE-384
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# Weak password requirements
|
||||
grep -rniE 'password.*length.*[0-5]|minlength.*[0-5]|min.?length.*[0-5]' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# Missing password hashing
|
||||
grep -rniE 'password\s*[:=].*req\.' --include='*.ts' --include='*.js' .
|
||||
# Then check if bcrypt/argon2/scrypt is used before storage
|
||||
|
||||
# Session fixation (no rotation after login)
|
||||
grep -rniE 'session\.regenerate|session\.id\s*=' --include='*.ts' --include='*.js' .
|
||||
|
||||
# JWT without expiration
|
||||
grep -rniE 'jwt\.sign\(' --include='*.ts' --include='*.js' .
|
||||
# Then check for expiresIn option
|
||||
|
||||
# Credentials in URL
|
||||
grep -rniE '(token|key|password|secret)=[^&\s]+' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
```
|
||||
|
||||
### Vulnerable Code Example
|
||||
|
||||
```javascript
|
||||
// BAD: JWT without expiration
|
||||
const token = jwt.sign({ userId: user.id }, SECRET);
|
||||
```
|
||||
|
||||
### Remediation
|
||||
|
||||
```javascript
|
||||
// GOOD: JWT with expiration and proper claims
|
||||
const token = jwt.sign(
|
||||
{ userId: user.id, role: user.role },
|
||||
SECRET,
|
||||
{ expiresIn: '1h', issuer: 'myapp', audience: 'myapp-client' }
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## A08: Software and Data Integrity Failures
|
||||
|
||||
**CWE**: CWE-345, CWE-353, CWE-426, CWE-494, CWE-502
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# Insecure deserialization
|
||||
grep -rniE '(pickle\.load|yaml\.load\(|unserialize|JSON\.parse\(.*req\.|eval\()' --include='*.py' --include='*.ts' --include='*.js' --include='*.php' .
|
||||
|
||||
# Missing integrity checks on downloads/updates
|
||||
grep -rniE '(download|fetch|curl|wget)' --include='*.sh' --include='*.yaml' --include='*.yml' .
|
||||
# Then check for checksum/signature verification
|
||||
|
||||
# CI/CD pipeline without pinned action versions
|
||||
grep -rniE 'uses:\s*[^@]+$|uses:.*@(main|master|latest)' .github/workflows/*.yml 2>/dev/null
|
||||
|
||||
# Unsafe YAML loading
|
||||
grep -rniE 'yaml\.load\(' --include='*.py' .
|
||||
# Should be yaml.safe_load()
|
||||
```
|
||||
|
||||
### Vulnerable Code Example
|
||||
|
||||
```python
|
||||
# BAD: Unsafe YAML loading
|
||||
import yaml
|
||||
data = yaml.load(user_input) # Allows arbitrary code execution
|
||||
```
|
||||
|
||||
### Remediation
|
||||
|
||||
```python
|
||||
# GOOD: Safe YAML loading
|
||||
import yaml
|
||||
data = yaml.safe_load(user_input)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## A09: Security Logging and Monitoring Failures
|
||||
|
||||
**CWE**: CWE-223, CWE-532, CWE-778
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# Check for logging of auth events
|
||||
grep -rniE '(log|logger|logging)\.' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
# Then check if login/logout/failed-auth events are logged
|
||||
|
||||
# Sensitive data in logs
|
||||
grep -rniE 'log.*(password|token|secret|credit.?card|ssn)' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# Empty catch blocks (swallowed errors)
|
||||
grep -rniE 'catch\s*\([^)]*\)\s*\{\s*\}' --include='*.ts' --include='*.js' .
|
||||
|
||||
# Missing audit trail for critical operations
|
||||
grep -rniE '(delete|update|create|transfer)' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
# Then check if these operations are logged with user context
|
||||
```
|
||||
|
||||
### Checks
|
||||
|
||||
- [ ] Failed login attempts are logged with IP and timestamp
|
||||
- [ ] Successful logins are logged
|
||||
- [ ] Access control failures are logged
|
||||
- [ ] Input validation failures are logged
|
||||
- [ ] Sensitive data is NOT logged (passwords, tokens, PII)
|
||||
- [ ] Logs include sufficient context (who, what, when, where)
|
||||
|
||||
### Remediation
|
||||
|
||||
Implement structured logging with: user ID, action, timestamp, IP address, result (success/failure). Exclude sensitive data. Set up log monitoring and alerting for anomalous patterns.
|
||||
|
||||
---
|
||||
|
||||
## A10: Server-Side Request Forgery (SSRF)
|
||||
|
||||
**CWE**: CWE-918
|
||||
|
||||
### Detection Patterns
|
||||
|
||||
```bash
|
||||
# User-controlled URLs in fetch/request calls
|
||||
grep -rniE '(fetch|axios|http\.request|requests\.(get|post)|urllib)\s*\(.*req\.(body|query|params)' \
|
||||
--include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# URL construction from user input
|
||||
grep -rniE '(url|endpoint|target|redirect)\s*[:=].*req\.(body|query|params)' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# Image/file fetch from URL
|
||||
grep -rniE '(download|fetchImage|getFile|loadUrl)\s*\(.*req\.' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
|
||||
# Redirect without validation
|
||||
grep -rniE 'res\.redirect\(.*req\.|redirect_to.*request\.' --include='*.ts' --include='*.js' --include='*.py' .
|
||||
```
|
||||
|
||||
### Vulnerable Code Example
|
||||
|
||||
```javascript
|
||||
// BAD: Unvalidated URL fetch
|
||||
app.get('/proxy', async (req, res) => {
|
||||
const response = await fetch(req.query.url); // Can access internal services
|
||||
res.send(await response.text());
|
||||
});
|
||||
```
|
||||
|
||||
### Remediation
|
||||
|
||||
```javascript
|
||||
// GOOD: URL allowlist validation
|
||||
const ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com'];
|
||||
|
||||
app.get('/proxy', async (req, res) => {
|
||||
const url = new URL(req.query.url);
|
||||
if (!ALLOWED_HOSTS.includes(url.hostname)) {
|
||||
return res.status(400).json({ error: 'Host not allowed' });
|
||||
}
|
||||
if (url.protocol !== 'https:') {
|
||||
return res.status(400).json({ error: 'HTTPS required' });
|
||||
}
|
||||
const response = await fetch(url.toString());
|
||||
res.send(await response.text());
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| ID | Category | Key Grep Pattern | Severity Baseline |
|
||||
|----|----------|-----------------|-------------------|
|
||||
| A01 | Broken Access Control | `findById.*params` without owner check | High |
|
||||
| A02 | Cryptographic Failures | `md5\|sha1` for passwords | High |
|
||||
| A03 | Injection | `query.*\+.*req\.\|f".*SELECT.*\{` | Critical |
|
||||
| A04 | Insecure Design | Missing rate limit on auth routes | Medium |
|
||||
| A05 | Security Misconfiguration | `DEBUG.*true\|stack.*res.json` | Medium |
|
||||
| A06 | Vulnerable Components | `npm audit` / `pip-audit` results | Varies |
|
||||
| A07 | Auth Failures | `jwt.sign` without `expiresIn` | High |
|
||||
| A08 | Integrity Failures | `pickle.load\|yaml.load` | High |
|
||||
| A09 | Logging Failures | Empty catch blocks, no auth logging | Medium |
|
||||
| A10 | SSRF | `fetch.*req.query.url` | High |
|
||||
141
.claude/skills/security-audit/specs/scoring-gates.md
Normal file
141
.claude/skills/security-audit/specs/scoring-gates.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# Scoring Gates
|
||||
|
||||
Defines the 10-point scoring system, severity weights, quality gates, and trend tracking format for security audits.
|
||||
|
||||
## When to Use
|
||||
|
||||
| Phase | Usage | Section |
|
||||
|-------|-------|---------|
|
||||
| Phase 1 | Quick-scan scoring (daily gate) | Severity Weights, Daily Gate |
|
||||
| Phase 4 | Full audit scoring and reporting | All sections |
|
||||
|
||||
---
|
||||
|
||||
## 10-Point Scale
|
||||
|
||||
All security audit scores are on a 0-10 scale where 10 = no findings and 0 = critical exposure.
|
||||
|
||||
| Score | Rating | Description |
|
||||
|-------|--------|-------------|
|
||||
| 9.0 - 10.0 | Excellent | Minimal risk. Production-ready without reservations. |
|
||||
| 7.0 - 8.9 | Good | Low risk. Acceptable for production with minor improvements. |
|
||||
| 5.0 - 6.9 | Fair | Moderate risk. Remediation recommended before production. |
|
||||
| 3.0 - 4.9 | Poor | High risk. Remediation required. Not production-ready. |
|
||||
| 0.0 - 2.9 | Critical | Severe exposure. Immediate action required. |
|
||||
|
||||
## Severity Weights
|
||||
|
||||
Each finding is weighted by severity for score calculation.
|
||||
|
||||
| Severity | Weight | Criteria | Examples |
|
||||
|----------|--------|----------|----------|
|
||||
| **Critical** | 10 | Exploitable with high impact, no user interaction needed | RCE, SQL injection with data access, leaked production credentials, auth bypass |
|
||||
| **High** | 7 | Exploitable with significant impact, may need user interaction | Broken authentication, SSRF, privilege escalation, XSS with session theft |
|
||||
| **Medium** | 4 | Limited exploitability or moderate impact | Reflected XSS, CSRF, verbose error messages, missing security headers |
|
||||
| **Low** | 1 | Informational or minimal impact | Missing best-practice headers, minor info disclosure, deprecated dependencies without known exploit |
|
||||
|
||||
## Score Calculation
|
||||
|
||||
```
|
||||
Input:
|
||||
findings[] -- array of all findings with severity
|
||||
files_scanned -- total source files analyzed
|
||||
|
||||
Algorithm:
|
||||
base_score = 10.0
|
||||
normalization = max(10, files_scanned)
|
||||
|
||||
weighted_sum = 0
|
||||
for each finding:
|
||||
weighted_sum += severity_weight(finding.severity)
|
||||
|
||||
penalty = weighted_sum / normalization
|
||||
final_score = max(0, base_score - penalty)
|
||||
final_score = round(final_score, 1)
|
||||
|
||||
return final_score
|
||||
```
|
||||
|
||||
**Example**:
|
||||
|
||||
| Findings | Files Scanned | Weighted Sum | Penalty | Score |
|
||||
|----------|--------------|--------------|---------|-------|
|
||||
| 1 critical | 50 | 10 | 0.2 | 9.8 |
|
||||
| 2 critical, 3 high | 50 | 41 | 0.82 | 9.2 |
|
||||
| 5 critical, 10 high | 50 | 120 | 2.4 | 7.6 |
|
||||
| 10 critical, 20 high, 15 medium | 100 | 300 | 3.0 | 7.0 |
|
||||
| 20 critical | 20 | 200 | 10.0 | 0.0 |
|
||||
|
||||
## Quality Gates
|
||||
|
||||
### Daily Quick-Scan Gate
|
||||
|
||||
Applies to Phase 1 (Supply Chain Scan) only.
|
||||
|
||||
| Result | Condition | Action |
|
||||
|--------|-----------|--------|
|
||||
| **PASS** | score >= 8.0 | Continue. No blocking issues. |
|
||||
| **WARN** | 6.0 <= score < 8.0 | Log warning. Review findings before deploy. |
|
||||
| **FAIL** | score < 6.0 | Block deployment. Remediate critical/high findings. |
|
||||
|
||||
### Comprehensive Audit Gate
|
||||
|
||||
Applies to full audit (all 4 phases).
|
||||
|
||||
**Initial/Baseline audit** (no previous audit exists):
|
||||
|
||||
| Result | Condition | Action |
|
||||
|--------|-----------|--------|
|
||||
| **PASS** | score >= 2.0 | Baseline established. Plan remediation. |
|
||||
| **FAIL** | score < 2.0 | Critical exposure. Immediate triage required. |
|
||||
|
||||
**Subsequent audits** (previous audit exists):
|
||||
|
||||
| Result | Condition | Action |
|
||||
|--------|-----------|--------|
|
||||
| **PASS** | score >= previous_score | No regression. Continue improvement. |
|
||||
| **WARN** | score within 0.5 of previous | Marginal change. Review new findings. |
|
||||
| **FAIL** | score < previous_score - 0.5 | Regression detected. Investigate new findings. |
|
||||
|
||||
**Production readiness target**: score >= 7.0
|
||||
|
||||
## Trend Tracking Format
|
||||
|
||||
Each audit report stores trend data for comparison.
|
||||
|
||||
```json
|
||||
{
|
||||
"trend": {
|
||||
"current_date": "2026-03-29",
|
||||
"current_score": 7.5,
|
||||
"previous_date": "2026-03-22",
|
||||
"previous_score": 6.8,
|
||||
"score_delta": 0.7,
|
||||
"new_findings": 2,
|
||||
"resolved_findings": 5,
|
||||
"direction": "improving",
|
||||
"history": [
|
||||
{ "date": "2026-03-15", "score": 5.2, "total_findings": 45 },
|
||||
{ "date": "2026-03-22", "score": 6.8, "total_findings": 32 },
|
||||
{ "date": "2026-03-29", "score": 7.5, "total_findings": 29 }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Direction values**:
|
||||
|
||||
| Direction | Condition |
|
||||
|-----------|-----------|
|
||||
| `improving` | score_delta > 0.5 |
|
||||
| `stable` | -0.5 <= score_delta <= 0.5 |
|
||||
| `regressing` | score_delta < -0.5 |
|
||||
| `baseline` | No previous audit exists |
|
||||
|
||||
## Finding Deduplication
|
||||
|
||||
When the same vulnerability appears in multiple phases:
|
||||
1. Keep the highest-severity classification
|
||||
2. Merge evidence from all phases
|
||||
3. Count as a single finding for scoring
|
||||
4. Note all phases that detected it
|
||||
105
.claude/skills/ship/SKILL.md
Normal file
105
.claude/skills/ship/SKILL.md
Normal file
@@ -0,0 +1,105 @@
|
||||
---
|
||||
name: ship
|
||||
description: Structured release pipeline with pre-flight checks, AI code review, version bump, changelog, and PR creation. Triggers on "ship", "release", "publish".
|
||||
allowed-tools: Read, Write, Bash, Glob, Grep
|
||||
---
|
||||
|
||||
# Ship
|
||||
|
||||
Structured release pipeline that guides code from working branch to pull request through 5 gated phases: pre-flight checks, automated code review, version bump, changelog generation, and PR creation.
|
||||
|
||||
## Key Design Principles
|
||||
|
||||
1. **Phase Gates**: Each phase must pass before the next begins — no shipping broken code
|
||||
2. **Multi-Project Support**: Detects npm (package.json), Python (pyproject.toml), and generic (VERSION) projects
|
||||
3. **AI-Powered Review**: Uses CCW CLI to run automated code review before release
|
||||
4. **Audit Trail**: Each phase produces structured output for traceability
|
||||
5. **Safe Defaults**: Warns on risky operations (direct push to main, major version bumps)
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
User: "ship" / "release" / "publish"
|
||||
|
|
||||
v
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ Phase 1: Pre-Flight Checks │
|
||||
│ → git clean? branch ok? tests pass? build ok? │
|
||||
│ → Output: preflight-report.json │
|
||||
│ → Gate: ALL checks must pass │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Phase 2: Code Review │
|
||||
│ → detect merge base, diff against base │
|
||||
│ → ccw cli --tool gemini --mode analysis │
|
||||
│ → flag high-risk changes │
|
||||
│ → Output: review-summary │
|
||||
│ → Gate: No critical issues flagged │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Phase 3: Version Bump │
|
||||
│ → detect version file (package.json/pyproject.toml/VERSION)
|
||||
│ → determine bump type from commits or user input │
|
||||
│ → update version file │
|
||||
│ → Output: version change record │
|
||||
│ → Gate: Version updated successfully │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Phase 4: Changelog & Commit │
|
||||
│ → generate changelog from git log since last tag │
|
||||
│ → update CHANGELOG.md │
|
||||
│ → create release commit, push to remote │
|
||||
│ → Output: commit SHA │
|
||||
│ → Gate: Push successful │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ Phase 5: PR Creation │
|
||||
│ → gh pr create with structured body │
|
||||
│ → auto-link issues from commits │
|
||||
│ → Output: PR URL │
|
||||
│ → Gate: PR created │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Execution Flow
|
||||
|
||||
Execute phases sequentially. Each phase has a gate condition — if the gate fails, stop and report status.
|
||||
|
||||
1. **Phase 1**: [Pre-Flight Checks](phases/01-preflight-checks.md) -- Validate git state, branch, tests, build
|
||||
2. **Phase 2**: [Code Review](phases/02-code-review.md) -- AI-powered diff review with risk assessment
|
||||
3. **Phase 3**: [Version Bump](phases/03-version-bump.md) -- Detect and update version across project types
|
||||
4. **Phase 4**: [Changelog & Commit](phases/04-changelog-commit.md) -- Generate changelog, create release commit, push
|
||||
5. **Phase 5**: [PR Creation](phases/05-pr-creation.md) -- Create PR with structured body and issue links
|
||||
|
||||
## Pre-Flight Checklist (Quick Reference)
|
||||
|
||||
| Check | Command | Pass Condition |
|
||||
|-------|---------|----------------|
|
||||
| Git clean | `git status --porcelain` | Empty output |
|
||||
| Branch | `git branch --show-current` | Not main/master |
|
||||
| Tests | `npm test` / `pytest` | Exit code 0 |
|
||||
| Build | `npm run build` / `python -m build` | Exit code 0 |
|
||||
|
||||
## Completion Status Protocol
|
||||
|
||||
This skill follows the Completion Status Protocol defined in [SKILL-DESIGN-SPEC.md sections 13-14](../_shared/SKILL-DESIGN-SPEC.md#13-completion-status-protocol).
|
||||
|
||||
Every execution terminates with one of:
|
||||
|
||||
| Status | When |
|
||||
|--------|------|
|
||||
| **DONE** | All 5 phases completed, PR created |
|
||||
| **DONE_WITH_CONCERNS** | PR created but with review warnings or non-critical issues |
|
||||
| **BLOCKED** | A gate failed (dirty git, tests fail, push rejected) |
|
||||
| **NEEDS_CONTEXT** | Cannot determine bump type, ambiguous branch target |
|
||||
|
||||
### Escalation
|
||||
|
||||
Follows the Three-Strike Rule (SKILL-DESIGN-SPEC section 14). On 3 consecutive failures at the same step, stop and output diagnostic dump.
|
||||
|
||||
## Reference Documents
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| [phases/01-preflight-checks.md](phases/01-preflight-checks.md) | Git, branch, test, build validation |
|
||||
| [phases/02-code-review.md](phases/02-code-review.md) | AI-powered diff review |
|
||||
| [phases/03-version-bump.md](phases/03-version-bump.md) | Version detection and bump |
|
||||
| [phases/04-changelog-commit.md](phases/04-changelog-commit.md) | Changelog generation and release commit |
|
||||
| [phases/05-pr-creation.md](phases/05-pr-creation.md) | PR creation with issue linking |
|
||||
| [../_shared/SKILL-DESIGN-SPEC.md](../_shared/SKILL-DESIGN-SPEC.md) | Skill design spec (completion protocol, escalation) |
|
||||
121
.claude/skills/ship/phases/01-preflight-checks.md
Normal file
121
.claude/skills/ship/phases/01-preflight-checks.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# Phase 1: Pre-Flight Checks
|
||||
|
||||
Validate that the repository is in a shippable state before proceeding with the release pipeline.
|
||||
|
||||
## Objective
|
||||
|
||||
- Confirm working tree is clean (no uncommitted changes)
|
||||
- Validate current branch is appropriate for release
|
||||
- Run test suite and confirm all tests pass
|
||||
- Verify build succeeds
|
||||
|
||||
## Gate Condition
|
||||
|
||||
ALL four checks must pass. If any check fails, stop the pipeline and report BLOCKED status with the specific failure.
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Git Clean Check
|
||||
|
||||
```bash
|
||||
git_status=$(git status --porcelain)
|
||||
if [ -n "$git_status" ]; then
|
||||
echo "FAIL: Working tree is dirty"
|
||||
echo "$git_status"
|
||||
# Gate: BLOCKED — commit or stash changes first
|
||||
else
|
||||
echo "PASS: Working tree is clean"
|
||||
fi
|
||||
```
|
||||
|
||||
**Pass condition**: `git status --porcelain` produces empty output.
|
||||
**On failure**: Report dirty files and suggest `git stash` or `git commit`.
|
||||
|
||||
### Step 2: Branch Validation
|
||||
|
||||
```bash
|
||||
current_branch=$(git branch --show-current)
|
||||
if [ "$current_branch" = "main" ] || [ "$current_branch" = "master" ]; then
|
||||
echo "WARN: Currently on $current_branch — direct push to main/master is risky"
|
||||
# Ask user for confirmation before proceeding
|
||||
else
|
||||
echo "PASS: On branch $current_branch"
|
||||
fi
|
||||
```
|
||||
|
||||
**Pass condition**: Not on main/master, OR user explicitly confirms direct-to-main release.
|
||||
**On warning**: Ask user to confirm they intend to release from main/master directly.
|
||||
|
||||
### Step 3: Test Suite Execution
|
||||
|
||||
Detect and run the project's test suite:
|
||||
|
||||
```bash
|
||||
# Detection priority:
|
||||
# 1. package.json with "test" script → npm test
|
||||
# 2. pytest available and tests exist → pytest
|
||||
# 3. No tests found → WARN and continue
|
||||
|
||||
if [ -f "package.json" ] && grep -q '"test"' package.json; then
|
||||
npm test
|
||||
elif command -v pytest &>/dev/null && [ -d "tests" -o -d "test" ]; then
|
||||
pytest
|
||||
elif [ -f "pyproject.toml" ] && grep -q 'pytest' pyproject.toml; then
|
||||
pytest
|
||||
else
|
||||
echo "WARN: No test suite detected — skipping test check"
|
||||
fi
|
||||
```
|
||||
|
||||
**Pass condition**: Test command exits with code 0, or no tests detected (warn).
|
||||
**On failure**: Report test failures and stop the pipeline.
|
||||
|
||||
### Step 4: Build Verification
|
||||
|
||||
Detect and run the project's build step:
|
||||
|
||||
```bash
|
||||
# Detection priority:
|
||||
# 1. package.json with "build" script → npm run build
|
||||
# 2. pyproject.toml → python -m build (if build module available)
|
||||
# 3. Makefile with build target → make build
|
||||
# 4. No build step → PASS (not all projects need a build)
|
||||
|
||||
if [ -f "package.json" ] && grep -q '"build"' package.json; then
|
||||
npm run build
|
||||
elif [ -f "pyproject.toml" ] && python -m build --help &>/dev/null; then
|
||||
python -m build
|
||||
elif [ -f "Makefile" ] && grep -q '^build:' Makefile; then
|
||||
make build
|
||||
else
|
||||
echo "INFO: No build step detected — skipping build check"
|
||||
fi
|
||||
```
|
||||
|
||||
**Pass condition**: Build command exits with code 0, or no build step detected.
|
||||
**On failure**: Report build errors and stop the pipeline.
|
||||
|
||||
## Output
|
||||
|
||||
- **Format**: JSON object with pass/fail per check
|
||||
- **Structure**:
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": "preflight",
|
||||
"timestamp": "ISO-8601",
|
||||
"checks": {
|
||||
"git_clean": { "status": "pass|fail", "details": "" },
|
||||
"branch": { "status": "pass|warn", "current": "branch-name", "details": "" },
|
||||
"tests": { "status": "pass|fail|skip", "details": "" },
|
||||
"build": { "status": "pass|fail|skip", "details": "" }
|
||||
},
|
||||
"overall": "pass|fail",
|
||||
"blockers": []
|
||||
}
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
If all checks pass, proceed to [Phase 2: Code Review](02-code-review.md).
|
||||
If any check fails, report BLOCKED status with the preflight report.
|
||||
137
.claude/skills/ship/phases/02-code-review.md
Normal file
137
.claude/skills/ship/phases/02-code-review.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Phase 2: Code Review
|
||||
|
||||
Automated AI-powered code review of changes since the base branch, with risk assessment.
|
||||
|
||||
## Objective
|
||||
|
||||
- Detect the merge base between current branch and target branch
|
||||
- Generate diff for review
|
||||
- Run AI-powered code review via CCW CLI
|
||||
- Flag high-risk changes (large diffs, sensitive files, breaking changes)
|
||||
|
||||
## Gate Condition
|
||||
|
||||
No critical issues flagged by the review. Warnings are reported but do not block.
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Detect Merge Base
|
||||
|
||||
```bash
|
||||
# Determine target branch (default: main, fallback: master)
|
||||
target_branch="main"
|
||||
if ! git rev-parse --verify "origin/$target_branch" &>/dev/null; then
|
||||
target_branch="master"
|
||||
fi
|
||||
|
||||
# Find merge base
|
||||
merge_base=$(git merge-base "origin/$target_branch" HEAD)
|
||||
echo "Merge base: $merge_base"
|
||||
|
||||
# If on main/master directly, compare against last tag
|
||||
current_branch=$(git branch --show-current)
|
||||
if [ "$current_branch" = "main" ] || [ "$current_branch" = "master" ]; then
|
||||
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
if [ -n "$last_tag" ]; then
|
||||
merge_base="$last_tag"
|
||||
echo "On main — using last tag as base: $last_tag"
|
||||
else
|
||||
# Use first commit if no tags exist
|
||||
merge_base=$(git rev-list --max-parents=0 HEAD | head -1)
|
||||
echo "No tags found — using initial commit as base"
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
### Step 2: Generate Diff Summary
|
||||
|
||||
```bash
|
||||
# File-level summary
|
||||
git diff --stat "$merge_base"...HEAD
|
||||
|
||||
# Full diff for review
|
||||
git diff "$merge_base"...HEAD > /tmp/ship-review-diff.txt
|
||||
|
||||
# Count changes for risk assessment
|
||||
files_changed=$(git diff --name-only "$merge_base"...HEAD | wc -l)
|
||||
lines_added=$(git diff --numstat "$merge_base"...HEAD | awk '{s+=$1} END {print s}')
|
||||
lines_removed=$(git diff --numstat "$merge_base"...HEAD | awk '{s+=$2} END {print s}')
|
||||
```
|
||||
|
||||
### Step 3: Risk Assessment
|
||||
|
||||
Flag high-risk indicators before AI review:
|
||||
|
||||
| Risk Factor | Threshold | Risk Level |
|
||||
|-------------|-----------|------------|
|
||||
| Files changed | > 50 | High |
|
||||
| Lines changed | > 1000 | High |
|
||||
| Sensitive files modified | Any of: `.env*`, `*secret*`, `*credential*`, `*auth*`, `*.key`, `*.pem` | High |
|
||||
| Config files modified | `package.json`, `pyproject.toml`, `tsconfig.json`, `Dockerfile` | Medium |
|
||||
| Migration files | `*migration*`, `*migrate*` | Medium |
|
||||
|
||||
```bash
|
||||
# Check for sensitive file changes
|
||||
sensitive_files=$(git diff --name-only "$merge_base"...HEAD | grep -iE '\.(env|key|pem)|secret|credential' || true)
|
||||
if [ -n "$sensitive_files" ]; then
|
||||
echo "HIGH RISK: Sensitive files modified:"
|
||||
echo "$sensitive_files"
|
||||
fi
|
||||
```
|
||||
|
||||
### Step 4: AI Code Review
|
||||
|
||||
Use CCW CLI for automated analysis:
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Review code changes for release readiness; success = all critical issues identified with file:line references
|
||||
TASK: Review diff for bugs | Check for breaking changes | Identify security concerns | Assess test coverage gaps
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Reviewing diff from $merge_base to HEAD ($files_changed files, +$lines_added/-$lines_removed lines)
|
||||
EXPECTED: Risk assessment (low/medium/high), list of issues with severity and file:line, release recommendation (ship/hold/fix-first)
|
||||
CONSTRAINTS: Focus on correctness and security | Flag breaking API changes | Ignore formatting-only changes
|
||||
" --tool gemini --mode analysis
|
||||
```
|
||||
|
||||
**Note**: Wait for the CLI analysis to complete before proceeding. Do not proceed to Phase 3 while review is running.
|
||||
|
||||
### Step 5: Evaluate Review Results
|
||||
|
||||
Based on the AI review output:
|
||||
|
||||
| Review Result | Action |
|
||||
|---------------|--------|
|
||||
| No critical issues | Proceed to Phase 3 |
|
||||
| Critical issues found | Report BLOCKED, list issues |
|
||||
| Warnings only | Proceed with DONE_WITH_CONCERNS note |
|
||||
| Review failed/timeout | Ask user whether to proceed or retry |
|
||||
|
||||
## Output
|
||||
|
||||
- **Format**: Review summary with risk assessment
|
||||
- **Structure**:
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": "code-review",
|
||||
"merge_base": "commit-sha",
|
||||
"stats": {
|
||||
"files_changed": 0,
|
||||
"lines_added": 0,
|
||||
"lines_removed": 0
|
||||
},
|
||||
"risk_level": "low|medium|high",
|
||||
"risk_factors": [],
|
||||
"ai_review": {
|
||||
"recommendation": "ship|hold|fix-first",
|
||||
"critical_issues": [],
|
||||
"warnings": []
|
||||
},
|
||||
"overall": "pass|fail|warn"
|
||||
}
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
If review passes (no critical issues), proceed to [Phase 3: Version Bump](03-version-bump.md).
|
||||
If critical issues found, report BLOCKED status with review summary.
|
||||
171
.claude/skills/ship/phases/03-version-bump.md
Normal file
171
.claude/skills/ship/phases/03-version-bump.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Phase 3: Version Bump
|
||||
|
||||
Detect the current version, determine the bump type, and update the version file.
|
||||
|
||||
## Objective
|
||||
|
||||
- Detect which version file the project uses
|
||||
- Read the current version
|
||||
- Determine bump type (patch/minor/major) from commit messages or user input
|
||||
- Update the version file
|
||||
- Record the version change
|
||||
|
||||
## Gate Condition
|
||||
|
||||
Version file updated successfully with the new version.
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Detect Version File
|
||||
|
||||
Detection priority order:
|
||||
|
||||
| Priority | File | Read Method |
|
||||
|----------|------|-------------|
|
||||
| 1 | `package.json` | `jq -r .version package.json` |
|
||||
| 2 | `pyproject.toml` | `grep -oP 'version\s*=\s*"\K[^"]+' pyproject.toml` |
|
||||
| 3 | `VERSION` | `cat VERSION` |
|
||||
|
||||
```bash
|
||||
if [ -f "package.json" ]; then
|
||||
version_file="package.json"
|
||||
current_version=$(node -p "require('./package.json').version" 2>/dev/null || jq -r .version package.json)
|
||||
elif [ -f "pyproject.toml" ]; then
|
||||
version_file="pyproject.toml"
|
||||
current_version=$(grep -oP 'version\s*=\s*"\K[^"]+' pyproject.toml | head -1)
|
||||
elif [ -f "VERSION" ]; then
|
||||
version_file="VERSION"
|
||||
current_version=$(cat VERSION | tr -d '[:space:]')
|
||||
else
|
||||
echo "NEEDS_CONTEXT: No version file found"
|
||||
echo "Expected one of: package.json, pyproject.toml, VERSION"
|
||||
# Ask user which file to use or create
|
||||
fi
|
||||
|
||||
echo "Version file: $version_file"
|
||||
echo "Current version: $current_version"
|
||||
```
|
||||
|
||||
### Step 2: Determine Bump Type
|
||||
|
||||
**Auto-detection from commit messages** (conventional commits):
|
||||
|
||||
```bash
|
||||
# Get commits since last tag
|
||||
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
if [ -n "$last_tag" ]; then
|
||||
commits=$(git log "$last_tag"..HEAD --oneline)
|
||||
else
|
||||
commits=$(git log --oneline -20)
|
||||
fi
|
||||
|
||||
# Scan for conventional commit prefixes
|
||||
has_breaking=$(echo "$commits" | grep -iE '(BREAKING CHANGE|!:)' || true)
|
||||
has_feat=$(echo "$commits" | grep -iE '^[a-f0-9]+ feat' || true)
|
||||
has_fix=$(echo "$commits" | grep -iE '^[a-f0-9]+ fix' || true)
|
||||
|
||||
if [ -n "$has_breaking" ]; then
|
||||
suggested_bump="major"
|
||||
elif [ -n "$has_feat" ]; then
|
||||
suggested_bump="minor"
|
||||
else
|
||||
suggested_bump="patch"
|
||||
fi
|
||||
|
||||
echo "Suggested bump: $suggested_bump"
|
||||
```
|
||||
|
||||
**User confirmation**:
|
||||
- For `patch` and `minor`: proceed with suggested bump, inform user
|
||||
- For `major`: always ask user to confirm before proceeding (major bumps have significant implications)
|
||||
- User can override the suggestion with an explicit bump type
|
||||
|
||||
### Step 3: Calculate New Version
|
||||
|
||||
```bash
|
||||
# Parse semver components
|
||||
IFS='.' read -r major minor patch <<< "$current_version"
|
||||
|
||||
case "$bump_type" in
|
||||
major)
|
||||
new_version="$((major + 1)).0.0"
|
||||
;;
|
||||
minor)
|
||||
new_version="${major}.$((minor + 1)).0"
|
||||
;;
|
||||
patch)
|
||||
new_version="${major}.${minor}.$((patch + 1))"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Version bump: $current_version -> $new_version"
|
||||
```
|
||||
|
||||
### Step 4: Update Version File
|
||||
|
||||
```bash
|
||||
case "$version_file" in
|
||||
package.json)
|
||||
# Use node/jq for safe JSON update
|
||||
jq --arg v "$new_version" '.version = $v' package.json > tmp.json && mv tmp.json package.json
|
||||
# Also update package-lock.json if it exists
|
||||
if [ -f "package-lock.json" ]; then
|
||||
jq --arg v "$new_version" '.version = $v | .packages[""].version = $v' package-lock.json > tmp.json && mv tmp.json package-lock.json
|
||||
fi
|
||||
;;
|
||||
pyproject.toml)
|
||||
# Use sed for TOML update (version line in [project] or [tool.poetry])
|
||||
sed -i "s/^version\s*=\s*\".*\"/version = \"$new_version\"/" pyproject.toml
|
||||
;;
|
||||
VERSION)
|
||||
echo "$new_version" > VERSION
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Updated $version_file: $current_version -> $new_version"
|
||||
```
|
||||
|
||||
### Step 5: Verify Update
|
||||
|
||||
```bash
|
||||
# Re-read to confirm
|
||||
case "$version_file" in
|
||||
package.json)
|
||||
verified=$(node -p "require('./package.json').version" 2>/dev/null || jq -r .version package.json)
|
||||
;;
|
||||
pyproject.toml)
|
||||
verified=$(grep -oP 'version\s*=\s*"\K[^"]+' pyproject.toml | head -1)
|
||||
;;
|
||||
VERSION)
|
||||
verified=$(cat VERSION | tr -d '[:space:]')
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$verified" = "$new_version" ]; then
|
||||
echo "PASS: Version verified as $new_version"
|
||||
else
|
||||
echo "FAIL: Version mismatch — expected $new_version, got $verified"
|
||||
fi
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **Format**: Version change record
|
||||
- **Structure**:
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": "version-bump",
|
||||
"version_file": "package.json",
|
||||
"previous_version": "1.2.3",
|
||||
"new_version": "1.3.0",
|
||||
"bump_type": "minor",
|
||||
"bump_source": "auto-detected|user-specified",
|
||||
"overall": "pass|fail"
|
||||
}
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
If version updated successfully, proceed to [Phase 4: Changelog & Commit](04-changelog-commit.md).
|
||||
If version update fails, report BLOCKED status.
|
||||
167
.claude/skills/ship/phases/04-changelog-commit.md
Normal file
167
.claude/skills/ship/phases/04-changelog-commit.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# Phase 4: Changelog & Commit
|
||||
|
||||
Generate changelog entry from git history, update CHANGELOG.md, create release commit, and push to remote.
|
||||
|
||||
## Objective
|
||||
|
||||
- Parse git log since last tag into grouped changelog entry
|
||||
- Update or create CHANGELOG.md
|
||||
- Create a release commit with version in the message
|
||||
- Push the branch to remote
|
||||
|
||||
## Gate Condition
|
||||
|
||||
Release commit created and pushed to remote successfully.
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Gather Commits Since Last Tag
|
||||
|
||||
```bash
|
||||
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$last_tag" ]; then
|
||||
echo "Generating changelog since tag: $last_tag"
|
||||
git log "$last_tag"..HEAD --pretty=format:"%h %s" --no-merges
|
||||
else
|
||||
echo "No previous tag found — using last 50 commits"
|
||||
git log --pretty=format:"%h %s" --no-merges -50
|
||||
fi
|
||||
```
|
||||
|
||||
### Step 2: Group Commits by Conventional Commit Type
|
||||
|
||||
Parse commit messages and group into categories:
|
||||
|
||||
| Prefix | Category | Changelog Section |
|
||||
|--------|----------|-------------------|
|
||||
| `feat:` / `feat(*):`| Features | **Features** |
|
||||
| `fix:` / `fix(*):`| Bug Fixes | **Bug Fixes** |
|
||||
| `perf:` | Performance | **Performance** |
|
||||
| `docs:` | Documentation | **Documentation** |
|
||||
| `refactor:` | Refactoring | **Refactoring** |
|
||||
| `chore:` | Maintenance | **Maintenance** |
|
||||
| `test:` | Testing | *(omitted from changelog)* |
|
||||
| Other | Miscellaneous | **Other Changes** |
|
||||
|
||||
```bash
|
||||
# Example grouping logic (executed by the agent, not a literal script):
|
||||
# 1. Read all commits since last tag
|
||||
# 2. Parse prefix from each commit message
|
||||
# 3. Group into categories
|
||||
# 4. Format as markdown sections
|
||||
# 5. Omit empty categories
|
||||
```
|
||||
|
||||
### Step 3: Format Changelog Entry
|
||||
|
||||
Generate a markdown changelog entry:
|
||||
|
||||
```markdown
|
||||
## [X.Y.Z] - YYYY-MM-DD
|
||||
|
||||
### Features
|
||||
- feat: description (sha)
|
||||
- feat(scope): description (sha)
|
||||
|
||||
### Bug Fixes
|
||||
- fix: description (sha)
|
||||
|
||||
### Performance
|
||||
- perf: description (sha)
|
||||
|
||||
### Other Changes
|
||||
- chore: description (sha)
|
||||
```
|
||||
|
||||
Rules:
|
||||
- Date format: YYYY-MM-DD (ISO 8601)
|
||||
- Each entry includes the short SHA for traceability
|
||||
- Empty categories are omitted
|
||||
- Entries are listed in chronological order within each category
|
||||
|
||||
### Step 4: Update CHANGELOG.md
|
||||
|
||||
```bash
|
||||
if [ -f "CHANGELOG.md" ]; then
|
||||
# Insert new entry after the first heading line (# Changelog)
|
||||
# The new entry goes between the main heading and the previous version entry
|
||||
# Use Write tool to insert the new section at the correct position
|
||||
echo "Updating existing CHANGELOG.md"
|
||||
else
|
||||
# Create new CHANGELOG.md with header
|
||||
echo "Creating new CHANGELOG.md"
|
||||
fi
|
||||
```
|
||||
|
||||
**CHANGELOG.md structure**:
|
||||
```markdown
|
||||
# Changelog
|
||||
|
||||
## [X.Y.Z] - YYYY-MM-DD
|
||||
(new entry here)
|
||||
|
||||
## [X.Y.Z-1] - YYYY-MM-DD
|
||||
(previous entry)
|
||||
```
|
||||
|
||||
### Step 5: Create Release Commit
|
||||
|
||||
```bash
|
||||
# Stage version file and changelog
|
||||
git add package.json package-lock.json pyproject.toml VERSION CHANGELOG.md 2>/dev/null
|
||||
|
||||
# Only stage files that actually exist and are modified
|
||||
git add -u
|
||||
|
||||
# Create release commit
|
||||
git commit -m "$(cat <<'EOF'
|
||||
chore: bump version to X.Y.Z
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
**Commit message format**: `chore: bump version to X.Y.Z`
|
||||
- Follows conventional commit format
|
||||
- Includes Co-Authored-By trailer
|
||||
|
||||
### Step 6: Push to Remote
|
||||
|
||||
```bash
|
||||
current_branch=$(git branch --show-current)
|
||||
|
||||
# Check if remote tracking branch exists
|
||||
if git rev-parse --verify "origin/$current_branch" &>/dev/null; then
|
||||
git push origin "$current_branch"
|
||||
else
|
||||
git push -u origin "$current_branch"
|
||||
fi
|
||||
```
|
||||
|
||||
**On push failure**:
|
||||
- If rejected (non-fast-forward): Report BLOCKED, suggest `git pull --rebase`
|
||||
- If permission denied: Report BLOCKED, check remote access
|
||||
- If no remote configured: Report BLOCKED, suggest `git remote add`
|
||||
|
||||
## Output
|
||||
|
||||
- **Format**: Commit and push record
|
||||
- **Structure**:
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": "changelog-commit",
|
||||
"changelog_entry": "## [X.Y.Z] - YYYY-MM-DD ...",
|
||||
"commit_sha": "abc1234",
|
||||
"commit_message": "chore: bump version to X.Y.Z",
|
||||
"pushed_to": "origin/branch-name",
|
||||
"overall": "pass|fail"
|
||||
}
|
||||
```
|
||||
|
||||
## Next Phase
|
||||
|
||||
If commit and push succeed, proceed to [Phase 5: PR Creation](05-pr-creation.md).
|
||||
If push fails, report BLOCKED status with error details.
|
||||
163
.claude/skills/ship/phases/05-pr-creation.md
Normal file
163
.claude/skills/ship/phases/05-pr-creation.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# Phase 5: PR Creation
|
||||
|
||||
Create a pull request via GitHub CLI with a structured body, linked issues, and release metadata.
|
||||
|
||||
## Objective
|
||||
|
||||
- Create a PR using `gh pr create` with structured body
|
||||
- Auto-link related issues from commit messages
|
||||
- Include release summary (version, changes, test plan)
|
||||
- Output the PR URL
|
||||
|
||||
## Gate Condition
|
||||
|
||||
PR created successfully and URL returned.
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Extract Issue References from Commits
|
||||
|
||||
```bash
|
||||
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$last_tag" ]; then
|
||||
commits=$(git log "$last_tag"..HEAD --pretty=format:"%s" --no-merges)
|
||||
else
|
||||
commits=$(git log --pretty=format:"%s" --no-merges -50)
|
||||
fi
|
||||
|
||||
# Extract issue references: fixes #N, closes #N, resolves #N, refs #N
|
||||
issues=$(echo "$commits" | grep -oiE '(fix(es)?|close[sd]?|resolve[sd]?|refs?)\s*#[0-9]+' | grep -oE '#[0-9]+' | sort -u || true)
|
||||
|
||||
echo "Referenced issues: $issues"
|
||||
```
|
||||
|
||||
### Step 2: Determine Target Branch
|
||||
|
||||
```bash
|
||||
# Default target: main (fallback: master)
|
||||
target_branch="main"
|
||||
if ! git rev-parse --verify "origin/$target_branch" &>/dev/null; then
|
||||
target_branch="master"
|
||||
fi
|
||||
|
||||
current_branch=$(git branch --show-current)
|
||||
echo "PR: $current_branch -> $target_branch"
|
||||
```
|
||||
|
||||
### Step 3: Build PR Title
|
||||
|
||||
Format: `release: vX.Y.Z`
|
||||
|
||||
```bash
|
||||
pr_title="release: v${new_version}"
|
||||
```
|
||||
|
||||
If the version context is not available, fall back to a descriptive title from the branch name.
|
||||
|
||||
### Step 4: Build PR Body
|
||||
|
||||
Construct the PR body using a HEREDOC for correct formatting:
|
||||
|
||||
```bash
|
||||
# Gather change summary
|
||||
change_summary=$(git log "$merge_base"..HEAD --pretty=format:"- %s (%h)" --no-merges)
|
||||
|
||||
# Build linked issues section
|
||||
if [ -n "$issues" ]; then
|
||||
issues_section="## Linked Issues
|
||||
$(echo "$issues" | while read -r issue; do echo "- $issue"; done)"
|
||||
else
|
||||
issues_section=""
|
||||
fi
|
||||
```
|
||||
|
||||
### Step 5: Create PR via gh CLI
|
||||
|
||||
```bash
|
||||
gh pr create --title "$pr_title" --base "$target_branch" --body "$(cat <<'EOF'
|
||||
## Summary
|
||||
Release vX.Y.Z
|
||||
|
||||
### Changes
|
||||
- list of changes from changelog
|
||||
|
||||
## Linked Issues
|
||||
- #N (fixes)
|
||||
- #M (closes)
|
||||
|
||||
## Version
|
||||
- Previous: X.Y.Z-1
|
||||
- New: X.Y.Z
|
||||
- Bump type: patch|minor|major
|
||||
|
||||
## Test Plan
|
||||
- [ ] Pre-flight checks passed (git clean, branch, tests, build)
|
||||
- [ ] AI code review completed with no critical issues
|
||||
- [ ] Version bump verified in version file
|
||||
- [ ] Changelog updated with all changes since last release
|
||||
- [ ] Release commit pushed successfully
|
||||
|
||||
Generated with [Claude Code](https://claude.com/claude-code)
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
**PR body sections**:
|
||||
|
||||
| Section | Content |
|
||||
|---------|---------|
|
||||
| **Summary** | Version being released, one-line description |
|
||||
| **Changes** | Grouped changelog entries (from Phase 4) |
|
||||
| **Linked Issues** | Auto-extracted `fixes #N`, `closes #N` references |
|
||||
| **Version** | Previous version, new version, bump type |
|
||||
| **Test Plan** | Checklist confirming all phases passed |
|
||||
|
||||
### Step 6: Capture and Report PR URL
|
||||
|
||||
```bash
|
||||
# gh pr create outputs the PR URL on success
|
||||
pr_url=$(gh pr create ... 2>&1 | tail -1)
|
||||
echo "PR created: $pr_url"
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **Format**: PR creation record
|
||||
- **Structure**:
|
||||
|
||||
```json
|
||||
{
|
||||
"phase": "pr-creation",
|
||||
"pr_url": "https://github.com/owner/repo/pull/N",
|
||||
"pr_title": "release: vX.Y.Z",
|
||||
"target_branch": "main",
|
||||
"source_branch": "feature-branch",
|
||||
"linked_issues": ["#1", "#2"],
|
||||
"overall": "pass|fail"
|
||||
}
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
After PR creation, output the final Completion Status:
|
||||
|
||||
```
|
||||
## STATUS: DONE
|
||||
|
||||
**Summary**: Released vX.Y.Z — PR created at {pr_url}
|
||||
|
||||
### Details
|
||||
- Phases completed: 5/5
|
||||
- Version: {previous} -> {new} ({bump_type})
|
||||
- PR: {pr_url}
|
||||
- Key outputs: CHANGELOG.md updated, release commit pushed, PR created
|
||||
|
||||
### Outputs
|
||||
- CHANGELOG.md (updated)
|
||||
- {version_file} (version bumped)
|
||||
- Release commit: {sha}
|
||||
- PR: {pr_url}
|
||||
```
|
||||
|
||||
If there were review warnings, use `DONE_WITH_CONCERNS` and list the warnings in the Details section.
|
||||
@@ -80,6 +80,11 @@ Generate Phase files for Sequential execution mode, defining fixed-order executi
|
||||
|
||||
{{quality_checklist}}
|
||||
|
||||
## Completion Status
|
||||
|
||||
Return one of: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT with structured reason.
|
||||
See [Completion Status Protocol](./../_shared/SKILL-DESIGN-SPEC.md#13) for output format.
|
||||
|
||||
## Next Phase
|
||||
|
||||
{{next_phase_link}}
|
||||
@@ -456,6 +461,11 @@ Write(\`${workDir}/${phaseConfig.output}\`, JSON.stringify(result, null, 2));
|
||||
- [ ] Core logic executed successfully
|
||||
- [ ] Output format correct
|
||||
|
||||
## Completion Status
|
||||
|
||||
Return one of: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT with structured reason.
|
||||
See [Completion Status Protocol](./../_shared/SKILL-DESIGN-SPEC.md#13) for output format.
|
||||
|
||||
${nextPhase ?
|
||||
`## Next Phase\n\n→ [Phase ${index + 2}: ${nextPhase.name}](${nextPhase.id}.md)` :
|
||||
'## Completion\n\nThis is the final phase.'}
|
||||
|
||||
@@ -80,6 +80,10 @@ Bash(\`mkdir -p "\${workDir}"\`);
|
||||
{{output_structure}}
|
||||
\`\`\`
|
||||
|
||||
## Completion Protocol
|
||||
|
||||
Follow [Completion Status Protocol](./../_shared/SKILL-DESIGN-SPEC.md#13) and [Escalation Protocol](./../_shared/SKILL-DESIGN-SPEC.md#14).
|
||||
|
||||
## Reference Documents by Phase
|
||||
|
||||
> **Important**: Reference documents should be organized by execution phase, clearly marking when and in what scenarios they are used. Avoid listing documents in a flat manner.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: spec-generator
|
||||
description: Specification generator - 6 phase document chain producing product brief, PRD, architecture, and epics. Triggers on "generate spec", "create specification", "spec generator", "workflow:spec".
|
||||
description: "Specification generator - 7 phase document chain producing product brief, PRD, architecture, epics, and issues with Codex review gates. Triggers on generate spec, create specification, spec generator, workflow:spec."
|
||||
allowed-tools: Agent, AskUserQuestion, TaskCreate, TaskUpdate, TaskList, Read, Write, Edit, Bash, Glob, Grep, Skill
|
||||
---
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5
|
||||
})
|
||||
```
|
||||
|
||||
**Inner Loop roles** (refactorer): Set `inner_loop: true`.
|
||||
**Inner Loop roles** (refactorer): Set `inner_loop` dynamically — `true` for single mode, `false` for fan-out/independent (parallel branches).
|
||||
**Single-task roles** (analyzer, designer, validator, reviewer): Set `inner_loop: false`.
|
||||
|
||||
## User Commands
|
||||
|
||||
@@ -82,7 +82,9 @@ Find ready tasks, spawn workers, STOP.
|
||||
2. No ready + work in progress -> report waiting, STOP
|
||||
3. No ready + nothing in progress -> handleComplete
|
||||
4. Has ready -> for each:
|
||||
a. Check if inner loop role with active worker -> skip (worker picks up)
|
||||
a. Check inner_loop: parse task description `InnerLoop:` field (NOT role.md default)
|
||||
- InnerLoop: true AND same-role worker already active -> skip (worker picks up)
|
||||
- InnerLoop: false OR no active same-role worker -> spawn new worker
|
||||
b. TaskUpdate -> in_progress
|
||||
c. team_msg log -> task_unblocked
|
||||
d. Spawn team-worker (see SKILL.md Spawn Template):
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
---
|
||||
role: refactorer
|
||||
prefix: REFACTOR
|
||||
inner_loop: true
|
||||
inner_loop: dynamic
|
||||
message_types: [state_update]
|
||||
---
|
||||
|
||||
# Code Refactorer
|
||||
|
||||
> **inner_loop: dynamic** — Dispatch sets per-task: `true` for single mode (one REFACTOR task with iterative fix cycles), `false` for fan-out/independent modes (REFACTOR-B01..N run as separate parallel workers). When false, each branch gets its own worker.
|
||||
|
||||
Implement architecture refactoring changes following the design plan. For FIX tasks, apply targeted corrections based on review/validation feedback.
|
||||
|
||||
## Modes
|
||||
|
||||
@@ -64,10 +64,10 @@
|
||||
"type": "code_generation",
|
||||
"description": "Implements architecture refactoring changes following the design plan",
|
||||
"role_spec": "roles/refactorer/role.md",
|
||||
"inner_loop": true,
|
||||
"inner_loop": "dynamic",
|
||||
"frontmatter": {
|
||||
"prefix": "REFACTOR",
|
||||
"inner_loop": true,
|
||||
"inner_loop": "dynamic",
|
||||
"additional_prefixes": ["FIX"],
|
||||
"discuss_rounds": [],
|
||||
"cli_tools": ["explore"],
|
||||
|
||||
@@ -130,9 +130,10 @@ Execute built-in Phase 1 (task discovery) -> role-spec Phase 2-4 -> built-in Pha
|
||||
})
|
||||
```
|
||||
|
||||
**Inner Loop roles** (role has 2+ serial same-prefix tasks): Set `inner_loop: true`. The team-worker agent handles the loop internally.
|
||||
|
||||
**Single-task roles**: Set `inner_loop: false`.
|
||||
**Inner Loop**: Determined per-task from task description `InnerLoop:` field, not per-role:
|
||||
- Serial chain (2+ tasks, each blockedBy previous): `inner_loop: true` — single worker loops
|
||||
- Parallel tasks (no mutual blockedBy): `inner_loop: false` — separate workers per task
|
||||
- Single-task roles: `inner_loop: false`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ For each role, determine frontmatter and generation hints:
|
||||
| Field | Derivation |
|
||||
|-------|------------|
|
||||
| `prefix` | From capability prefix (e.g., RESEARCH, DRAFT, IMPL) |
|
||||
| `inner_loop` | `true` if role has 2+ serial same-prefix tasks |
|
||||
| `inner_loop` | `true` if role has 2+ same-prefix tasks AND they form a serial chain (each blockedBy the previous). `false` if tasks are parallel (no mutual blockedBy) or role has only 1 task |
|
||||
| `CLI tools` | Suggested, not mandatory — coordinator may adjust based on task needs |
|
||||
| `pattern_hint` | Reference pattern name from role-spec-template (research/document/code/analysis/validation) — guides coordinator's Phase 2-4 composition, NOT a rigid template selector |
|
||||
| `output_type` | `artifact` (new files in session/artifacts/) / `codebase` (modify existing project files) / `mixed` (both) — determines verification strategy in Behavioral Traits |
|
||||
|
||||
@@ -95,9 +95,10 @@ RoleSpec: <session-folder>/role-specs/<role-name>.md
|
||||
|
||||
| Condition | InnerLoop |
|
||||
|-----------|-----------|
|
||||
| Role has 2+ serial same-prefix tasks | true |
|
||||
| Role has 2+ same-prefix tasks forming a serial chain (each blockedBy the previous) | true |
|
||||
| Role has 1 task | false |
|
||||
| Tasks are parallel (no dependency between them) | false |
|
||||
| Role has 2+ same-prefix tasks but they are parallel (no mutual blockedBy) | false |
|
||||
| Mixed: some serial, some parallel within same role | Set per-task: true for serial chain members, false for parallel members |
|
||||
|
||||
### Dependency Validation
|
||||
|
||||
|
||||
@@ -144,9 +144,10 @@ Ready tasks found?
|
||||
+- NONE + work in progress -> report waiting -> STOP
|
||||
+- NONE + nothing in progress -> PIPELINE_COMPLETE -> handleComplete
|
||||
+- HAS ready tasks -> for each:
|
||||
+- Is task owner an Inner Loop role AND that role already has an active_worker?
|
||||
+- Parse task description `InnerLoop:` field (NOT session.roles[].inner_loop)
|
||||
+- InnerLoop: true AND same-role worker already in active_workers?
|
||||
| +- YES -> SKIP spawn (existing worker will pick it up via inner loop)
|
||||
| +- NO -> normal spawn below
|
||||
| +- NO -> normal spawn below (InnerLoop: false OR no active same-role worker)
|
||||
+- TaskUpdate -> in_progress
|
||||
+- team_msg log -> task_unblocked (session_id=<session-id>)
|
||||
+- Spawn team-worker (see spawn tool call below)
|
||||
|
||||
@@ -207,15 +207,9 @@ Regardless of complexity score or role count, coordinator MUST:
|
||||
- `project_root` = result of `Bash({ command: "pwd" })`
|
||||
- `skill_root` = `<project_root>/.claude/skills/team-coordinate`
|
||||
|
||||
2. **Check `needs_research` flag** from task-analysis.json:
|
||||
- If `true`: **Spawn researcher worker first** to gather codebase context
|
||||
- Wait for researcher callback
|
||||
- Merge research findings into task context
|
||||
- Update task-analysis.json with enriched context
|
||||
2. **Generate session ID**: `TC-<slug>-<date>` (slug from first 3 meaningful words of task)
|
||||
|
||||
3. **Generate session ID**: `TC-<slug>-<date>` (slug from first 3 meaningful words of task)
|
||||
|
||||
4. **Create session folder structure**:
|
||||
3. **Create session folder structure**:
|
||||
```
|
||||
.workflow/.team/<session-id>/
|
||||
+-- role-specs/
|
||||
@@ -226,11 +220,11 @@ Regardless of complexity score or role count, coordinator MUST:
|
||||
+-- .msg/
|
||||
```
|
||||
|
||||
5. **Call TeamCreate** with team name derived from session ID
|
||||
4. **Call TeamCreate** with team name derived from session ID
|
||||
|
||||
6. **Read `specs/role-spec-template.md`** for Behavioral Traits + Reference Patterns
|
||||
5. **Read `specs/role-spec-template.md`** for Behavioral Traits + Reference Patterns
|
||||
|
||||
7. **For each role in task-analysis.json#roles**:
|
||||
6. **For each role in task-analysis.json#roles**:
|
||||
- Fill YAML frontmatter: role, prefix, inner_loop, additional_members, message_types
|
||||
- **Compose Phase 2-4 content** (NOT copy from template):
|
||||
- Phase 2: Derive input sources and context loading steps from **task description + upstream dependencies**
|
||||
@@ -239,14 +233,14 @@ Regardless of complexity score or role count, coordinator MUST:
|
||||
- Reference Patterns may guide phase structure, but task description determines specific content
|
||||
- Write generated role-spec to `<session>/role-specs/<role-name>.md`
|
||||
|
||||
8. **Register roles** in team-session.json#roles (with `role_spec` path instead of `role_file`)
|
||||
7. **Register roles** in team-session.json#roles (with `role_spec` path instead of `role_file`)
|
||||
|
||||
9. **Initialize shared infrastructure**:
|
||||
8. **Initialize shared infrastructure**:
|
||||
- `wisdom/learnings.md`, `wisdom/decisions.md`, `wisdom/issues.md` (empty with headers)
|
||||
- `explorations/cache-index.json` (`{ "entries": [] }`)
|
||||
- `discussions/` (empty directory)
|
||||
|
||||
10. **Initialize pipeline metadata** via team_msg:
|
||||
9. **Initialize pipeline metadata** via team_msg:
|
||||
```typescript
|
||||
// 使用 team_msg 将 pipeline 元数据写入 .msg/meta.json
|
||||
// 注意: 此处为动态角色,执行时需将 <placeholders> 替换为 task-analysis.json 中生成的实际角色列表
|
||||
@@ -265,7 +259,14 @@ mcp__ccw-tools__team_msg({
|
||||
})
|
||||
```
|
||||
|
||||
11. **Write team-session.json** with: session_id, task_description, status="active", roles, pipeline (empty), active_workers=[], completion_action="interactive", created_at
|
||||
10. **Write team-session.json** with: session_id, task_description, status="active", roles, pipeline (empty), active_workers=[], completion_action="interactive", created_at
|
||||
|
||||
11. **Check `needs_research` flag** from task-analysis.json:
|
||||
- If `true`: Spawn researcher worker (role-spec now exists from step 6) to gather codebase context
|
||||
- Wait for researcher callback
|
||||
- Merge research findings into task context
|
||||
- Update task-analysis.json with enriched context
|
||||
- If `false`: Skip, proceed to Phase 3
|
||||
|
||||
**Success**: Session created, role-spec files generated, shared infrastructure initialized.
|
||||
|
||||
|
||||
@@ -38,18 +38,20 @@ Phase 3-N: monitor.md
|
||||
|
||||
## Dependency Graph Structure
|
||||
|
||||
task-analysis.json encodes the pipeline:
|
||||
task-analysis.json encodes the pipeline as adjacency list (task ID -> blockedBy array):
|
||||
|
||||
```json
|
||||
{
|
||||
"dependency_graph": {
|
||||
"RESEARCH-001": { "role": "researcher", "blockedBy": [], "priority": "P0" },
|
||||
"IMPL-001": { "role": "developer", "blockedBy": ["RESEARCH-001"], "priority": "P1" },
|
||||
"TEST-001": { "role": "tester", "blockedBy": ["IMPL-001"], "priority": "P2" }
|
||||
"RESEARCH-001": [],
|
||||
"IMPL-001": ["RESEARCH-001"],
|
||||
"TEST-001": ["IMPL-001"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Role mapping comes from `task-analysis.json#capabilities[].tasks[]`, not from the dependency graph itself.
|
||||
|
||||
## Role-Worker Map
|
||||
|
||||
Dynamic — loaded from session role-specs at runtime:
|
||||
@@ -64,6 +66,7 @@ Role-spec files contain YAML frontmatter:
|
||||
role: <role-name>
|
||||
prefix: <PREFIX>
|
||||
inner_loop: <true|false>
|
||||
output_tag: "[<role-name>]"
|
||||
message_types:
|
||||
success: <type>
|
||||
error: error
|
||||
|
||||
@@ -11,6 +11,7 @@ Template used by coordinator to generate lightweight worker role-spec files at r
|
||||
role: <role_name>
|
||||
prefix: <PREFIX>
|
||||
inner_loop: <true|false>
|
||||
output_tag: "[<role_name>]"
|
||||
CLI tools: [<CLI tool-names>]
|
||||
message_types:
|
||||
success: <prefix>_complete
|
||||
|
||||
@@ -37,7 +37,7 @@ The SKILL.md follows a strict template. Every generated SKILL.md contains these
|
||||
```yaml
|
||||
---
|
||||
name: ${teamConfig.skillName}
|
||||
description: ${teamConfig.domain}. Triggers on "${teamConfig.skillName}".
|
||||
description: "${teamConfig.domain}. Triggers on ${teamConfig.skillName}."
|
||||
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Agent(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
|
||||
---
|
||||
```
|
||||
|
||||
127
.claude/skills/team-interactive-craft/SKILL.md
Normal file
127
.claude/skills/team-interactive-craft/SKILL.md
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
name: team-interactive-craft
|
||||
description: Unified team skill for interactive component crafting. Vanilla JS + CSS interactive components with zero dependencies. Research -> interaction design -> build -> a11y test. Uses team-worker agent architecture. Triggers on "team interactive craft", "interactive component".
|
||||
allowed-tools: Agent, AskUserQuestion, Read, Write, Edit, Bash, Glob, Grep, TaskList, TaskGet, TaskUpdate, TaskCreate, TeamCreate, TeamDelete, SendMessage, mcp__ccw-tools__read_file, mcp__ccw-tools__write_file, mcp__ccw-tools__edit_file, mcp__ccw-tools__team_msg
|
||||
---
|
||||
|
||||
# Team Interactive Craft
|
||||
|
||||
Systematic interactive component pipeline: research -> interaction design -> build -> a11y test. Built on **team-worker agent architecture** -- all worker roles share a single agent definition with role-specific Phase 2-4 loaded from `roles/<role>/role.md`.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Skill(skill="team-interactive-craft", args="task description")
|
||||
|
|
||||
SKILL.md (this file) = Router
|
||||
|
|
||||
+--------------+--------------+
|
||||
| |
|
||||
no --role flag --role <name>
|
||||
| |
|
||||
Coordinator Worker
|
||||
roles/coordinator/role.md roles/<name>/role.md
|
||||
|
|
||||
+-- analyze -> dispatch -> spawn workers -> STOP
|
||||
|
|
||||
+-------+-------+-------+-------+
|
||||
v v v v
|
||||
[team-worker agents, each loads roles/<role>/role.md]
|
||||
researcher interaction-designer builder a11y-tester
|
||||
```
|
||||
|
||||
## Role Registry
|
||||
|
||||
| Role | Path | Prefix | Inner Loop |
|
||||
|------|------|--------|------------|
|
||||
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | -- | -- |
|
||||
| researcher | [roles/researcher/role.md](roles/researcher/role.md) | RESEARCH-* | false |
|
||||
| interaction-designer | [roles/interaction-designer/role.md](roles/interaction-designer/role.md) | INTERACT-* | false |
|
||||
| builder | [roles/builder/role.md](roles/builder/role.md) | BUILD-* | true |
|
||||
| a11y-tester | [roles/a11y-tester/role.md](roles/a11y-tester/role.md) | A11Y-* | false |
|
||||
|
||||
## Role Router
|
||||
|
||||
Parse `$ARGUMENTS`:
|
||||
- Has `--role <name>` -> Read `roles/<name>/role.md`, execute Phase 2-4
|
||||
- No `--role` -> `@roles/coordinator/role.md`, execute entry router
|
||||
|
||||
## Shared Constants
|
||||
|
||||
- **Session prefix**: `IC`
|
||||
- **Session path**: `.workflow/.team/IC-<slug>-<date>/`
|
||||
- **CLI tools**: `ccw cli --mode analysis` (read-only), `ccw cli --mode write` (modifications)
|
||||
- **Message bus**: `mcp__ccw-tools__team_msg(session_id=<session-id>, ...)`
|
||||
- **Max GC rounds**: 2
|
||||
|
||||
## Worker Spawn Template
|
||||
|
||||
Coordinator spawns workers using this template:
|
||||
|
||||
```
|
||||
Agent({
|
||||
subagent_type: "team-worker",
|
||||
description: "Spawn <role> worker for <task-id>",
|
||||
team_name: "interactive-craft",
|
||||
name: "<role>",
|
||||
run_in_background: true,
|
||||
prompt: `## Role Assignment
|
||||
role: <role>
|
||||
role_spec: <skill_root>/roles/<role>/role.md
|
||||
session: <session-folder>
|
||||
session_id: <session-id>
|
||||
team_name: interactive-craft
|
||||
requirement: <task-description>
|
||||
inner_loop: <true|false>
|
||||
|
||||
Read role_spec file (@<skill_root>/roles/<role>/role.md) to load Phase 2-4 domain instructions.
|
||||
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).`
|
||||
})
|
||||
```
|
||||
|
||||
## User Commands
|
||||
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| `check` / `status` | View execution status graph |
|
||||
| `resume` / `continue` | Advance to next step |
|
||||
|
||||
## Specs Reference
|
||||
|
||||
- [specs/pipelines.md](specs/pipelines.md) -- Pipeline definitions and task registry
|
||||
- [specs/interaction-patterns.md](specs/interaction-patterns.md) -- Interaction pattern catalog
|
||||
- [specs/vanilla-constraints.md](specs/vanilla-constraints.md) -- Zero-dependency rules
|
||||
|
||||
## Session Directory
|
||||
|
||||
```
|
||||
.workflow/.team/IC-<slug>-<date>/
|
||||
+-- .msg/
|
||||
| +-- messages.jsonl # Team message bus
|
||||
| +-- meta.json # Pipeline config + GC state
|
||||
+-- research/ # Researcher output
|
||||
| +-- interaction-inventory.json
|
||||
| +-- browser-api-audit.json
|
||||
| +-- pattern-reference.json
|
||||
+-- interaction/ # Interaction designer output
|
||||
| +-- blueprints/
|
||||
| +-- {component-name}.md
|
||||
+-- build/ # Builder output
|
||||
| +-- components/
|
||||
| +-- {name}.js
|
||||
| +-- {name}.css
|
||||
+-- a11y/ # A11y tester output
|
||||
| +-- a11y-audit-{NNN}.md
|
||||
+-- wisdom/ # Cross-task knowledge
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Unknown command | Error with available command list |
|
||||
| Role not found | Error with role registry |
|
||||
| Session corruption | Attempt recovery, fallback to manual |
|
||||
| Fast-advance conflict | Coordinator reconciles on next callback |
|
||||
| Completion action fails | Default to Keep Active |
|
||||
| GC loop stuck > 2 rounds | Escalate to user: accept / retry / terminate |
|
||||
159
.claude/skills/team-interactive-craft/roles/a11y-tester/role.md
Normal file
159
.claude/skills/team-interactive-craft/roles/a11y-tester/role.md
Normal file
@@ -0,0 +1,159 @@
|
||||
---
|
||||
role: a11y-tester
|
||||
prefix: A11Y
|
||||
inner_loop: false
|
||||
message_types: [state_update]
|
||||
---
|
||||
|
||||
# Accessibility Tester
|
||||
|
||||
Test interactive components for keyboard navigation, screen reader compatibility, reduced motion fallback, focus management, and color contrast. Act as Critic in the builder<->a11y-tester Generator-Critic loop. Serve as quality gate before pipeline completion.
|
||||
|
||||
## Phase 2: Context & Artifact Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Built components | <session>/build/components/*.js, *.css | Yes |
|
||||
| Interaction blueprints | <session>/interaction/blueprints/*.md | Yes |
|
||||
| Research artifacts | <session>/research/browser-api-audit.json | No |
|
||||
| Previous audits | <session>/a11y/a11y-audit-*.md | Only for GC re-audit |
|
||||
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
|
||||
|
||||
1. Extract session path from task description
|
||||
2. Read all built component files (JS + CSS)
|
||||
3. Read interaction blueprints for expected behavior reference
|
||||
4. If GC re-audit: read previous audit to track improvement/regression
|
||||
5. Load audit history from meta.json for trend analysis
|
||||
|
||||
## Phase 3: Audit Execution
|
||||
|
||||
Test 5 accessibility dimensions. For each, evaluate every built component:
|
||||
|
||||
### Dimension 1: Keyboard Navigation (Weight: 25%)
|
||||
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| Tab order | Scan tabindex values, focusable elements | Logical tab order, no tabindex > 0 |
|
||||
| Arrow key navigation | Check onKeyDown for ArrowLeft/Right/Up/Down | All navigable items reachable via arrows |
|
||||
| Enter/Space activation | Check onKeyDown for Enter, Space | All interactive elements activatable |
|
||||
| Escape dismissal | Check onKeyDown for Escape | Overlays/modals dismiss on Escape |
|
||||
| Focus trap (overlays) | Check focus cycling logic | Tab stays within overlay when open |
|
||||
| No keyboard trap | Verify all states have keyboard exit | Can always Tab/Escape out of component |
|
||||
|
||||
Score: count(pass) / count(total_checks) * 10
|
||||
|
||||
### Dimension 2: Screen Reader Compatibility (Weight: 25%)
|
||||
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| ARIA role | Scan for role attribute | Appropriate role set (slider, dialog, tablist, etc.) |
|
||||
| ARIA label | Scan for aria-label, aria-labelledby | All interactive elements have accessible name |
|
||||
| ARIA states | Scan for aria-expanded, aria-selected, aria-hidden | Dynamic states update with interaction |
|
||||
| Live regions | Scan for aria-live, aria-atomic | State changes announced (polite/assertive as needed) |
|
||||
| Semantic HTML | Check element types | Uses button/a/input where appropriate, not div-only |
|
||||
| Alt text | Check img/svg elements | Decorative: aria-hidden; informative: alt/aria-label |
|
||||
|
||||
Score: count(pass) / count(total_checks) * 10
|
||||
|
||||
### Dimension 3: Reduced Motion (Weight: 20%)
|
||||
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| Media query present | Search CSS for prefers-reduced-motion | @media (prefers-reduced-motion: reduce) exists |
|
||||
| Transitions disabled | Check reduced-motion block | transition-duration near 0 or removed |
|
||||
| Animations disabled | Check reduced-motion block | animation-duration near 0 or removed |
|
||||
| Content still accessible | Verify no content depends on animation | Information conveyed without motion |
|
||||
| JS respects preference | Check matchMedia usage | JS checks prefers-reduced-motion before animating |
|
||||
|
||||
Score: count(pass) / count(total_checks) * 10
|
||||
|
||||
### Dimension 4: Focus Management (Weight: 20%)
|
||||
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| Visible focus indicator | Search CSS for :focus-visible | Visible outline/ring on keyboard focus |
|
||||
| Focus contrast | Check outline color against background | >= 3:1 contrast ratio |
|
||||
| Focus on open | Check overlay/modal open logic | Focus moves to first interactive element |
|
||||
| Focus on close | Check overlay/modal close logic | Focus returns to trigger element |
|
||||
| No focus loss | Check state transitions | Focus never moves to non-interactive element |
|
||||
| Skip link (page mode) | Check for skip navigation | Present if multiple interactive sections |
|
||||
|
||||
Score: count(pass) / count(total_checks) * 10
|
||||
|
||||
### Dimension 5: Color Contrast (Weight: 10%)
|
||||
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| Text contrast | Evaluate CSS color vs background | >= 4.5:1 for normal text, >= 3:1 for large text |
|
||||
| UI component contrast | Evaluate interactive element borders/fills | >= 3:1 against adjacent colors |
|
||||
| Focus indicator contrast | Evaluate outline color | >= 3:1 against background |
|
||||
| State indication | Check non-color state indicators | State not conveyed by color alone |
|
||||
|
||||
Score: count(pass) / count(total_checks) * 10
|
||||
|
||||
### Overall Score Calculation
|
||||
|
||||
`overallScore = round(keyboard*0.25 + screenReader*0.25 + reducedMotion*0.20 + focus*0.20 + contrast*0.10)`
|
||||
|
||||
### Issue Classification
|
||||
|
||||
| Severity | Definition | Examples |
|
||||
|----------|-----------|----------|
|
||||
| Critical | Component unusable for assistive tech users | No keyboard access, no ARIA role, focus trap |
|
||||
| High | Significant barrier, workaround exists | Missing aria-label, no reduced motion, poor focus |
|
||||
| Medium | Minor inconvenience | Suboptimal tab order, missing live region |
|
||||
| Low | Enhancement opportunity | Could improve contrast, better semantic HTML |
|
||||
|
||||
### Signal Determination
|
||||
|
||||
| Condition | Signal |
|
||||
|-----------|--------|
|
||||
| 0 critical AND 0 high issues | `a11y_passed` (GC CONVERGED) |
|
||||
| 0 critical AND high_count > 0 | `a11y_result` (GC REVISION NEEDED) |
|
||||
| critical_count > 0 | `fix_required` (CRITICAL FIX NEEDED) |
|
||||
|
||||
## Phase 4: Report & Output
|
||||
|
||||
1. Write audit report to `<session>/a11y/a11y-audit-{NNN}.md`:
|
||||
|
||||
```markdown
|
||||
# A11y Audit Report - {NNN}
|
||||
|
||||
## Summary
|
||||
- **Overall Score**: X/10
|
||||
- **Signal**: a11y_passed | a11y_result | fix_required
|
||||
- **Critical**: N | **High**: N | **Medium**: N | **Low**: N
|
||||
|
||||
## Dimension Scores
|
||||
|
||||
| Dimension | Score | Weight | Weighted |
|
||||
|-----------|-------|--------|----------|
|
||||
| Keyboard Navigation | X/10 | 25% | X.XX |
|
||||
| Screen Reader | X/10 | 25% | X.XX |
|
||||
| Reduced Motion | X/10 | 20% | X.XX |
|
||||
| Focus Management | X/10 | 20% | X.XX |
|
||||
| Color Contrast | X/10 | 10% | X.XX |
|
||||
|
||||
## Issues
|
||||
|
||||
### Critical
|
||||
- [C-001] {description} | File: {file}:{line} | Fix: {remediation}
|
||||
|
||||
### High
|
||||
- [H-001] {description} | File: {file}:{line} | Fix: {remediation}
|
||||
|
||||
### Medium
|
||||
- [M-001] {description} | File: {file}:{line} | Fix: {remediation}
|
||||
|
||||
## GC Loop Status
|
||||
- **Signal**: {signal}
|
||||
- **Action Required**: {none | builder fix | escalate}
|
||||
|
||||
## Trend (if previous audit exists)
|
||||
- Previous score: X/10 -> Current: X/10 ({improving|stable|declining})
|
||||
- Resolved issues: [list]
|
||||
- New issues: [list]
|
||||
```
|
||||
|
||||
2. Update `<session>/wisdom/.msg/meta.json` under `a11y-tester` namespace:
|
||||
- Read existing -> merge `{ "a11y-tester": { audit_id, score, critical_count, high_count, signal, timestamp } }` -> write back
|
||||
216
.claude/skills/team-interactive-craft/roles/builder/role.md
Normal file
216
.claude/skills/team-interactive-craft/roles/builder/role.md
Normal file
@@ -0,0 +1,216 @@
|
||||
---
|
||||
role: builder
|
||||
prefix: BUILD
|
||||
inner_loop: true
|
||||
message_types: [state_update]
|
||||
---
|
||||
|
||||
# Interactive Component Builder
|
||||
|
||||
Implement vanilla JS + CSS interactive components from interaction blueprints. Zero dependencies, ES modules, progressive enhancement, GPU-only animations, touch-aware. Act as Generator in the builder<->a11y-tester Generator-Critic loop.
|
||||
|
||||
## Phase 2: Context & Artifact Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Interaction blueprints | <session>/interaction/blueprints/*.md | Yes |
|
||||
| Research artifacts | <session>/research/*.json | Yes |
|
||||
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
|
||||
| A11y audit feedback | <session>/a11y/a11y-audit-*.md | Only for GC fix tasks |
|
||||
|
||||
1. Extract session path from task description
|
||||
2. Read interaction blueprint for target component
|
||||
3. Read research artifacts: browser-api-audit.json (API availability), pattern-reference.json (reference patterns)
|
||||
4. Detect task type from subject: numbered -> New component, "fix" -> GC fix
|
||||
5. If GC fix task: read latest a11y audit feedback
|
||||
|
||||
## Phase 3: Implementation Execution
|
||||
|
||||
**Component Implementation (BUILD-001, BUILD-002, etc.)**:
|
||||
|
||||
### JavaScript (ES Module)
|
||||
Implement component class in `<session>/build/components/{name}.js`:
|
||||
|
||||
```javascript
|
||||
// Structure template (adapt to component type)
|
||||
export class ComponentName {
|
||||
// --- Configuration ---
|
||||
static defaults = { /* configurable params from blueprint */ };
|
||||
|
||||
// --- Lifecycle ---
|
||||
constructor(element, options = {}) { /* merge options, query DOM, bind events */ }
|
||||
init() { /* setup observers, initial state */ }
|
||||
destroy() { /* cleanup: remove listeners, disconnect observers */ }
|
||||
|
||||
// --- State Machine ---
|
||||
#state = 'idle';
|
||||
#setState(next) { /* validate transition, update, trigger side effects */ }
|
||||
|
||||
// --- Event Handlers (from blueprint event flow map) ---
|
||||
#onPointerDown(e) { /* setPointerCapture, transition state */ }
|
||||
#onPointerMove(e) { /* lerp interpolation, update transform */ }
|
||||
#onPointerUp(e) { /* releasePointerCapture, settle animation */ }
|
||||
#onKeyDown(e) { /* keyboard mapping from blueprint */ }
|
||||
|
||||
// --- Animation ---
|
||||
#lerp(current, target, speed) { return current + (target - current) * speed; }
|
||||
#animate() { /* requestAnimationFrame loop, GPU-only transforms */ }
|
||||
|
||||
// --- Observers ---
|
||||
#resizeObserver = null; // responsive behavior
|
||||
#intersectionObserver = null; // scroll triggers
|
||||
|
||||
// --- Accessibility ---
|
||||
#announceToScreenReader(message) { /* aria-live region update */ }
|
||||
}
|
||||
|
||||
// Auto-init: progressive enhancement
|
||||
document.querySelectorAll('[data-component-name]').forEach(el => {
|
||||
new ComponentName(el);
|
||||
});
|
||||
```
|
||||
|
||||
Requirements:
|
||||
- Pure ES module with `export` (no CommonJS, no bundler)
|
||||
- Class-based with private fields (#)
|
||||
- Constructor accepts DOM element + options object
|
||||
- State machine from blueprint with validated transitions
|
||||
- Event handlers from blueprint event flow map
|
||||
- Lerp interpolation for smooth drag/follow (speed from blueprint)
|
||||
- requestAnimationFrame for frame-synced updates
|
||||
- setPointerCapture for reliable drag tracking
|
||||
- ResizeObserver for responsive layout adjustments
|
||||
- IntersectionObserver for scroll-triggered behavior (when applicable)
|
||||
- Proper cleanup in destroy() method
|
||||
- Auto-init via data attribute for progressive enhancement
|
||||
|
||||
### CSS (Custom Properties)
|
||||
Implement styles in `<session>/build/components/{name}.css`:
|
||||
|
||||
```css
|
||||
/* Structure template */
|
||||
/* --- Custom Properties (configurable) --- */
|
||||
.component-name {
|
||||
--component-duration: 400ms;
|
||||
--component-easing: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--component-color-primary: #1a1a2e;
|
||||
/* ... from blueprint animation choreography */
|
||||
}
|
||||
|
||||
/* --- Base Layout (works without JS) --- */
|
||||
.component-name { /* progressive enhancement base */ }
|
||||
|
||||
/* --- States (from blueprint state machine) --- */
|
||||
.component-name[data-state="idle"] { }
|
||||
.component-name[data-state="hover"] { }
|
||||
.component-name[data-state="active"] { }
|
||||
.component-name[data-state="dragging"] { }
|
||||
|
||||
/* --- Animations (GPU-only: transform + opacity) --- */
|
||||
.component-name__element {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
transition: transform var(--component-duration) var(--component-easing),
|
||||
opacity var(--component-duration) var(--component-easing);
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
/* --- Focus Styles --- */
|
||||
.component-name:focus-visible {
|
||||
outline: 2px solid var(--component-focus-color, #4a9eff);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* --- Reduced Motion --- */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.component-name,
|
||||
.component-name * {
|
||||
transition-duration: 0.01ms !important;
|
||||
animation-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Responsive --- */
|
||||
@media (max-width: 768px) { /* touch-optimized sizes */ }
|
||||
```
|
||||
|
||||
Requirements:
|
||||
- CSS custom properties for all configurable values (no preprocessor)
|
||||
- Base layout works without JavaScript (progressive enhancement)
|
||||
- State-driven via data attributes (`data-state`, `data-active`)
|
||||
- GPU-only animations: transform + opacity ONLY (no width/height/top/left)
|
||||
- `will-change` on animated elements
|
||||
- `prefers-reduced-motion` media query with instant transitions
|
||||
- `focus-visible` for keyboard-only focus ring
|
||||
- Responsive breakpoints for touch targets (min 44x44px)
|
||||
- No inline styles from JS -- use CSS classes and custom properties
|
||||
|
||||
### Native Platform APIs (prefer over custom implementations)
|
||||
|
||||
**Dialog API** (`<dialog>`):
|
||||
- Use `<dialog>` for modals — provides built-in focus trap and backdrop
|
||||
- `dialog.showModal()` for modal (with backdrop, escape-to-close, focus trap)
|
||||
- `dialog.show()` for non-modal
|
||||
- `dialog.close()` to dismiss
|
||||
- Style `::backdrop` pseudo-element for overlay
|
||||
- Returns focus to trigger element on close
|
||||
- Add `inert` attribute to siblings when modal is open (prevents background interaction)
|
||||
|
||||
**Popover API** (native tooltips/dropdowns):
|
||||
- `<div popover>` for light-dismiss popovers (click-outside-to-close)
|
||||
- `<button popovertarget="id">` for trigger
|
||||
- Auto-stacking (no z-index management needed)
|
||||
- Built-in accessibility (focus management, escape-to-close)
|
||||
- Use for: tooltips, dropdown menus, date pickers, color pickers
|
||||
|
||||
**CSS Anchor Positioning** (Chrome 125+, progressive enhancement):
|
||||
- `anchor-name: --trigger` on trigger element
|
||||
- `position-anchor: --trigger` on positioned element
|
||||
- `@position-try` for fallback positioning
|
||||
- Fallback: `position: fixed` with JS-calculated coordinates
|
||||
|
||||
**GC Fix Mode (BUILD-fix-N)**:
|
||||
- Parse a11y audit feedback for specific issues
|
||||
- Re-read affected component files
|
||||
- Apply targeted fixes: missing ARIA attributes, keyboard handlers, focus management, contrast adjustments
|
||||
- Re-write affected files
|
||||
- Signal `build_revision` instead of `build_ready`
|
||||
|
||||
## Phase 4: Self-Validation & Output
|
||||
|
||||
1. Zero-dependency check:
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| No imports from npm | No `import` from node_modules paths |
|
||||
| No require() | No CommonJS require statements |
|
||||
| ES module exports | Uses `export class` or `export function` |
|
||||
| No build tools needed | Runs directly in browser with `<script type="module">` |
|
||||
|
||||
2. State machine completeness:
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| All states from blueprint | Every blueprint state has corresponding code path |
|
||||
| All transitions | Every transition has handler code |
|
||||
| Error recovery | All states can reach idle via reset |
|
||||
|
||||
3. Accessibility baseline:
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| Keyboard handlers | onKeyDown handles Enter, Space, Escape, Arrows |
|
||||
| ARIA attributes | role, aria-label, aria-expanded (as needed) set |
|
||||
| Focus management | tabindex, focus-visible styles present |
|
||||
| Reduced motion | prefers-reduced-motion media query in CSS |
|
||||
|
||||
4. Performance baseline:
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| GPU-only transforms | No width/height/top/left in transitions |
|
||||
| No forced reflow | No offsetWidth/getBoundingClientRect in animation loop |
|
||||
| Cleanup | destroy() disconnects all observers and listeners |
|
||||
|
||||
5. Update `<session>/wisdom/.msg/meta.json` under `builder` namespace:
|
||||
- Read existing -> merge `{ "builder": { task_type, component_name, file_count, output_dir, states_implemented, events_bound } }` -> write back
|
||||
@@ -0,0 +1,71 @@
|
||||
# Analyze Task
|
||||
|
||||
Parse user task -> detect interactive component scope -> identify browser APIs -> determine pipeline mode.
|
||||
|
||||
**CONSTRAINT**: Text-level analysis only. NO source code reading, NO codebase exploration.
|
||||
|
||||
## Signal Detection
|
||||
|
||||
| Keywords | Capability | Pipeline Hint |
|
||||
|----------|------------|---------------|
|
||||
| split, compare, before/after, slider, divider | split-compare | single |
|
||||
| gallery, carousel, scroll-snap, horizontal scroll | scroll-snap-gallery | gallery |
|
||||
| lightbox, modal, overlay, fullscreen view | lightbox | single |
|
||||
| scroll reveal, appear on scroll, fade in, stagger | scroll-reveal | single or gallery |
|
||||
| glass, terminal, frosted, blur, backdrop | glass-terminal | single |
|
||||
| lens, magnify, zoom, loupe | lens-effect | single |
|
||||
| drag, resize, pointer, touch | pointer-interaction | single |
|
||||
| page, landing, sections, multi-section | interactive-page | page |
|
||||
| multiple components, collection, set | multi-component | gallery or page |
|
||||
|
||||
## Scope Determination
|
||||
|
||||
| Signal | Pipeline Mode |
|
||||
|--------|---------------|
|
||||
| Single component mentioned | single |
|
||||
| Gallery or scroll-based multi-component | gallery |
|
||||
| Full interactive page or multi-section | page |
|
||||
| Unclear | ask user |
|
||||
|
||||
## Complexity Scoring
|
||||
|
||||
| Factor | Points |
|
||||
|--------|--------|
|
||||
| Single component | +1 |
|
||||
| Gallery / scroll collection | +2 |
|
||||
| Full interactive page | +3 |
|
||||
| Pointer/drag interactions | +1 |
|
||||
| Scroll-based triggers (IntersectionObserver) | +1 |
|
||||
| Touch gestures (pinch, swipe) | +1 |
|
||||
| Overlay/modal with focus trap | +1 |
|
||||
| Animation choreography (stagger, sequence) | +1 |
|
||||
|
||||
Results: 1-2 Low (single), 3-4 Medium (gallery), 5+ High (page)
|
||||
|
||||
## Browser API Detection
|
||||
|
||||
| Keywords | Browser API |
|
||||
|----------|-------------|
|
||||
| scroll, appear, visibility, threshold | IntersectionObserver |
|
||||
| resize, container, responsive, layout | ResizeObserver |
|
||||
| drag, pointer, mouse, click | Pointer Events |
|
||||
| touch, swipe, pinch, gesture | Touch Events |
|
||||
| scroll snap, snap point, mandatory | CSS scroll-snap |
|
||||
| clip, mask, reveal, wipe | CSS clip-path |
|
||||
| blur, frosted, glass | CSS backdrop-filter |
|
||||
| animate, transition, keyframe | Web Animations API |
|
||||
| focus, trap, tab, keyboard | Focus Management |
|
||||
|
||||
## Output
|
||||
|
||||
Write scope context to coordinator memory:
|
||||
```json
|
||||
{
|
||||
"pipeline_mode": "<single|gallery|page>",
|
||||
"scope": "<description>",
|
||||
"interaction_type": "<pointer|scroll|overlay|mixed>",
|
||||
"components": ["<detected-component-types>"],
|
||||
"browser_apis": ["<detected-apis>"],
|
||||
"complexity": { "score": 0, "level": "Low|Medium|High" }
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,192 @@
|
||||
# Command: Dispatch
|
||||
|
||||
Create the interactive craft task chain with correct dependencies and structured task descriptions. Supports single, gallery, and page pipeline modes.
|
||||
|
||||
## Phase 2: Context Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| User requirement | From coordinator Phase 1 | Yes |
|
||||
| Session folder | From coordinator Phase 2 | Yes |
|
||||
| Pipeline mode | From session meta.json `pipeline` | Yes |
|
||||
| Interaction type | From session meta.json `interaction_type` | Yes |
|
||||
|
||||
1. Load user requirement and scope from session meta.json
|
||||
2. Load pipeline stage definitions from specs/pipelines.md
|
||||
3. Read `pipeline` and `interaction_type` from session meta.json
|
||||
|
||||
## Phase 3: Task Chain Creation (Mode-Branched)
|
||||
|
||||
### Task Description Template
|
||||
|
||||
Every task description uses structured format:
|
||||
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "<TASK-ID>",
|
||||
description: "PURPOSE: <what this task achieves> | Success: <measurable completion criteria>
|
||||
TASK:
|
||||
- <step 1: specific action>
|
||||
- <step 2: specific action>
|
||||
- <step 3: specific action>
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <interaction-scope>
|
||||
- Components: <component-list>
|
||||
- Upstream artifacts: <artifact-1>, <artifact-2>
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <deliverable path> + <quality criteria>
|
||||
CONSTRAINTS: <scope limits, focus areas>"
|
||||
})
|
||||
TaskUpdate({ taskId: "<TASK-ID>", addBlockedBy: [<dependency-list>], owner: "<role>" })
|
||||
```
|
||||
|
||||
### Mode Router
|
||||
|
||||
| Mode | Action |
|
||||
|------|--------|
|
||||
| `single` | Create 4 tasks: RESEARCH -> INTERACT -> BUILD -> A11Y |
|
||||
| `gallery` | Create 6 tasks: RESEARCH -> INTERACT-001 -> BUILD-001 -> INTERACT-002 -> BUILD-002 -> A11Y |
|
||||
| `page` | Create 4+ tasks: RESEARCH -> INTERACT -> [BUILD-001..N parallel] -> A11Y |
|
||||
|
||||
---
|
||||
|
||||
### Single Pipeline Task Chain
|
||||
|
||||
**RESEARCH-001** (researcher):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "RESEARCH-001",
|
||||
description: "PURPOSE: Analyze interaction patterns, browser API availability, and reference implementations | Success: 3 research artifacts with valid data
|
||||
TASK:
|
||||
- Catalog existing interactive components in project
|
||||
- Audit browser API usage (IntersectionObserver, ResizeObserver, Pointer Events, Touch Events)
|
||||
- Collect reference patterns for target component type
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <interaction-scope>
|
||||
- Components: <component-list>
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/research/*.json | All 3 research files with valid JSON
|
||||
CONSTRAINTS: Read-only analysis | Focus on <interaction-scope>"
|
||||
})
|
||||
TaskUpdate({ taskId: "RESEARCH-001", owner: "researcher" })
|
||||
```
|
||||
|
||||
**INTERACT-001** (interaction-designer):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "INTERACT-001",
|
||||
description: "PURPOSE: Design complete interaction blueprint with state machine and event flows | Success: Blueprint with all states, events, and keyboard mappings defined
|
||||
TASK:
|
||||
- Define state machine (idle -> hover -> active -> animating -> complete)
|
||||
- Map event flows (pointer/touch/keyboard -> handlers -> state transitions)
|
||||
- Specify gesture parameters (lerp speed, thresholds, easing)
|
||||
- Design animation choreography (entry/exit/idle transitions)
|
||||
- Create touch/keyboard/mouse mapping table
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <interaction-scope>
|
||||
- Upstream artifacts: research/*.json
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/interaction/blueprints/<component-name>.md | Complete state machine + event map + keyboard coverage
|
||||
CONSTRAINTS: Vanilla JS only | GPU-only animations | Progressive enhancement"
|
||||
})
|
||||
TaskUpdate({ taskId: "INTERACT-001", addBlockedBy: ["RESEARCH-001"], owner: "interaction-designer" })
|
||||
```
|
||||
|
||||
**BUILD-001** (builder):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "BUILD-001",
|
||||
description: "PURPOSE: Implement interactive component as vanilla JS + CSS | Success: Working ES module + CSS with all states, touch-aware, keyboard accessible
|
||||
TASK:
|
||||
- Implement ES module component class from interaction blueprint
|
||||
- Write CSS with custom properties (no preprocessor)
|
||||
- Add progressive enhancement (content works without JS)
|
||||
- Use GPU-only animations (transform + opacity)
|
||||
- Implement pointer events with touch fallback
|
||||
- Add ResizeObserver for responsive behavior
|
||||
- Add IntersectionObserver for scroll triggers (if applicable)
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <interaction-scope>
|
||||
- Upstream artifacts: interaction/blueprints/*.md, research/*.json
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/build/components/<name>.js + <name>.css | Zero dependencies, all states implemented
|
||||
CONSTRAINTS: No npm packages | ES modules only | No inline styles | < 5ms per frame"
|
||||
})
|
||||
TaskUpdate({ taskId: "BUILD-001", addBlockedBy: ["INTERACT-001"], owner: "builder" })
|
||||
```
|
||||
|
||||
**A11Y-001** (a11y-tester):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "A11Y-001",
|
||||
description: "PURPOSE: Audit accessibility of built component | Success: Audit report with pass/fail per check, 0 critical issues
|
||||
TASK:
|
||||
- Test keyboard navigation (tab order, arrow keys, escape, enter/space)
|
||||
- Check screen reader compatibility (ARIA roles, states, live regions)
|
||||
- Verify reduced motion fallback (prefers-reduced-motion)
|
||||
- Test focus management (visible indicator, focus trap for overlays)
|
||||
- Check color contrast (foreground/background ratio)
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <interaction-scope>
|
||||
- Upstream artifacts: build/components/*.js, build/components/*.css, interaction/blueprints/*.md
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/a11y/a11y-audit-001.md | Per-check pass/fail with remediation suggestions
|
||||
CONSTRAINTS: Read-only analysis | GC convergence: 0 critical issues"
|
||||
})
|
||||
TaskUpdate({ taskId: "A11Y-001", addBlockedBy: ["BUILD-001"], owner: "a11y-tester" })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Gallery Pipeline Task Chain
|
||||
|
||||
Create tasks in dependency order:
|
||||
|
||||
| Task | Role | blockedBy | Description |
|
||||
|------|------|-----------|-------------|
|
||||
| RESEARCH-001 | researcher | (none) | Interaction patterns + browser API audit |
|
||||
| INTERACT-001 | interaction-designer | RESEARCH-001 | Base component interaction blueprint |
|
||||
| BUILD-001 | builder | INTERACT-001 | Base component implementation |
|
||||
| INTERACT-002 | interaction-designer | BUILD-001 | Gallery/scroll-snap interaction blueprint |
|
||||
| BUILD-002 | builder | INTERACT-002 | Gallery container + navigation implementation |
|
||||
| A11Y-001 | a11y-tester | BUILD-002 | Full gallery accessibility audit |
|
||||
|
||||
Task descriptions follow same template as single pipeline, with subject-specific content:
|
||||
- INTERACT-002 focuses on scroll-snap container, navigation dots, active item detection
|
||||
- BUILD-002 focuses on gallery container with CSS scroll-snap, IntersectionObserver for active item, navigation controls
|
||||
|
||||
---
|
||||
|
||||
### Page Pipeline Task Chain
|
||||
|
||||
| Task | Role | blockedBy | Description |
|
||||
|------|------|-----------|-------------|
|
||||
| RESEARCH-001 | researcher | (none) | Interaction patterns for all page sections |
|
||||
| INTERACT-001 | interaction-designer | RESEARCH-001 | Blueprints for all interactive sections |
|
||||
| BUILD-001..N | builder | INTERACT-001 | One task per section (parallel fan-out) |
|
||||
| A11Y-001 | a11y-tester | BUILD-001..N (all) | Full page accessibility audit |
|
||||
|
||||
**Parallel fan-out**: Create one BUILD task per distinct interactive section detected in the interaction blueprint. Each BUILD task is blocked only by INTERACT-001. A11Y-001 is blocked by ALL BUILD tasks.
|
||||
|
||||
Task descriptions for each BUILD-00N specify which section to implement, referencing the corresponding section in the interaction blueprint.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Validation
|
||||
|
||||
Verify task chain integrity:
|
||||
|
||||
| Check | Method | Expected |
|
||||
|-------|--------|----------|
|
||||
| Task count correct | TaskList count | single: 4, gallery: 6, page: 3+N |
|
||||
| Dependencies correct | Trace dependency graph | Acyclic, correct blockedBy |
|
||||
| No circular dependencies | Trace dependency graph | Acyclic |
|
||||
| Task IDs use correct prefixes | Pattern check | RESEARCH/INTERACT/BUILD/A11Y |
|
||||
| Structured descriptions complete | Each has PURPOSE/TASK/CONTEXT/EXPECTED/CONSTRAINTS | All present |
|
||||
|
||||
If validation fails, fix the specific task and re-validate.
|
||||
@@ -0,0 +1,183 @@
|
||||
# Monitor Pipeline
|
||||
|
||||
Event-driven pipeline coordination. Beat model: coordinator wake -> process -> spawn -> STOP.
|
||||
|
||||
## Constants
|
||||
|
||||
- SPAWN_MODE: background
|
||||
- ONE_STEP_PER_INVOCATION: true
|
||||
- FAST_ADVANCE_AWARE: true
|
||||
- WORKER_AGENT: team-worker
|
||||
- MAX_GC_ROUNDS: 2
|
||||
|
||||
## Handler Router
|
||||
|
||||
| Source | Handler |
|
||||
|--------|---------|
|
||||
| Message contains [researcher], [interaction-designer], [builder], [a11y-tester] | handleCallback |
|
||||
| "capability_gap" | handleAdapt |
|
||||
| "check" or "status" | handleCheck |
|
||||
| "resume" or "continue" | handleResume |
|
||||
| All tasks completed | handleComplete |
|
||||
| Default | handleSpawnNext |
|
||||
|
||||
## handleCallback
|
||||
|
||||
Worker completed. Process and advance.
|
||||
|
||||
1. Parse message to identify role and task ID:
|
||||
|
||||
| Message Pattern | Role |
|
||||
|----------------|------|
|
||||
| `[researcher]` or `RESEARCH-*` | researcher |
|
||||
| `[interaction-designer]` or `INTERACT-*` | interaction-designer |
|
||||
| `[builder]` or `BUILD-*` | builder |
|
||||
| `[a11y-tester]` or `A11Y-*` | a11y-tester |
|
||||
|
||||
2. Mark task completed: `TaskUpdate({ taskId: "<task-id>", status: "completed" })`
|
||||
3. Record completion in session state
|
||||
|
||||
4. Check checkpoint for completed task:
|
||||
|
||||
| Completed Task | Checkpoint | Action |
|
||||
|---------------|------------|--------|
|
||||
| RESEARCH-001 | - | Notify user: research complete |
|
||||
| INTERACT-001 | - | Proceed to BUILD-001 (single/gallery) or BUILD-001..N (page parallel) |
|
||||
| INTERACT-002 | - | Proceed to BUILD-002 (gallery) |
|
||||
| BUILD-001 | - | Check mode: single -> A11Y-001; gallery -> INTERACT-002; page -> check if all BUILD done |
|
||||
| BUILD-001..N | - | Page mode: check if all BUILD tasks done -> A11Y-001 |
|
||||
| BUILD-002 | - | Gallery: proceed to A11Y-001 |
|
||||
| A11Y-001 | QUALITY: A11y Gate | Check a11y signal -> GC loop or complete |
|
||||
|
||||
5. **A11y Gate handling** (A11Y task completed):
|
||||
Read a11y signal from message: `a11y_passed`, `a11y_result`, or `fix_required`
|
||||
|
||||
| Signal | Condition | Action |
|
||||
|--------|-----------|--------|
|
||||
| `a11y_passed` | 0 critical issues | GC converged -> record gate -> handleComplete |
|
||||
| `a11y_result` | Minor issues only | gc_rounds < max -> create BUILD-fix task |
|
||||
| `fix_required` | Critical issues found | gc_rounds < max -> create BUILD-fix task (CRITICAL) |
|
||||
| Any | gc_rounds >= max | Escalate to user |
|
||||
|
||||
**GC Fix Task Creation**:
|
||||
```
|
||||
TaskCreate({ subject: "BUILD-fix-<round>",
|
||||
description: "PURPOSE: Address a11y audit feedback | Success: All critical/high issues resolved
|
||||
TASK:
|
||||
- Parse a11y audit feedback for specific issues
|
||||
- Apply targeted fixes to component JS/CSS
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Upstream artifacts: a11y/a11y-audit-<NNN>.md" })
|
||||
TaskUpdate({ taskId: "BUILD-fix-<round>", owner: "builder" })
|
||||
```
|
||||
Then create new A11Y task blocked by fix. Increment gc_state.round.
|
||||
|
||||
**GC Escalation Options** (when max rounds exceeded):
|
||||
1. Accept current implementation - skip remaining a11y fixes
|
||||
2. Try one more round
|
||||
3. Terminate
|
||||
|
||||
6. -> handleSpawnNext
|
||||
|
||||
## handleCheck
|
||||
|
||||
Read-only status report, then STOP.
|
||||
|
||||
```
|
||||
Pipeline Status (<pipeline-mode>):
|
||||
[DONE] RESEARCH-001 (researcher) -> research/*.json
|
||||
[DONE] INTERACT-001 (interaction-designer) -> blueprints/*.md
|
||||
[RUN] BUILD-001 (builder) -> building component...
|
||||
[WAIT] A11Y-001 (a11y-tester) -> blocked by BUILD-001
|
||||
|
||||
GC Rounds: 0/2
|
||||
Session: <session-id>
|
||||
Commands: 'resume' to advance | 'check' to refresh
|
||||
```
|
||||
|
||||
Output status -- do NOT advance pipeline.
|
||||
|
||||
## handleResume
|
||||
|
||||
1. Audit task list for inconsistencies:
|
||||
- Tasks stuck in "in_progress" -> reset to "pending"
|
||||
- Tasks with completed blockers but still "pending" -> include in spawn list
|
||||
2. -> handleSpawnNext
|
||||
|
||||
## handleSpawnNext
|
||||
|
||||
Find ready tasks, spawn workers, STOP.
|
||||
|
||||
1. Collect: completedSubjects, inProgressSubjects, readySubjects (pending + all blockedBy completed)
|
||||
2. No ready + work in progress -> report waiting, STOP
|
||||
3. No ready + nothing in progress -> handleComplete
|
||||
4. Has ready -> for each:
|
||||
a. Check inner loop role with active worker -> skip (worker picks up)
|
||||
b. TaskUpdate -> in_progress
|
||||
c. team_msg log -> task_unblocked
|
||||
d. Spawn team-worker:
|
||||
|
||||
```
|
||||
Agent({
|
||||
subagent_type: "team-worker",
|
||||
description: "Spawn <role> worker for <task-id>",
|
||||
team_name: "interactive-craft",
|
||||
name: "<role>",
|
||||
run_in_background: true,
|
||||
prompt: `## Role Assignment
|
||||
role: <role>
|
||||
role_spec: <project>/.claude/skills/team-interactive-craft/roles/<role>/role.md
|
||||
session: <session-folder>
|
||||
session_id: <session-id>
|
||||
team_name: interactive-craft
|
||||
requirement: <task-description>
|
||||
inner_loop: <true|false>
|
||||
|
||||
Read role_spec file to load Phase 2-4 domain instructions.
|
||||
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).`
|
||||
})
|
||||
```
|
||||
|
||||
**Parallel spawn rules by mode**:
|
||||
|
||||
| Mode | Scenario | Spawn Behavior |
|
||||
|------|----------|---------------|
|
||||
| single | Sequential | One task at a time |
|
||||
| gallery | Sequential | One task at a time |
|
||||
| page | After INTERACT-001 | Spawn BUILD-001..N in parallel (CP-3 fan-out) |
|
||||
| page | After all BUILD done | Spawn A11Y-001 |
|
||||
|
||||
5. Add to active_workers, update session, output summary, STOP
|
||||
|
||||
## handleComplete
|
||||
|
||||
Pipeline done. Generate report and completion action.
|
||||
|
||||
**Completion check by mode**:
|
||||
|
||||
| Mode | Completion Condition |
|
||||
|------|---------------------|
|
||||
| single | All 4 tasks (+ fix tasks) completed |
|
||||
| gallery | All 6 tasks (+ fix tasks) completed |
|
||||
| page | All 3+N tasks (+ fix tasks) completed |
|
||||
|
||||
1. If any tasks not completed -> handleSpawnNext
|
||||
2. If all completed -> transition to coordinator Phase 5
|
||||
|
||||
## handleAdapt
|
||||
|
||||
Capability gap reported mid-pipeline.
|
||||
|
||||
1. Parse gap description
|
||||
2. Check if existing role covers it -> redirect
|
||||
3. Role count < 5 -> generate dynamic role spec
|
||||
4. Create new task, spawn worker
|
||||
5. Role count >= 5 -> merge or pause
|
||||
|
||||
## Fast-Advance Reconciliation
|
||||
|
||||
On every coordinator wake:
|
||||
1. Read team_msg entries with type="fast_advance"
|
||||
2. Sync active_workers with spawned successors
|
||||
3. No duplicate spawns
|
||||
166
.claude/skills/team-interactive-craft/roles/coordinator/role.md
Normal file
166
.claude/skills/team-interactive-craft/roles/coordinator/role.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Coordinator Role
|
||||
|
||||
Interactive Craft Team coordinator. Orchestrate pipeline: analyze -> dispatch -> spawn -> monitor -> report. Manages task chains for interactive component creation, GC loops between builder and a11y-tester, parallel fan-out for page mode.
|
||||
|
||||
## Identity
|
||||
- **Name**: coordinator | **Tag**: [coordinator]
|
||||
- **Responsibility**: Analyze task -> Create team -> Dispatch tasks -> Monitor progress -> Report results
|
||||
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
- All output (SendMessage, team_msg, logs) must carry `[coordinator]` identifier
|
||||
- Use `team-worker` agent type for all worker spawns (NOT `general-purpose`)
|
||||
- Dispatch tasks with proper dependency chains and blockedBy
|
||||
- Monitor worker progress via message bus and route messages
|
||||
- Handle Generator-Critic loops with max 2 iterations
|
||||
- Maintain session state persistence
|
||||
|
||||
### MUST NOT
|
||||
- Implement domain logic (researching, designing, building, testing) -- workers handle this
|
||||
- Spawn workers without creating tasks first
|
||||
- Skip sync points when configured
|
||||
- Force-advance pipeline past failed a11y audit
|
||||
- Modify source code or component artifacts directly -- delegate to workers
|
||||
- Omit `[coordinator]` identifier in any output
|
||||
|
||||
## Command Execution Protocol
|
||||
|
||||
When coordinator needs to execute a command (analyze, dispatch, monitor):
|
||||
|
||||
1. Read `commands/<command>.md`
|
||||
2. Follow the workflow defined in the command
|
||||
3. Commands are inline execution guides, NOT separate agents
|
||||
4. Execute synchronously, complete before proceeding
|
||||
|
||||
## Entry Router
|
||||
|
||||
| Detection | Condition | Handler |
|
||||
|-----------|-----------|---------|
|
||||
| Worker callback | Message contains [researcher], [interaction-designer], [builder], [a11y-tester] | -> handleCallback (monitor.md) |
|
||||
| Status check | Args contain "check" or "status" | -> handleCheck (monitor.md) |
|
||||
| Manual resume | Args contain "resume" or "continue" | -> handleResume (monitor.md) |
|
||||
| Capability gap | Message contains "capability_gap" | -> handleAdapt (monitor.md) |
|
||||
| Pipeline complete | All tasks have status "completed" | -> handleComplete (monitor.md) |
|
||||
| Interrupted session | Active/paused session exists in .workflow/.team/IC-* | -> Phase 0 |
|
||||
| New session | None of above | -> Phase 1 |
|
||||
|
||||
For callback/check/resume/adapt/complete: load `@commands/monitor.md`, execute matched handler, STOP.
|
||||
|
||||
## Phase 0: Session Resume Check
|
||||
|
||||
1. Scan `.workflow/.team/IC-*/.msg/meta.json` for active/paused sessions
|
||||
2. No sessions -> Phase 1
|
||||
3. Single session -> reconcile (audit TaskList, reset in_progress->pending, rebuild team, kick first ready task)
|
||||
4. Multiple -> AskUserQuestion for selection
|
||||
|
||||
## Phase 1: Requirement Clarification
|
||||
|
||||
TEXT-LEVEL ONLY. No source code reading.
|
||||
|
||||
1. Parse task description from arguments
|
||||
2. Detect interactive scope:
|
||||
|
||||
| Signal | Pipeline Mode |
|
||||
|--------|---------------|
|
||||
| Single component (split compare, lightbox, lens, scroll reveal, glass terminal) | single |
|
||||
| Gallery, carousel, scroll-snap collection, multi-component scroll | gallery |
|
||||
| Full interactive page, landing page, multi-section interactive | page |
|
||||
| Unclear | ask user |
|
||||
|
||||
3. Ask for missing parameters if scope unclear:
|
||||
```
|
||||
AskUserQuestion({
|
||||
questions: [
|
||||
{ question: "Interactive component scope?", header: "Scope", options: [
|
||||
{ label: "Single component", description: "One interactive element (split compare, lightbox, etc.)" },
|
||||
{ label: "Gallery / Scroll collection", description: "Scroll-snap gallery or multi-component scroll" },
|
||||
{ label: "Full interactive page", description: "Complete page with multiple interactive sections" }
|
||||
]},
|
||||
{ question: "Primary interaction type?", header: "Interaction", options: [
|
||||
{ label: "Pointer/drag", description: "Drag, resize, slider interactions" },
|
||||
{ label: "Scroll-based", description: "Scroll snap, scroll reveal, parallax" },
|
||||
{ label: "Overlay/modal", description: "Lightbox, lens, tooltip overlays" },
|
||||
{ label: "Mixed" }
|
||||
]}
|
||||
]
|
||||
})
|
||||
```
|
||||
4. Delegate to `@commands/analyze.md` -> output scope context
|
||||
5. Record: pipeline_mode, interaction_type, complexity
|
||||
|
||||
## Phase 2: Create Team + Initialize Session
|
||||
|
||||
1. Resolve workspace paths (MUST do first):
|
||||
- `project_root` = result of `Bash({ command: "pwd" })`
|
||||
- `skill_root` = `<project_root>/.claude/skills/team-interactive-craft`
|
||||
2. Generate session ID: `IC-<slug>-<YYYY-MM-DD>`
|
||||
3. Create session folder structure:
|
||||
```
|
||||
.workflow/.team/IC-<slug>-<date>/research/
|
||||
.workflow/.team/IC-<slug>-<date>/interaction/blueprints/
|
||||
.workflow/.team/IC-<slug>-<date>/build/components/
|
||||
.workflow/.team/IC-<slug>-<date>/a11y/
|
||||
.workflow/.team/IC-<slug>-<date>/wisdom/
|
||||
.workflow/.team/IC-<slug>-<date>/.msg/
|
||||
```
|
||||
4. Initialize `.msg/meta.json` via team_msg state_update with pipeline metadata
|
||||
5. TeamCreate(team_name="interactive-craft")
|
||||
6. Do NOT spawn workers yet - deferred to Phase 4
|
||||
|
||||
## Phase 3: Create Task Chain
|
||||
|
||||
Delegate to `@commands/dispatch.md`. Task chains by mode:
|
||||
|
||||
| Mode | Task Chain |
|
||||
|------|------------|
|
||||
| single | RESEARCH-001 -> INTERACT-001 -> BUILD-001 -> A11Y-001 |
|
||||
| gallery | RESEARCH-001 -> INTERACT-001 -> BUILD-001 -> INTERACT-002 -> BUILD-002 -> A11Y-001 |
|
||||
| page | RESEARCH-001 -> INTERACT-001 -> [BUILD-001..N parallel] -> A11Y-001 |
|
||||
|
||||
## Phase 4: Spawn-and-Stop
|
||||
|
||||
Delegate to `@commands/monitor.md#handleSpawnNext`:
|
||||
1. Find ready tasks (pending + blockedBy resolved)
|
||||
2. Spawn team-worker agents (see SKILL.md Spawn Template)
|
||||
3. Output status summary
|
||||
4. STOP
|
||||
|
||||
## Phase 5: Report + Completion Action
|
||||
|
||||
1. Read session state -> collect all results
|
||||
2. List deliverables:
|
||||
|
||||
| Deliverable | Path |
|
||||
|-------------|------|
|
||||
| Interaction Inventory | <session>/research/interaction-inventory.json |
|
||||
| Browser API Audit | <session>/research/browser-api-audit.json |
|
||||
| Pattern Reference | <session>/research/pattern-reference.json |
|
||||
| Interaction Blueprints | <session>/interaction/blueprints/*.md |
|
||||
| Component JS Files | <session>/build/components/*.js |
|
||||
| Component CSS Files | <session>/build/components/*.css |
|
||||
| A11y Audit Reports | <session>/a11y/a11y-audit-*.md |
|
||||
|
||||
3. Calculate: completed_tasks, gc_rounds, a11y_score, components_built
|
||||
4. Output pipeline summary with [coordinator] prefix
|
||||
5. Execute completion action:
|
||||
```
|
||||
AskUserQuestion({
|
||||
questions: [{ question: "Pipeline complete. What next?", header: "Completion", options: [
|
||||
{ label: "Archive & Clean", description: "Archive session and clean up team resources" },
|
||||
{ label: "Keep Active", description: "Keep session for follow-up work" },
|
||||
{ label: "Export Results", description: "Export deliverables to specified location" }
|
||||
]}]
|
||||
})
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Task timeout | Log, mark failed, ask user to retry or skip |
|
||||
| Worker crash | Reset task to pending, respawn worker |
|
||||
| Dependency cycle | Detect, report to user, halt |
|
||||
| Invalid scope | Reject with error, ask to clarify |
|
||||
| Session corruption | Attempt recovery, fallback to manual reconciliation |
|
||||
| GC loop stuck > 2 rounds | Escalate to user: accept / try one more / terminate |
|
||||
@@ -0,0 +1,144 @@
|
||||
---
|
||||
role: interaction-designer
|
||||
prefix: INTERACT
|
||||
inner_loop: false
|
||||
message_types: [state_update]
|
||||
---
|
||||
|
||||
# Interaction Blueprint Designer
|
||||
|
||||
Design complete interaction blueprints: state machines, event flows, gesture specifications, animation choreography, and input mapping tables. Consume research artifacts to produce blueprints for the builder role.
|
||||
|
||||
## Phase 2: Context & Artifact Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Research artifacts | <session>/research/*.json | Yes |
|
||||
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
|
||||
| Existing blueprints | <session>/interaction/blueprints/*.md | Only for INTERACT-002+ |
|
||||
|
||||
1. Extract session path from task description
|
||||
2. Read research findings: interaction-inventory.json, browser-api-audit.json, pattern-reference.json
|
||||
3. Detect task type from subject: "001" -> Primary blueprint, "002" -> Secondary/gallery blueprint
|
||||
4. If INTERACT-002+: read existing blueprints for consistency with base component
|
||||
|
||||
## Phase 3: Design Execution
|
||||
|
||||
**Primary Blueprint (INTERACT-001)**:
|
||||
|
||||
For each target component, produce a blueprint document containing:
|
||||
|
||||
### State Machine
|
||||
Define complete state diagram:
|
||||
```
|
||||
[idle] --(pointerenter)--> [hover]
|
||||
[hover] --(pointerdown)--> [active]
|
||||
[hover] --(pointerleave)--> [idle]
|
||||
[active] --(pointermove)--> [dragging/animating]
|
||||
[active] --(pointerup)--> [hover]
|
||||
[dragging] --(pointerup)--> [settling]
|
||||
[settling] --(transitionend)--> [idle]
|
||||
[any] --(focus)--> [focused]
|
||||
[focused] --(blur)--> [previous-state]
|
||||
[any] --(keydown:Escape)--> [idle]
|
||||
```
|
||||
- All states must be reachable
|
||||
- All states must have exit transitions
|
||||
- Error/reset transitions from every state back to idle
|
||||
|
||||
### Event Flow Map
|
||||
Map events to handlers to state transitions:
|
||||
|
||||
| Event | Source | Handler | State Transition | Side Effect |
|
||||
|-------|--------|---------|-----------------|-------------|
|
||||
| pointerdown | element | onPointerDown | idle->active | setPointerCapture, preventDefault |
|
||||
| pointermove | document | onPointerMove | active->dragging | update position via lerp |
|
||||
| pointerup | document | onPointerUp | dragging->settling | releasePointerCapture |
|
||||
| keydown:ArrowLeft | element | onKeyDown | - | decrement value |
|
||||
| keydown:ArrowRight | element | onKeyDown | - | increment value |
|
||||
| keydown:Escape | element | onKeyDown | any->idle | reset to default |
|
||||
| keydown:Enter/Space | element | onKeyDown | idle->active | toggle/activate |
|
||||
|
||||
### Gesture Specification
|
||||
For pointer/touch interactions:
|
||||
|
||||
| Gesture | Detection | Parameters |
|
||||
|---------|-----------|------------|
|
||||
| Drag | pointerdown + pointermove > 3px | lerp speed: 0.15, axis: x/y/both |
|
||||
| Swipe | pointerup with velocity > 0.5px/ms | direction: left/right/up/down |
|
||||
| Pinch | 2+ touch points, distance change | scale factor, min/max zoom |
|
||||
| Scroll snap | CSS scroll-snap-type: x mandatory | align: start/center, behavior: smooth |
|
||||
|
||||
- Lerp interpolation: `current += (target - current) * speed`
|
||||
- Dead zone: ignore movements < 3px from start
|
||||
- Velocity tracking: store last 3-5 pointer positions with timestamps
|
||||
|
||||
### Animation Choreography
|
||||
Define animation sequences:
|
||||
|
||||
| Animation | Trigger | Properties | Duration | Easing | GPU |
|
||||
|-----------|---------|------------|----------|--------|-----|
|
||||
| Entry | mount/reveal | opacity 0->1, translateY 20px->0 | 400ms | cubic-bezier(0.16,1,0.3,1) | Yes |
|
||||
| Exit | unmount/hide | opacity 1->0, translateY 0->-10px | 200ms | ease-in | Yes |
|
||||
| Drag follow | pointermove | translateX via lerp | per-frame | linear (lerp) | Yes |
|
||||
| Settle | pointerup | translateX to snap point | 300ms | cubic-bezier(0.16,1,0.3,1) | Yes |
|
||||
| Hover | pointerenter | scale 1->1.02 | 200ms | ease-out | Yes |
|
||||
| Focus ring | focus-visible | outline-offset 0->2px | 150ms | ease-out | No (outline) |
|
||||
| Stagger | intersection | delay: index * 80ms | 400ms+delay | cubic-bezier(0.16,1,0.3,1) | Yes |
|
||||
|
||||
- ALL animations must use transform + opacity only (GPU-composited)
|
||||
- Exception: outline for focus indicators
|
||||
- Reduced motion: replace all motion with opacity-only crossfade (200ms)
|
||||
|
||||
### Input Mapping Table
|
||||
Unified mapping across input methods:
|
||||
|
||||
| Action | Mouse | Touch | Keyboard | Screen Reader |
|
||||
|--------|-------|-------|----------|--------------|
|
||||
| Activate | click | tap | Enter/Space | Enter/Space |
|
||||
| Navigate prev | - | swipe-right | ArrowLeft | ArrowLeft |
|
||||
| Navigate next | - | swipe-left | ArrowRight | ArrowRight |
|
||||
| Drag/adjust | pointerdown+move | pointerdown+move | Arrow keys (step) | Arrow keys (step) |
|
||||
| Dismiss | click outside | tap outside | Escape | Escape |
|
||||
| Focus | pointermove (hover) | - | Tab | Tab |
|
||||
|
||||
### Platform API Preference
|
||||
|
||||
When designing interaction blueprints, prefer native APIs over custom implementations:
|
||||
|
||||
| Need | Native API | Custom Fallback |
|
||||
|------|-----------|-----------------|
|
||||
| Modal dialog | `<dialog>` + `showModal()` | Custom with focus trap + inert |
|
||||
| Tooltip/popover | Popover API (`popover` attribute) | Custom with click-outside listener |
|
||||
| Dropdown positioning | CSS Anchor Positioning | `position: fixed` + JS coords |
|
||||
| Focus trap | `<dialog>` built-in or `inert` attribute | Manual focus cycling with tabindex |
|
||||
| Escape-to-close | Built into `<dialog>` and Popover | Manual keydown listener |
|
||||
|
||||
Document in blueprint: which native API to use, what the fallback is for unsupported browsers, and how to feature-detect.
|
||||
|
||||
**Gallery/Secondary Blueprint (INTERACT-002)**:
|
||||
- Design scroll-snap container interaction
|
||||
- Navigation controls (prev/next arrows, dots/indicators)
|
||||
- Active item detection via IntersectionObserver
|
||||
- Keyboard navigation within gallery (ArrowLeft/ArrowRight between items)
|
||||
- Touch momentum and snap behavior
|
||||
- Reference base component blueprint for consistency
|
||||
|
||||
Output: `<session>/interaction/blueprints/{component-name}.md`
|
||||
|
||||
## Phase 4: Self-Validation
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| State machine complete | All states reachable, all states have exit |
|
||||
| Event coverage | All events mapped to handlers |
|
||||
| Keyboard complete | All interactive actions have keyboard equivalent |
|
||||
| Touch parity | All mouse actions have touch equivalent |
|
||||
| GPU-only animations | No width/height/top/left animations |
|
||||
| Reduced motion | prefers-reduced-motion fallback defined |
|
||||
| Screen reader path | All actions accessible via screen reader |
|
||||
|
||||
If any check fails, revise the blueprint before output.
|
||||
|
||||
Update `<session>/wisdom/.msg/meta.json` under `interaction-designer` namespace:
|
||||
- Read existing -> merge `{ "interaction-designer": { task_type, components_designed, states_count, events_count, gestures } }` -> write back
|
||||
131
.claude/skills/team-interactive-craft/roles/researcher/role.md
Normal file
131
.claude/skills/team-interactive-craft/roles/researcher/role.md
Normal file
@@ -0,0 +1,131 @@
|
||||
---
|
||||
role: researcher
|
||||
prefix: RESEARCH
|
||||
inner_loop: false
|
||||
message_types: [state_update]
|
||||
---
|
||||
|
||||
# Interaction Pattern Researcher
|
||||
|
||||
Analyze existing interactive components, audit browser API usage, and collect reference patterns for target component types. Produce foundation data for downstream interaction-designer, builder, and a11y-tester roles.
|
||||
|
||||
## Phase 2: Context & Environment Detection
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Task description | From task subject/description | Yes |
|
||||
| Session path | Extracted from task description | Yes |
|
||||
| .msg/meta.json | <session>/wisdom/.msg/meta.json | No |
|
||||
|
||||
1. Extract session path and target scope from task description
|
||||
2. Detect project structure and existing interactive patterns:
|
||||
|
||||
| File Pattern | Detected Pattern |
|
||||
|--------------|-----------------|
|
||||
| *.js with addEventListener | Event-driven components |
|
||||
| IntersectionObserver usage | Scroll-triggered animations |
|
||||
| ResizeObserver usage | Responsive layout components |
|
||||
| pointer/mouse/touch events | Interactive drag/gesture components |
|
||||
| scroll-snap in CSS | Scroll-snap gallery |
|
||||
| backdrop-filter in CSS | Glass/frosted effects |
|
||||
| clip-path in CSS | Reveal/mask animations |
|
||||
|
||||
3. Use CLI tools (e.g., `ccw cli -p "..." --tool gemini --mode analysis`) or direct tools (Glob, Grep) to scan for existing interactive components, animation patterns, event handling approaches
|
||||
4. Read interaction type context from session config
|
||||
|
||||
## Phase 3: Research Execution
|
||||
|
||||
Execute 3 analysis streams:
|
||||
|
||||
**Stream 1 -- Interaction Inventory**:
|
||||
- Search for existing interactive components (event listeners, observers, animation code)
|
||||
- Identify interaction patterns in use (drag, scroll, overlay, reveal)
|
||||
- Map component lifecycle (init, mount, resize, destroy)
|
||||
- Find dependency patterns (any external libs vs vanilla)
|
||||
- Catalog gesture handling approaches (pointer vs mouse+touch)
|
||||
- Output: `<session>/research/interaction-inventory.json`
|
||||
- Schema:
|
||||
```json
|
||||
{
|
||||
"existing_components": [
|
||||
{ "name": "", "type": "", "events": [], "observers": [], "file": "" }
|
||||
],
|
||||
"patterns": {
|
||||
"event_handling": "",
|
||||
"animation_approach": "",
|
||||
"lifecycle": "",
|
||||
"dependency_model": ""
|
||||
},
|
||||
"summary": { "total_interactive": 0, "vanilla_count": 0, "lib_count": 0 }
|
||||
}
|
||||
```
|
||||
|
||||
**Stream 2 -- Browser API Audit**:
|
||||
- Check availability and usage of target browser APIs:
|
||||
- IntersectionObserver (scroll triggers, lazy loading, visibility detection)
|
||||
- ResizeObserver (responsive layout, container queries)
|
||||
- Pointer Events (unified mouse/touch/pen input)
|
||||
- Touch Events (gesture recognition, multi-touch)
|
||||
- CSS scroll-snap (snap points, scroll behavior)
|
||||
- CSS clip-path (shape masking, reveal animations)
|
||||
- CSS backdrop-filter (blur, brightness, glass effects)
|
||||
- Web Animations API (programmatic animation control)
|
||||
- requestAnimationFrame (frame-synced updates)
|
||||
- Identify polyfill needs for target browser support
|
||||
- Output: `<session>/research/browser-api-audit.json`
|
||||
- Schema:
|
||||
```json
|
||||
{
|
||||
"apis": {
|
||||
"<api-name>": {
|
||||
"available": true,
|
||||
"in_use": false,
|
||||
"support": "baseline|modern|polyfill-needed",
|
||||
"usage_count": 0,
|
||||
"notes": ""
|
||||
}
|
||||
},
|
||||
"polyfill_needs": [],
|
||||
"min_browser_target": ""
|
||||
}
|
||||
```
|
||||
|
||||
**Stream 3 -- Pattern Reference**:
|
||||
- Collect reference patterns for each target component type
|
||||
- For each component, document: state machine pattern, event flow, animation approach, touch handling, accessibility pattern
|
||||
- Reference well-known implementations (e.g., scroll-snap gallery, split-view compare, lightbox overlay)
|
||||
- Note performance considerations and gotchas per pattern
|
||||
- Output: `<session>/research/pattern-reference.json`
|
||||
- Schema:
|
||||
```json
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"component_type": "",
|
||||
"state_machine": { "states": [], "transitions": [] },
|
||||
"events": { "primary": [], "fallback": [] },
|
||||
"animation": { "approach": "", "gpu_only": true, "easing": "" },
|
||||
"touch": { "gestures": [], "threshold_px": 0 },
|
||||
"a11y": { "role": "", "aria_states": [], "keyboard": [] },
|
||||
"performance": { "budget_ms": 0, "gotchas": [] }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Compile research summary metrics: existing_interactive_count, vanilla_ratio, apis_available, polyfill_count, patterns_collected.
|
||||
|
||||
## Phase 4: Validation & Output
|
||||
|
||||
1. Verify all 3 output files exist and contain valid JSON with required fields:
|
||||
|
||||
| File | Required Fields |
|
||||
|------|----------------|
|
||||
| interaction-inventory.json | existing_components array, patterns object |
|
||||
| browser-api-audit.json | apis object |
|
||||
| pattern-reference.json | patterns array |
|
||||
|
||||
2. If any file missing or invalid, re-run corresponding stream
|
||||
|
||||
3. Update `<session>/wisdom/.msg/meta.json` under `researcher` namespace:
|
||||
- Read existing -> merge `{ "researcher": { interactive_count, vanilla_ratio, apis_available, polyfill_needs, scope } }` -> write back
|
||||
@@ -0,0 +1,362 @@
|
||||
# Interaction Pattern Catalog
|
||||
|
||||
Reference patterns for common interactive components. Each pattern defines the core interaction model, browser APIs, state machine, animation approach, and accessibility requirements.
|
||||
|
||||
---
|
||||
|
||||
## Glass Terminal Pattern
|
||||
|
||||
Split-view layout with frosted glass effect, tab navigation, and command input simulation.
|
||||
|
||||
**Core Interaction**:
|
||||
- Tab-based view switching (2-4 panels)
|
||||
- Command input field with syntax-highlighted output
|
||||
- Frosted glass background via `backdrop-filter: blur()`
|
||||
- Resize-aware layout via ResizeObserver
|
||||
|
||||
**State Machine**:
|
||||
```
|
||||
[idle] --(tab-click)--> [switching]
|
||||
[switching] --(transition-end)--> [idle]
|
||||
[idle] --(input-focus)--> [input-active]
|
||||
[input-active] --(Enter)--> [processing]
|
||||
[processing] --(output-ready)--> [idle]
|
||||
[input-active] --(Escape)--> [idle]
|
||||
```
|
||||
|
||||
**Browser APIs**: ResizeObserver, CSS backdrop-filter, CSS custom properties
|
||||
|
||||
**Animation**:
|
||||
- Tab switch: opacity crossfade (200ms, ease-out), GPU-only
|
||||
- Output appear: translateY(10px)->0 + opacity (300ms, ease-out)
|
||||
- Cursor blink: CSS animation (1s steps(2))
|
||||
|
||||
**CSS Key Properties**:
|
||||
```css
|
||||
.glass-terminal {
|
||||
backdrop-filter: blur(12px) saturate(180%);
|
||||
-webkit-backdrop-filter: blur(12px) saturate(180%);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
```
|
||||
|
||||
**Accessibility**:
|
||||
- role="tablist" + role="tab" + role="tabpanel"
|
||||
- aria-selected on active tab
|
||||
- Arrow keys navigate tabs, Enter/Space activates
|
||||
- Input field: role="textbox", aria-label
|
||||
- Output: aria-live="polite" for new content
|
||||
|
||||
---
|
||||
|
||||
## Split Compare Pattern
|
||||
|
||||
Before/after overlay with draggable divider for visual comparison.
|
||||
|
||||
**Core Interaction**:
|
||||
- Draggable vertical divider splits two overlapping images/views
|
||||
- Pointer events for drag with Lerp interpolation (speed: 0.15)
|
||||
- clip-path animation reveals before/after content
|
||||
- Touch-friendly with full pointer event support
|
||||
|
||||
**State Machine**:
|
||||
```
|
||||
[idle] --(pointerenter)--> [hover]
|
||||
[hover] --(pointerdown on divider)--> [dragging]
|
||||
[hover] --(pointerleave)--> [idle]
|
||||
[dragging] --(pointermove)--> [dragging] (update position)
|
||||
[dragging] --(pointerup)--> [settling]
|
||||
[settling] --(lerp-complete)--> [idle]
|
||||
[any] --(focus + ArrowLeft/Right)--> [keyboard-adjusting]
|
||||
[keyboard-adjusting] --(keyup)--> [idle]
|
||||
```
|
||||
|
||||
**Browser APIs**: Pointer Events, CSS clip-path, ResizeObserver, requestAnimationFrame
|
||||
|
||||
**Animation**:
|
||||
- Divider follow: Lerp `current += (target - current) * 0.15` per frame
|
||||
- Clip-path update: `clip-path: inset(0 0 0 ${position}%)` on after layer
|
||||
- Settle: natural Lerp deceleration to final position
|
||||
- Hover hint: divider scale(1.1) + glow (200ms, ease-out)
|
||||
|
||||
**CSS Key Properties**:
|
||||
```css
|
||||
.split-compare__after {
|
||||
clip-path: inset(0 0 0 var(--split-position, 50%));
|
||||
transition: none; /* JS-driven via lerp */
|
||||
}
|
||||
.split-compare__divider {
|
||||
cursor: col-resize;
|
||||
touch-action: none; /* prevent scroll during drag */
|
||||
}
|
||||
```
|
||||
|
||||
**Keyboard**:
|
||||
- Tab to divider element (tabindex="0")
|
||||
- ArrowLeft/ArrowRight: move divider 2% per keypress
|
||||
- Home/End: move to 0%/100%
|
||||
|
||||
**Accessibility**:
|
||||
- role="slider", aria-valuenow, aria-valuemin="0", aria-valuemax="100"
|
||||
- aria-label="Image comparison slider"
|
||||
- Keyboard step: 2%, large step (PageUp/PageDown): 10%
|
||||
|
||||
---
|
||||
|
||||
## Scroll-Snap Gallery Pattern
|
||||
|
||||
Horizontal scroll with CSS scroll-snap, navigation controls, and active item detection.
|
||||
|
||||
**Core Interaction**:
|
||||
- CSS scroll-snap-type: x mandatory on container
|
||||
- scroll-snap-align: start on children
|
||||
- Touch-friendly: native momentum scrolling
|
||||
- Navigation dots/arrows update with IntersectionObserver
|
||||
- Keyboard: ArrowLeft/ArrowRight navigate between items
|
||||
|
||||
**State Machine**:
|
||||
```
|
||||
[idle] --(scroll-start)--> [scrolling]
|
||||
[scrolling] --(scroll-end)--> [snapped]
|
||||
[snapped] --(intersection-change)--> [idle] (update active)
|
||||
[idle] --(arrow-click)--> [navigating]
|
||||
[navigating] --(scrollTo-complete)--> [idle]
|
||||
[idle] --(keyboard-arrow)--> [navigating]
|
||||
```
|
||||
|
||||
**Browser APIs**: CSS scroll-snap, IntersectionObserver, Element.scrollTo(), Pointer Events
|
||||
|
||||
**Animation**:
|
||||
- Scroll: native CSS scroll-snap (browser-handled, smooth)
|
||||
- Active dot: scale(1) -> scale(1.3) + opacity change (200ms, ease-out)
|
||||
- Item entry: opacity 0->1 as intersection threshold crossed (CSS transition)
|
||||
- Arrow hover: translateX(+-2px) (150ms, ease-out)
|
||||
|
||||
**CSS Key Properties**:
|
||||
```css
|
||||
.gallery__track {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x mandatory;
|
||||
scroll-behavior: smooth;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
.gallery__track::-webkit-scrollbar { display: none; }
|
||||
.gallery__item {
|
||||
scroll-snap-align: start;
|
||||
flex: 0 0 100%; /* or 80% for peek */
|
||||
}
|
||||
```
|
||||
|
||||
**IntersectionObserver Config**:
|
||||
```javascript
|
||||
new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) updateActiveItem(entry.target);
|
||||
});
|
||||
}, { root: trackElement, threshold: 0.5 });
|
||||
```
|
||||
|
||||
**Accessibility**:
|
||||
- role="region", aria-label="Image gallery"
|
||||
- role="group" on each item, aria-roledescription="slide"
|
||||
- aria-label="Slide N of M" on each item
|
||||
- Navigation: role="tablist" on dots, role="tab" on each dot
|
||||
- ArrowLeft/ArrowRight between items, Home/End to first/last
|
||||
|
||||
---
|
||||
|
||||
## Scroll Reveal Pattern
|
||||
|
||||
Elements animate into view as user scrolls, using IntersectionObserver with staggered delays.
|
||||
|
||||
**Core Interaction**:
|
||||
- IntersectionObserver with threshold: 0.1 triggers entry animation
|
||||
- data-reveal attribute marks revealable elements
|
||||
- Staggered delay: index * 80ms for grouped items
|
||||
- GPU-only: translateY(20px)->0 + opacity 0->1
|
||||
- One-shot: element stays visible after reveal
|
||||
|
||||
**State Machine**:
|
||||
```
|
||||
[hidden] --(intersection: entering)--> [revealing]
|
||||
[revealing] --(animation-end)--> [visible]
|
||||
[visible] -- (terminal state, no transition out)
|
||||
```
|
||||
|
||||
**Browser APIs**: IntersectionObserver, CSS transitions, requestAnimationFrame
|
||||
|
||||
**Animation**:
|
||||
- Entry: translateY(20px) -> translateY(0) + opacity 0->1
|
||||
- Duration: 400ms
|
||||
- Easing: cubic-bezier(0.16, 1, 0.3, 1)
|
||||
- Stagger: CSS custom property `--reveal-delay: calc(var(--reveal-index) * 80ms)`
|
||||
- Reduced motion: opacity-only crossfade (200ms)
|
||||
|
||||
**CSS Key Properties**:
|
||||
```css
|
||||
[data-reveal] {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 400ms cubic-bezier(0.16, 1, 0.3, 1),
|
||||
transform 400ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
transition-delay: var(--reveal-delay, 0ms);
|
||||
}
|
||||
[data-reveal="visible"] {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
[data-reveal] {
|
||||
transform: none;
|
||||
transition: opacity 200ms ease;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**IntersectionObserver Config**:
|
||||
```javascript
|
||||
new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.dataset.reveal = 'visible';
|
||||
observer.unobserve(entry.target); // one-shot
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.1 });
|
||||
```
|
||||
|
||||
**Accessibility**:
|
||||
- Content must be accessible in DOM before reveal (no display:none)
|
||||
- Use opacity + transform only (content readable by screen readers at all times)
|
||||
- aria-hidden NOT used (content is always in accessibility tree)
|
||||
- Stagger delay < 500ms total to avoid perception of broken page
|
||||
|
||||
---
|
||||
|
||||
## Lens/Overlay Pattern
|
||||
|
||||
Magnification overlay that follows pointer position over an image or content area.
|
||||
|
||||
**Core Interaction**:
|
||||
- Circular/rectangular lens follows pointer over source content
|
||||
- Magnified view rendered via CSS transform: scale() on background
|
||||
- Lens positioned via transform: translate() (GPU-only)
|
||||
- Toggle on click/tap, follow on pointermove
|
||||
|
||||
**State Machine**:
|
||||
```
|
||||
[inactive] --(click/tap on source)--> [active]
|
||||
[active] --(pointermove)--> [active] (update lens position)
|
||||
[active] --(click/tap)--> [inactive]
|
||||
[active] --(pointerleave)--> [inactive]
|
||||
[active] --(Escape)--> [inactive]
|
||||
[inactive] --(Enter/Space on source)--> [active-keyboard]
|
||||
[active-keyboard] --(Arrow keys)--> [active-keyboard] (move lens)
|
||||
[active-keyboard] --(Escape)--> [inactive]
|
||||
```
|
||||
|
||||
**Browser APIs**: Pointer Events, CSS transform, CSS clip-path/border-radius, requestAnimationFrame
|
||||
|
||||
**Animation**:
|
||||
- Lens appear: opacity 0->1 + scale(0.8)->scale(1) (200ms, ease-out)
|
||||
- Lens follow: Lerp position tracking (speed: 0.2)
|
||||
- Lens dismiss: opacity 1->0 + scale(1)->scale(0.9) (150ms, ease-in)
|
||||
|
||||
**CSS Key Properties**:
|
||||
```css
|
||||
.lens__overlay {
|
||||
position: absolute;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
transform: translate(var(--lens-x), var(--lens-y));
|
||||
will-change: transform;
|
||||
}
|
||||
.lens__magnified {
|
||||
transform: scale(var(--lens-zoom, 2));
|
||||
transform-origin: var(--lens-origin-x) var(--lens-origin-y);
|
||||
}
|
||||
```
|
||||
|
||||
**Accessibility**:
|
||||
- Source: role="img" with descriptive aria-label
|
||||
- Lens toggle: aria-expanded on source element
|
||||
- Keyboard: Enter/Space to activate, Arrow keys to pan, Escape to dismiss
|
||||
- Screen reader: aria-live="polite" announces zoom state changes
|
||||
- Not essential content: decorative enhancement, base content always visible
|
||||
|
||||
---
|
||||
|
||||
## Lightbox Pattern
|
||||
|
||||
Full-viewport overlay for content viewing with background dim and entry animation.
|
||||
|
||||
**Core Interaction**:
|
||||
- Click/tap thumbnail opens full-viewport overlay
|
||||
- Background dim via backdrop-filter + background overlay
|
||||
- Scale-up entry animation from thumbnail position
|
||||
- Dismiss: click outside, Escape key, close button
|
||||
- Focus trap: Tab cycles within lightbox
|
||||
- Scroll lock on body while open
|
||||
|
||||
**State Machine**:
|
||||
```
|
||||
[closed] --(click thumbnail)--> [opening]
|
||||
[opening] --(animation-end)--> [open]
|
||||
[open] --(click-outside / Escape / close-btn)--> [closing]
|
||||
[closing] --(animation-end)--> [closed]
|
||||
[open] --(ArrowLeft)--> [navigating-prev]
|
||||
[open] --(ArrowRight)--> [navigating-next]
|
||||
[navigating-*] --(content-loaded)--> [open]
|
||||
```
|
||||
|
||||
**Browser APIs**: CSS backdrop-filter, Focus trap (manual), CSS transitions, Pointer Events
|
||||
|
||||
**Animation**:
|
||||
- Open: scale(0.85)->scale(1) + opacity 0->1 (300ms, cubic-bezier(0.16,1,0.3,1))
|
||||
- Close: scale(1)->scale(0.95) + opacity 1->0 (200ms, ease-in)
|
||||
- Backdrop: opacity 0->1 (250ms, ease-out)
|
||||
- Navigation: translateX crossfade between items (250ms)
|
||||
|
||||
**CSS Key Properties**:
|
||||
```css
|
||||
.lightbox__backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
backdrop-filter: blur(4px);
|
||||
z-index: 1000;
|
||||
}
|
||||
.lightbox__content {
|
||||
transform: scale(var(--lb-scale, 0.85));
|
||||
opacity: var(--lb-opacity, 0);
|
||||
transition: transform 300ms cubic-bezier(0.16, 1, 0.3, 1),
|
||||
opacity 300ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
.lightbox--open .lightbox__content {
|
||||
--lb-scale: 1;
|
||||
--lb-opacity: 1;
|
||||
}
|
||||
```
|
||||
|
||||
**Focus Trap Implementation**:
|
||||
```javascript
|
||||
// On open: store trigger, move focus to first focusable in lightbox
|
||||
// On Tab: cycle within lightbox (first <-> last focusable)
|
||||
// On close: restore focus to original trigger element
|
||||
// Prevent body scroll: document.body.style.overflow = 'hidden'
|
||||
```
|
||||
|
||||
**Accessibility**:
|
||||
- role="dialog", aria-modal="true", aria-label="Image viewer"
|
||||
- Close button: aria-label="Close lightbox"
|
||||
- Focus trap: Tab cycles within dialog
|
||||
- Escape dismisses
|
||||
- ArrowLeft/ArrowRight for gallery navigation
|
||||
- aria-live="polite" announces current item "Image N of M"
|
||||
- Scroll lock: prevent background scroll while open
|
||||
85
.claude/skills/team-interactive-craft/specs/pipelines.md
Normal file
85
.claude/skills/team-interactive-craft/specs/pipelines.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Pipeline Definitions
|
||||
|
||||
Interactive craft pipeline modes and task registry.
|
||||
|
||||
## Pipeline Modes
|
||||
|
||||
| Mode | Description | Task Count |
|
||||
|------|-------------|------------|
|
||||
| single | Single component: research -> interaction design -> build -> a11y test | 4 tasks |
|
||||
| gallery | Gallery: base component + scroll container, two build phases | 6 tasks |
|
||||
| page | Full page: parallel component builds after single interaction design | 3 + N tasks |
|
||||
|
||||
## Single Pipeline Task Registry
|
||||
|
||||
| Task ID | Role | blockedBy | Description |
|
||||
|---------|------|-----------|-------------|
|
||||
| RESEARCH-001 | researcher | [] | Interaction inventory, browser API audit, pattern reference |
|
||||
| INTERACT-001 | interaction-designer | [RESEARCH-001] | State machine, event flow, gesture spec, animation choreography |
|
||||
| BUILD-001 | builder | [INTERACT-001] | Vanilla JS + CSS component: ES module, GPU animations, touch-aware |
|
||||
| A11Y-001 | a11y-tester | [BUILD-001] | Keyboard, screen reader, reduced motion, focus, contrast audit |
|
||||
|
||||
## Gallery Pipeline Task Registry
|
||||
|
||||
| Task ID | Role | blockedBy | Description |
|
||||
|---------|------|-----------|-------------|
|
||||
| RESEARCH-001 | researcher | [] | Interaction patterns for base component + gallery container |
|
||||
| INTERACT-001 | interaction-designer | [RESEARCH-001] | Base component interaction blueprint |
|
||||
| BUILD-001 | builder | [INTERACT-001] | Base component implementation |
|
||||
| INTERACT-002 | interaction-designer | [BUILD-001] | Gallery/scroll-snap container blueprint |
|
||||
| BUILD-002 | builder | [INTERACT-002] | Gallery container + navigation implementation |
|
||||
| A11Y-001 | a11y-tester | [BUILD-002] | Full gallery accessibility audit |
|
||||
|
||||
## Page Pipeline Task Registry
|
||||
|
||||
| Task ID | Role | blockedBy | Description |
|
||||
|---------|------|-----------|-------------|
|
||||
| RESEARCH-001 | researcher | [] | Interaction patterns for all page sections |
|
||||
| INTERACT-001 | interaction-designer | [RESEARCH-001] | Blueprints for all interactive sections |
|
||||
| BUILD-001 | builder | [INTERACT-001] | Section 1 component |
|
||||
| BUILD-002 | builder | [INTERACT-001] | Section 2 component |
|
||||
| ... | builder | [INTERACT-001] | Additional sections (parallel) |
|
||||
| BUILD-00N | builder | [INTERACT-001] | Section N component |
|
||||
| A11Y-001 | a11y-tester | [BUILD-001..N] | Full page accessibility audit |
|
||||
|
||||
## Quality Gate (A11y Checkpoint)
|
||||
|
||||
| Checkpoint | Task | Condition | Action |
|
||||
|------------|------|-----------|--------|
|
||||
| A11Y Gate | A11Y-001 completes | 0 critical, 0 high | Pipeline complete |
|
||||
| A11Y GC Loop | A11Y-* completes | Critical or high issues | Create BUILD-fix task, new A11Y task (max 2 rounds) |
|
||||
|
||||
## GC Loop Behavior
|
||||
|
||||
| Signal | Condition | Action |
|
||||
|--------|-----------|--------|
|
||||
| a11y_passed | 0 critical, 0 high | GC converged -> pipeline complete |
|
||||
| a11y_result | 0 critical, high > 0 | gc_rounds < max -> create BUILD-fix task |
|
||||
| fix_required | critical > 0 | gc_rounds < max -> create BUILD-fix task (CRITICAL) |
|
||||
| Any | gc_rounds >= max | Escalate to user: accept / try one more / terminate |
|
||||
|
||||
## Parallel Spawn Rules
|
||||
|
||||
| Mode | After | Spawn Behavior |
|
||||
|------|-------|----------------|
|
||||
| single | Sequential | One task at a time |
|
||||
| gallery | Sequential | One task at a time |
|
||||
| page | INTERACT-001 | Spawn BUILD-001..N in parallel (CP-3 fan-out) |
|
||||
| page | All BUILD complete | Spawn A11Y-001 |
|
||||
|
||||
## Collaboration Patterns
|
||||
|
||||
| Pattern | Roles | Description |
|
||||
|---------|-------|-------------|
|
||||
| CP-1 Linear Pipeline | All | Base sequential flow for single/gallery modes |
|
||||
| CP-2 Review-Fix | builder <-> a11y-tester | GC loop with max 2 rounds |
|
||||
| CP-3 Parallel Fan-out | builder (multiple) | Page mode: multiple BUILD tasks in parallel |
|
||||
|
||||
## Output Artifacts
|
||||
|
||||
| Task | Output Path |
|
||||
|------|-------------|
|
||||
| RESEARCH-001 | <session>/research/*.json |
|
||||
| INTERACT-* | <session>/interaction/blueprints/*.md |
|
||||
| BUILD-* | <session>/build/components/*.js + *.css |
|
||||
| A11Y-* | <session>/a11y/a11y-audit-*.md |
|
||||
105
.claude/skills/team-interactive-craft/specs/team-config.json
Normal file
105
.claude/skills/team-interactive-craft/specs/team-config.json
Normal file
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"team_name": "interactive-craft",
|
||||
"team_display_name": "Interactive Craft",
|
||||
"description": "Interactive component team with vanilla JS + CSS. Research -> interaction design -> build -> a11y test.",
|
||||
"version": "1.0.0",
|
||||
|
||||
"roles": {
|
||||
"coordinator": {
|
||||
"task_prefix": null,
|
||||
"responsibility": "Scope assessment, pipeline orchestration, GC loop control between builder and a11y-tester",
|
||||
"message_types": ["task_unblocked", "a11y_checkpoint", "fix_required", "error", "shutdown"]
|
||||
},
|
||||
"researcher": {
|
||||
"task_prefix": "RESEARCH",
|
||||
"responsibility": "Interaction pattern analysis, browser API audit, reference pattern collection",
|
||||
"message_types": ["research_ready", "research_progress", "error"]
|
||||
},
|
||||
"interaction-designer": {
|
||||
"task_prefix": "INTERACT",
|
||||
"responsibility": "State machine design, event flow mapping, gesture specification, animation choreography",
|
||||
"message_types": ["blueprint_ready", "blueprint_revision", "blueprint_progress", "error"]
|
||||
},
|
||||
"builder": {
|
||||
"task_prefix": "BUILD",
|
||||
"inner_loop": true,
|
||||
"responsibility": "Vanilla JS + CSS component implementation, progressive enhancement, GPU-only animations",
|
||||
"message_types": ["build_ready", "build_revision", "build_progress", "error"]
|
||||
},
|
||||
"a11y-tester": {
|
||||
"task_prefix": "A11Y",
|
||||
"responsibility": "Keyboard navigation, screen reader, reduced motion, focus management, contrast testing",
|
||||
"message_types": ["a11y_passed", "a11y_result", "fix_required", "error"]
|
||||
}
|
||||
},
|
||||
|
||||
"pipelines": {
|
||||
"single": {
|
||||
"description": "Single component: research -> interaction design -> build -> a11y test",
|
||||
"task_chain": ["RESEARCH-001", "INTERACT-001", "BUILD-001", "A11Y-001"],
|
||||
"complexity": "low"
|
||||
},
|
||||
"gallery": {
|
||||
"description": "Gallery with base component + scroll container: two build phases",
|
||||
"task_chain": [
|
||||
"RESEARCH-001",
|
||||
"INTERACT-001", "BUILD-001",
|
||||
"INTERACT-002", "BUILD-002",
|
||||
"A11Y-001"
|
||||
],
|
||||
"complexity": "medium"
|
||||
},
|
||||
"page": {
|
||||
"description": "Full interactive page with parallel component builds",
|
||||
"task_chain": [
|
||||
"RESEARCH-001",
|
||||
"INTERACT-001",
|
||||
"BUILD-001..N (parallel)",
|
||||
"A11Y-001"
|
||||
],
|
||||
"parallel_stage": "BUILD-001..N",
|
||||
"complexity": "high"
|
||||
}
|
||||
},
|
||||
|
||||
"innovation_patterns": {
|
||||
"generator_critic": {
|
||||
"generator": "builder",
|
||||
"critic": "a11y-tester",
|
||||
"max_rounds": 2,
|
||||
"convergence": "a11y.critical_count === 0 && a11y.high_count === 0",
|
||||
"escalation": "Coordinator intervenes after max rounds"
|
||||
},
|
||||
"shared_memory": {
|
||||
"file": "shared-memory.json",
|
||||
"fields": {
|
||||
"researcher": ["interaction_inventory", "browser_apis"],
|
||||
"interaction-designer": ["state_machines", "event_flows"],
|
||||
"builder": ["component_registry", "implementation_decisions"],
|
||||
"a11y-tester": ["audit_history"]
|
||||
}
|
||||
},
|
||||
"dynamic_pipeline": {
|
||||
"criteria": {
|
||||
"single": "scope.component_count <= 1",
|
||||
"gallery": "scope.has_gallery || scope.has_scroll_collection",
|
||||
"page": "scope.is_full_page || scope.section_count > 2"
|
||||
}
|
||||
},
|
||||
"parallel_fanout": {
|
||||
"pattern": "CP-3",
|
||||
"description": "Multiple BUILD tasks spawned in parallel after single INTERACT blueprint",
|
||||
"trigger": "page mode after INTERACT-001 completes",
|
||||
"fallback": "If parallel fails, coordinator falls back to sequential execution"
|
||||
}
|
||||
},
|
||||
|
||||
"session_dirs": {
|
||||
"base": ".workflow/.team/IC-{slug}-{YYYY-MM-DD}/",
|
||||
"research": "research/",
|
||||
"interaction": "interaction/blueprints/",
|
||||
"build": "build/components/",
|
||||
"a11y": "a11y/",
|
||||
"messages": ".workflow/.team-msg/{team-name}/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
# Vanilla Constraints
|
||||
|
||||
Zero-dependency rules for all interactive components built by this team. These constraints are non-negotiable and apply to every BUILD task output.
|
||||
|
||||
## Dependency Rules
|
||||
|
||||
| Rule | Requirement |
|
||||
|------|-------------|
|
||||
| No npm packages | Zero `import` from node_modules or CDN URLs |
|
||||
| No build tools required | Components run directly via `<script type="module">` |
|
||||
| No framework dependency | No React, Vue, Svelte, Angular, jQuery, etc. |
|
||||
| No CSS preprocessor | No Sass, Less, PostCSS, Tailwind -- pure CSS only |
|
||||
| No bundler required | No webpack, Vite, Rollup, esbuild in critical path |
|
||||
|
||||
## JavaScript Rules
|
||||
|
||||
| Rule | Requirement |
|
||||
|------|-------------|
|
||||
| ES modules only | `export class`, `export function`, `import` syntax |
|
||||
| Class-based components | Private fields (#), constructor(element, options) |
|
||||
| No inline styles from JS | Set CSS custom properties or toggle CSS classes |
|
||||
| No document.write | Use DOM APIs (createElement, append, etc.) |
|
||||
| No eval or innerHTML | Use textContent or DOM construction |
|
||||
| requestAnimationFrame | All animation loops use rAF, not setInterval |
|
||||
| Pointer Events primary | Use pointer events; touch events as fallback only |
|
||||
| Cleanup required | destroy() method disconnects all observers/listeners |
|
||||
| Auto-init pattern | `document.querySelectorAll('[data-component]')` on load |
|
||||
|
||||
## CSS Rules
|
||||
|
||||
| Rule | Requirement |
|
||||
|------|-------------|
|
||||
| Custom properties | All configurable values as CSS custom properties |
|
||||
| No inline styles | JS sets `--custom-prop` values, not style.left/top |
|
||||
| State via data attributes | `[data-state="active"]`, not inline style changes |
|
||||
| GPU-only animations | `transform` and `opacity` ONLY in transitions/animations |
|
||||
| No layout animations | Never animate `width`, `height`, `top`, `left`, `margin`, `padding` |
|
||||
| will-change on animated | Hint browser for animated elements |
|
||||
| Reduced motion | `@media (prefers-reduced-motion: reduce)` with instant fallback |
|
||||
| focus-visible | `:focus-visible` for keyboard-only focus indicators |
|
||||
| Responsive | Min touch target 44x44px on mobile, use @media breakpoints |
|
||||
|
||||
## Progressive Enhancement
|
||||
|
||||
| Rule | Requirement |
|
||||
|------|-------------|
|
||||
| Content without JS | Base content visible and readable without JavaScript |
|
||||
| CSS-only fallback | Essential layout works with CSS alone |
|
||||
| No-JS class | Optional `[data-js-enabled]` class for JS-enhanced styles |
|
||||
| Semantic HTML base | Use appropriate elements (button, a, nav, dialog) |
|
||||
|
||||
## Performance Budget
|
||||
|
||||
| Metric | Budget |
|
||||
|--------|--------|
|
||||
| Frame time | < 5ms per frame (leaves room for browser work in 16ms budget) |
|
||||
| Interaction response | < 50ms from input to visual feedback |
|
||||
| Animation jank | 0 frames dropped at 60fps for GPU-composited animations |
|
||||
| Observer callbacks | < 1ms per IntersectionObserver/ResizeObserver callback |
|
||||
| Component init | < 100ms from constructor to interactive |
|
||||
| Memory | No detached DOM nodes after destroy() |
|
||||
| Listeners | All removed in destroy(), no orphaned listeners |
|
||||
|
||||
## Forbidden Patterns
|
||||
|
||||
| Pattern | Why |
|
||||
|---------|-----|
|
||||
| `element.style.left = ...` | Forces layout recalc, not GPU composited |
|
||||
| `element.offsetWidth` in animation loop | Forces synchronous layout (reflow) |
|
||||
| `setInterval` for animation | Not synced to display refresh rate |
|
||||
| `setTimeout` for animation | Not synced to display refresh rate |
|
||||
| `innerHTML = userContent` | XSS vector |
|
||||
| Passive: false on scroll/touch without need | Blocks scrolling performance |
|
||||
| `!important` in component CSS | Breaks cascade, unmaintainable |
|
||||
| Global CSS selectors (tag-only) | Leaks styles outside component scope |
|
||||
|
||||
## File Output Convention
|
||||
|
||||
| File | Purpose | Location |
|
||||
|------|---------|----------|
|
||||
| `{name}.js` | ES module component class | `<session>/build/components/` |
|
||||
| `{name}.css` | Component styles with custom properties | `<session>/build/components/` |
|
||||
| `demo.html` | Optional: standalone demo page | `<session>/build/components/` |
|
||||
@@ -1,127 +0,0 @@
|
||||
---
|
||||
name: team-iterdev
|
||||
description: Unified team skill for iterative development team. Pure router — all roles read this file. Beat model is coordinator-only in monitor.md. Generator-Critic loops (developer<->reviewer, max 3 rounds). Triggers on "team iterdev".
|
||||
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Agent(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
|
||||
---
|
||||
|
||||
# Team IterDev
|
||||
|
||||
Iterative development team skill. Generator-Critic loops (developer<->reviewer, max 3 rounds), task ledger (task-ledger.json) for real-time progress, shared memory (cross-sprint learning), and dynamic pipeline selection for incremental delivery.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Skill(skill="team-iterdev", args="task description")
|
||||
|
|
||||
SKILL.md (this file) = Router
|
||||
|
|
||||
+--------------+--------------+
|
||||
| |
|
||||
no --role flag --role <name>
|
||||
| |
|
||||
Coordinator Worker
|
||||
roles/coordinator/role.md roles/<name>/role.md
|
||||
|
|
||||
+-- analyze -> dispatch -> spawn workers -> STOP
|
||||
|
|
||||
+-------+-------+-------+
|
||||
v v v v
|
||||
[architect] [developer] [tester] [reviewer]
|
||||
(team-worker agents, each loads roles/<role>/role.md)
|
||||
```
|
||||
|
||||
## Role Registry
|
||||
|
||||
| Role | Path | Prefix | Inner Loop |
|
||||
|------|------|--------|------------|
|
||||
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | — | — |
|
||||
| architect | [roles/architect/role.md](roles/architect/role.md) | DESIGN-* | false |
|
||||
| developer | [roles/developer/role.md](roles/developer/role.md) | DEV-* | true |
|
||||
| tester | [roles/tester/role.md](roles/tester/role.md) | VERIFY-* | false |
|
||||
| reviewer | [roles/reviewer/role.md](roles/reviewer/role.md) | REVIEW-* | false |
|
||||
|
||||
## Role Router
|
||||
|
||||
Parse `$ARGUMENTS`:
|
||||
- Has `--role <name>` → Read `roles/<name>/role.md`, execute Phase 2-4
|
||||
- No `--role` → `@roles/coordinator/role.md`, execute entry router
|
||||
|
||||
## Shared Constants
|
||||
|
||||
- **Session prefix**: `IDS`
|
||||
- **Session path**: `.workflow/.team/IDS-<slug>-<date>/`
|
||||
- **CLI tools**: `ccw cli --mode analysis` (read-only), `ccw cli --mode write` (modifications)
|
||||
- **Message bus**: `mcp__ccw-tools__team_msg(session_id=<session-id>, ...)`
|
||||
|
||||
## Worker Spawn Template
|
||||
|
||||
Coordinator spawns workers using this template:
|
||||
|
||||
```
|
||||
Agent({
|
||||
subagent_type: "team-worker",
|
||||
description: "Spawn <role> worker",
|
||||
team_name: "iterdev",
|
||||
name: "<role>",
|
||||
run_in_background: true,
|
||||
prompt: `## Role Assignment
|
||||
role: <role>
|
||||
role_spec: <skill_root>/roles/<role>/role.md
|
||||
session: <session-folder>
|
||||
session_id: <session-id>
|
||||
team_name: iterdev
|
||||
requirement: <task-description>
|
||||
inner_loop: <true|false>
|
||||
|
||||
Read role_spec file (@<skill_root>/roles/<role>/role.md) to load Phase 2-4 domain instructions.
|
||||
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).`
|
||||
})
|
||||
```
|
||||
|
||||
## User Commands
|
||||
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| `check` / `status` | View execution status graph |
|
||||
| `resume` / `continue` | Advance to next step |
|
||||
|
||||
## Session Directory
|
||||
|
||||
```
|
||||
.workflow/.team/IDS-<slug>-<YYYY-MM-DD>/
|
||||
├── .msg/
|
||||
│ ├── messages.jsonl # Team message bus
|
||||
│ └── meta.json # Session state
|
||||
├── task-analysis.json # Coordinator analyze output
|
||||
├── task-ledger.json # Real-time task progress ledger
|
||||
├── wisdom/ # Cross-task knowledge accumulation
|
||||
│ ├── learnings.md
|
||||
│ ├── decisions.md
|
||||
│ ├── conventions.md
|
||||
│ └── issues.md
|
||||
├── design/ # Architect output
|
||||
│ ├── design-001.md
|
||||
│ └── task-breakdown.json
|
||||
├── code/ # Developer tracking
|
||||
│ └── dev-log.md
|
||||
├── verify/ # Tester output
|
||||
│ └── verify-001.json
|
||||
└── review/ # Reviewer output
|
||||
└── review-001.md
|
||||
```
|
||||
|
||||
## Specs Reference
|
||||
|
||||
- [specs/pipelines.md](specs/pipelines.md) — Pipeline definitions and task registry
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Unknown command | Error with available command list |
|
||||
| Role not found | Error with role registry |
|
||||
| GC loop exceeds 3 rounds | Accept with warning, record in shared memory |
|
||||
| Sprint velocity drops below 50% | Coordinator alerts user, suggests scope reduction |
|
||||
| Task ledger corrupted | Rebuild from TaskList state |
|
||||
| Conflict detected | Update conflict_info, notify coordinator, create DEV-fix task |
|
||||
| Pipeline deadlock | Check blockedBy chain, report blocking point |
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
role: architect
|
||||
prefix: DESIGN
|
||||
inner_loop: false
|
||||
message_types:
|
||||
success: design_ready
|
||||
revision: design_revision
|
||||
error: error
|
||||
---
|
||||
|
||||
# Architect
|
||||
|
||||
Technical design, task decomposition, and architecture decision records for iterative development.
|
||||
|
||||
## Phase 2: Context Loading + Codebase Exploration
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Task description | From task subject/description | Yes |
|
||||
| Session path | Extracted from task description | Yes |
|
||||
| .msg/meta.json | <session>/.msg/meta.json | No |
|
||||
| Wisdom files | <session>/wisdom/ | No |
|
||||
|
||||
1. Extract session path and requirement from task description
|
||||
2. Read .msg/meta.json for shared context (architecture_decisions, implementation_context)
|
||||
3. Read wisdom files if available (learnings.md, decisions.md, conventions.md)
|
||||
4. Explore codebase for existing patterns, module structure, dependencies:
|
||||
- Use mcp__ace-tool__search_context for semantic discovery
|
||||
- Identify similar implementations and integration points
|
||||
|
||||
## Phase 3: Technical Design + Task Decomposition
|
||||
|
||||
**Design strategy selection**:
|
||||
|
||||
| Condition | Strategy |
|
||||
|-----------|----------|
|
||||
| Single module change | Direct inline design |
|
||||
| Cross-module change | Multi-component design with integration points |
|
||||
| Large refactoring | Phased approach with milestones |
|
||||
|
||||
**Outputs**:
|
||||
|
||||
1. **Design Document** (`<session>/design/design-<num>.md`):
|
||||
- Architecture decision: approach, rationale, alternatives
|
||||
- Component design: responsibility, dependencies, files, complexity
|
||||
- Task breakdown: files, estimated complexity, dependencies, acceptance criteria
|
||||
- Integration points and risks with mitigations
|
||||
|
||||
2. **Task Breakdown JSON** (`<session>/design/task-breakdown.json`):
|
||||
- Array of tasks with id, title, files, complexity, dependencies, acceptance_criteria
|
||||
- Execution order for developer to follow
|
||||
|
||||
## Phase 4: Design Validation
|
||||
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| Components defined | Verify component list | At least 1 component |
|
||||
| Task breakdown exists | Verify task list | At least 1 task |
|
||||
| Dependencies mapped | All components have dependencies field | All present (can be empty) |
|
||||
| Integration points | Verify integration section | Key integrations documented |
|
||||
|
||||
1. Run validation checks above
|
||||
2. Write architecture_decisions entry to .msg/meta.json:
|
||||
- design_id, approach, rationale, components, task_count
|
||||
3. Write discoveries to wisdom/decisions.md and wisdom/conventions.md
|
||||
@@ -1,62 +0,0 @@
|
||||
# Analyze Task
|
||||
|
||||
Parse iterative development task -> detect capabilities -> assess pipeline complexity -> design roles.
|
||||
|
||||
**CONSTRAINT**: Text-level analysis only. NO source code reading, NO codebase exploration.
|
||||
|
||||
## Signal Detection
|
||||
|
||||
| Keywords | Capability | Role |
|
||||
|----------|------------|------|
|
||||
| design, architect, restructure, refactor plan | architect | architect |
|
||||
| implement, build, code, fix, develop | developer | developer |
|
||||
| test, verify, validate, coverage | tester | tester |
|
||||
| review, audit, quality, check | reviewer | reviewer |
|
||||
|
||||
## Pipeline Selection
|
||||
|
||||
| Signal | Score |
|
||||
|--------|-------|
|
||||
| Changed files > 10 | +3 |
|
||||
| Changed files 3-10 | +2 |
|
||||
| Structural change (refactor, architect, restructure) | +3 |
|
||||
| Cross-cutting (multiple, across, cross) | +2 |
|
||||
| Simple fix (fix, bug, typo, patch) | -2 |
|
||||
|
||||
| Score | Pipeline |
|
||||
|-------|----------|
|
||||
| >= 5 | multi-sprint |
|
||||
| 2-4 | sprint |
|
||||
| 0-1 | patch |
|
||||
|
||||
## Dependency Graph
|
||||
|
||||
Natural ordering tiers:
|
||||
- Tier 0: architect (design must come first)
|
||||
- Tier 1: developer (implementation requires design)
|
||||
- Tier 2: tester, reviewer (validation requires artifacts, can run parallel)
|
||||
|
||||
## Complexity Assessment
|
||||
|
||||
| Factor | Points |
|
||||
|--------|--------|
|
||||
| Cross-module changes | +2 |
|
||||
| Serial depth > 3 | +1 |
|
||||
| Multiple developers needed | +2 |
|
||||
| GC loop likely needed | +1 |
|
||||
|
||||
## Output
|
||||
|
||||
Write <session>/task-analysis.json:
|
||||
```json
|
||||
{
|
||||
"task_description": "<original>",
|
||||
"pipeline_type": "<patch|sprint|multi-sprint>",
|
||||
"capabilities": [{ "name": "<cap>", "role": "<role>", "keywords": ["..."] }],
|
||||
"roles": [{ "name": "<role>", "prefix": "<PREFIX>", "inner_loop": false }],
|
||||
"complexity": { "score": 0, "level": "Low|Medium|High" },
|
||||
"needs_architecture": true,
|
||||
"needs_testing": true,
|
||||
"needs_review": true
|
||||
}
|
||||
```
|
||||
@@ -1,234 +0,0 @@
|
||||
# Command: Dispatch
|
||||
|
||||
Create the iterative development task chain with correct dependencies and structured task descriptions.
|
||||
|
||||
## Phase 2: Context Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| User requirement | From coordinator Phase 1 | Yes |
|
||||
| Session folder | From coordinator Phase 2 | Yes |
|
||||
| Pipeline definition | From SKILL.md Pipeline Definitions | Yes |
|
||||
| Pipeline mode | From session.json `pipeline` | Yes |
|
||||
|
||||
1. Load user requirement and scope from session.json
|
||||
2. Load pipeline stage definitions from SKILL.md Task Metadata Registry
|
||||
3. Read `pipeline` mode from session.json (patch / sprint / multi-sprint)
|
||||
|
||||
## Phase 3: Task Chain Creation
|
||||
|
||||
### Task Description Template
|
||||
|
||||
Every task description uses structured format for clarity:
|
||||
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "<TASK-ID>",
|
||||
description: "PURPOSE: <what this task achieves> | Success: <measurable completion criteria>
|
||||
TASK:
|
||||
- <step 1: specific action>
|
||||
- <step 2: specific action>
|
||||
- <step 3: specific action>
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <task-scope>
|
||||
- Upstream artifacts: <artifact-1>, <artifact-2>
|
||||
- Shared memory: <session>/.msg/meta.json
|
||||
EXPECTED: <deliverable path> + <quality criteria>
|
||||
CONSTRAINTS: <scope limits, focus areas>
|
||||
---
|
||||
InnerLoop: <true|false>"
|
||||
})
|
||||
TaskUpdate({ taskId: "<TASK-ID>", addBlockedBy: [<dependency-list>], owner: "<role>" })
|
||||
```
|
||||
|
||||
### Mode Router
|
||||
|
||||
| Mode | Action |
|
||||
|------|--------|
|
||||
| `patch` | Create DEV-001 + VERIFY-001 |
|
||||
| `sprint` | Create DESIGN-001 + DEV-001 + VERIFY-001 + REVIEW-001 |
|
||||
| `multi-sprint` | Create Sprint 1 chain, subsequent sprints created dynamically |
|
||||
|
||||
---
|
||||
|
||||
### Patch Pipeline
|
||||
|
||||
**DEV-001** (developer):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "DEV-001",
|
||||
description: "PURPOSE: Implement fix | Success: Fix applied, syntax clean
|
||||
TASK:
|
||||
- Load target files and understand context
|
||||
- Apply fix changes
|
||||
- Validate syntax
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <task-scope>
|
||||
- Shared memory: <session>/.msg/meta.json
|
||||
EXPECTED: Modified source files + <session>/code/dev-log.md | Syntax clean
|
||||
CONSTRAINTS: Minimal changes | Preserve existing behavior
|
||||
---
|
||||
InnerLoop: true"
|
||||
})
|
||||
TaskUpdate({ taskId: "DEV-001", owner: "developer" })
|
||||
```
|
||||
|
||||
**VERIFY-001** (tester):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "VERIFY-001",
|
||||
description: "PURPOSE: Verify fix correctness | Success: Tests pass, no regressions
|
||||
TASK:
|
||||
- Detect test framework
|
||||
- Run targeted tests for changed files
|
||||
- Run regression test suite
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <task-scope>
|
||||
- Upstream artifacts: code/dev-log.md
|
||||
- Shared memory: <session>/.msg/meta.json
|
||||
EXPECTED: <session>/verify/verify-001.json | Pass rate >= 95%
|
||||
CONSTRAINTS: Focus on changed files | Report any regressions
|
||||
---
|
||||
InnerLoop: false"
|
||||
})
|
||||
TaskUpdate({ taskId: "VERIFY-001", addBlockedBy: ["DEV-001"], owner: "tester" })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Sprint Pipeline
|
||||
|
||||
**DESIGN-001** (architect):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "DESIGN-001",
|
||||
description: "PURPOSE: Technical design and task breakdown | Success: Design document + task breakdown ready
|
||||
TASK:
|
||||
- Explore codebase for patterns and dependencies
|
||||
- Create component design with integration points
|
||||
- Break down into implementable tasks with acceptance criteria
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <task-scope>
|
||||
- Shared memory: <session>/.msg/meta.json
|
||||
EXPECTED: <session>/design/design-001.md + <session>/design/task-breakdown.json | Components defined, tasks actionable
|
||||
CONSTRAINTS: Focus on <task-scope> | Risk assessment required
|
||||
---
|
||||
InnerLoop: false"
|
||||
})
|
||||
TaskUpdate({ taskId: "DESIGN-001", owner: "architect" })
|
||||
```
|
||||
|
||||
**DEV-001** (developer):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "DEV-001",
|
||||
description: "PURPOSE: Implement design | Success: All design tasks implemented, syntax clean
|
||||
TASK:
|
||||
- Load design and task breakdown
|
||||
- Implement tasks in execution order
|
||||
- Validate syntax after changes
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <task-scope>
|
||||
- Upstream artifacts: design/design-001.md, design/task-breakdown.json
|
||||
- Shared memory: <session>/.msg/meta.json
|
||||
EXPECTED: Modified source files + <session>/code/dev-log.md | Syntax clean, all tasks done
|
||||
CONSTRAINTS: Follow design | Preserve existing behavior | Follow code conventions
|
||||
---
|
||||
InnerLoop: true"
|
||||
})
|
||||
TaskUpdate({ taskId: "DEV-001", addBlockedBy: ["DESIGN-001"], owner: "developer" })
|
||||
```
|
||||
|
||||
**VERIFY-001** (tester, parallel with REVIEW-001):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "VERIFY-001",
|
||||
description: "PURPOSE: Verify implementation | Success: Tests pass, no regressions
|
||||
TASK:
|
||||
- Detect test framework
|
||||
- Run tests for changed files
|
||||
- Run regression test suite
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <task-scope>
|
||||
- Upstream artifacts: code/dev-log.md
|
||||
- Shared memory: <session>/.msg/meta.json
|
||||
EXPECTED: <session>/verify/verify-001.json | Pass rate >= 95%
|
||||
CONSTRAINTS: Focus on changed files | Report regressions
|
||||
---
|
||||
InnerLoop: false"
|
||||
})
|
||||
TaskUpdate({ taskId: "VERIFY-001", addBlockedBy: ["DEV-001"], owner: "tester" })
|
||||
```
|
||||
|
||||
**REVIEW-001** (reviewer, parallel with VERIFY-001):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "REVIEW-001",
|
||||
description: "PURPOSE: Code review for correctness and quality | Success: All dimensions reviewed, verdict issued
|
||||
TASK:
|
||||
- Load changed files and design document
|
||||
- Review across 4 dimensions: correctness, completeness, maintainability, security
|
||||
- Score quality (1-10) and issue verdict
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <task-scope>
|
||||
- Upstream artifacts: design/design-001.md, code/dev-log.md
|
||||
- Shared memory: <session>/.msg/meta.json
|
||||
EXPECTED: <session>/review/review-001.md | Per-dimension findings with severity
|
||||
CONSTRAINTS: Focus on implementation changes | Provide file:line references
|
||||
---
|
||||
InnerLoop: false"
|
||||
})
|
||||
TaskUpdate({ taskId: "REVIEW-001", addBlockedBy: ["DEV-001"], owner: "reviewer" })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Multi-Sprint Pipeline
|
||||
|
||||
Sprint 1: DESIGN-001 -> DEV-001 -> DEV-002(incremental) -> VERIFY-001 -> DEV-fix -> REVIEW-001
|
||||
|
||||
Create Sprint 1 tasks using sprint templates above, plus:
|
||||
|
||||
**DEV-002** (developer, incremental):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "DEV-002",
|
||||
description: "PURPOSE: Incremental implementation | Success: Remaining tasks implemented
|
||||
TASK:
|
||||
- Load remaining tasks from breakdown
|
||||
- Implement incrementally
|
||||
- Validate syntax
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <task-scope>
|
||||
- Upstream artifacts: design/task-breakdown.json, code/dev-log.md
|
||||
- Shared memory: <session>/.msg/meta.json
|
||||
EXPECTED: Modified source files + updated dev-log.md
|
||||
CONSTRAINTS: Incremental delivery | Follow existing patterns
|
||||
---
|
||||
InnerLoop: true"
|
||||
})
|
||||
TaskUpdate({ taskId: "DEV-002", addBlockedBy: ["DEV-001"], owner: "developer" })
|
||||
```
|
||||
|
||||
Subsequent sprints created dynamically after Sprint N completes.
|
||||
|
||||
## Phase 4: Validation
|
||||
|
||||
Verify task chain integrity:
|
||||
|
||||
| Check | Method | Expected |
|
||||
|-------|--------|----------|
|
||||
| Task count correct | TaskList count | patch: 2, sprint: 4, multi: 5+ |
|
||||
| Dependencies correct | Trace addBlockedBy graph | Acyclic, correct ordering |
|
||||
| No circular dependencies | Trace full graph | Acyclic |
|
||||
| Structured descriptions | Each has PURPOSE/TASK/CONTEXT/EXPECTED | All present |
|
||||
|
||||
If validation fails, fix the specific task and re-validate.
|
||||
@@ -1,182 +0,0 @@
|
||||
# Command: Monitor
|
||||
|
||||
Event-driven pipeline coordination. Beat model: coordinator wake -> process -> spawn -> STOP.
|
||||
|
||||
## Constants
|
||||
|
||||
- SPAWN_MODE: background
|
||||
- ONE_STEP_PER_INVOCATION: true
|
||||
- FAST_ADVANCE_AWARE: true
|
||||
- WORKER_AGENT: team-worker
|
||||
- MAX_GC_ROUNDS: 3
|
||||
|
||||
## Handler Router
|
||||
|
||||
| Source | Handler |
|
||||
|--------|---------|
|
||||
| Message contains [architect], [developer], [tester], [reviewer] | handleCallback |
|
||||
| "capability_gap" | handleAdapt |
|
||||
| "check" or "status" | handleCheck |
|
||||
| "resume" or "continue" | handleResume |
|
||||
| All tasks completed | handleComplete |
|
||||
| Default | handleSpawnNext |
|
||||
|
||||
## Phase 2: Context Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Session state | <session>/session.json | Yes |
|
||||
| Task list | TaskList() | Yes |
|
||||
| Trigger event | From Entry Router detection | Yes |
|
||||
| Meta state | <session>/.msg/meta.json | Yes |
|
||||
| Task ledger | <session>/task-ledger.json | No |
|
||||
|
||||
1. Load session.json for current state, pipeline mode, gc_round, max_gc_rounds
|
||||
2. Run TaskList() to get current task statuses
|
||||
3. Identify trigger event type from Entry Router
|
||||
|
||||
## Phase 3: Event Handlers
|
||||
|
||||
### handleCallback
|
||||
|
||||
Triggered when a worker sends completion message.
|
||||
|
||||
1. Parse message to identify role and task ID:
|
||||
|
||||
| Message Pattern | Role Detection |
|
||||
|----------------|---------------|
|
||||
| `[architect]` or task ID `DESIGN-*` | architect |
|
||||
| `[developer]` or task ID `DEV-*` | developer |
|
||||
| `[tester]` or task ID `VERIFY-*` | tester |
|
||||
| `[reviewer]` or task ID `REVIEW-*` | reviewer |
|
||||
|
||||
2. Mark task as completed:
|
||||
|
||||
```
|
||||
TaskUpdate({ taskId: "<task-id>", status: "completed" })
|
||||
```
|
||||
|
||||
3. Record completion in session state and update task-ledger.json metrics
|
||||
|
||||
4. **Generator-Critic check** (when reviewer completes):
|
||||
- If completed task is REVIEW-* AND pipeline is sprint or multi-sprint:
|
||||
- Read review report for GC signal (critical_count, score)
|
||||
- Read session.json for gc_round
|
||||
|
||||
| GC Signal | gc_round < max | Action |
|
||||
|-----------|----------------|--------|
|
||||
| review.critical_count > 0 OR review.score < 7 | Yes | Increment gc_round, create DEV-fix task blocked by this REVIEW, log `gc_loop_trigger` |
|
||||
| review.critical_count > 0 OR review.score < 7 | No (>= max) | Force convergence, accept with warning, log to wisdom/issues.md |
|
||||
| review.critical_count == 0 AND review.score >= 7 | - | Review passed, proceed to handleComplete check |
|
||||
|
||||
- Log team_msg with type "gc_loop_trigger" or "task_unblocked"
|
||||
|
||||
5. Proceed to handleSpawnNext
|
||||
|
||||
### handleSpawnNext
|
||||
|
||||
Find and spawn the next ready tasks.
|
||||
|
||||
1. Scan task list for tasks where:
|
||||
- Status is "pending"
|
||||
- All blockedBy tasks have status "completed"
|
||||
|
||||
2. For each ready task, determine role from task prefix:
|
||||
|
||||
| Task Prefix | Role | Inner Loop |
|
||||
|-------------|------|------------|
|
||||
| DESIGN-* | architect | false |
|
||||
| DEV-* | developer | true |
|
||||
| VERIFY-* | tester | false |
|
||||
| REVIEW-* | reviewer | false |
|
||||
|
||||
3. Spawn team-worker:
|
||||
|
||||
```
|
||||
Agent({
|
||||
subagent_type: "team-worker",
|
||||
description: "Spawn <role> worker for <task-id>",
|
||||
team_name: "iterdev",
|
||||
name: "<role>",
|
||||
run_in_background: true,
|
||||
prompt: `## Role Assignment
|
||||
role: <role>
|
||||
role_spec: ~ or <project>/.claude/skills/team-iterdev/roles/<role>/role.md
|
||||
session: <session-folder>
|
||||
session_id: <session-id>
|
||||
team_name: iterdev
|
||||
requirement: <task-description>
|
||||
inner_loop: <true|false>
|
||||
|
||||
Read role_spec file to load Phase 2-4 domain instructions.
|
||||
Execute built-in Phase 1 -> role-spec Phase 2-4 -> built-in Phase 5.`
|
||||
})
|
||||
```
|
||||
|
||||
4. **Parallel spawn rules**:
|
||||
|
||||
| Pipeline | Scenario | Spawn Behavior |
|
||||
|----------|----------|---------------|
|
||||
| Patch | DEV -> VERIFY | One worker at a time |
|
||||
| Sprint | VERIFY + REVIEW both unblocked | Spawn BOTH in parallel |
|
||||
| Sprint | Other stages | One worker at a time |
|
||||
| Multi-Sprint | VERIFY + DEV-fix both unblocked | Spawn BOTH in parallel |
|
||||
| Multi-Sprint | Other stages | One worker at a time |
|
||||
|
||||
5. STOP after spawning -- wait for next callback
|
||||
|
||||
### handleCheck
|
||||
|
||||
Output current pipeline status. Do NOT advance pipeline.
|
||||
|
||||
```
|
||||
Pipeline Status (<pipeline-mode>):
|
||||
[DONE] DESIGN-001 (architect) -> design/design-001.md
|
||||
[DONE] DEV-001 (developer) -> code/dev-log.md
|
||||
[RUN] VERIFY-001 (tester) -> verifying...
|
||||
[RUN] REVIEW-001 (reviewer) -> reviewing...
|
||||
[WAIT] DEV-fix (developer) -> blocked by REVIEW-001
|
||||
|
||||
GC Rounds: <gc_round>/<max_gc_rounds>
|
||||
Sprint: <sprint_id>
|
||||
Session: <session-id>
|
||||
```
|
||||
|
||||
### handleResume
|
||||
|
||||
Resume pipeline after user pause or interruption.
|
||||
|
||||
1. Audit task list for inconsistencies:
|
||||
- Tasks stuck in "in_progress" -> reset to "pending"
|
||||
- Tasks with completed blockers but still "pending" -> include in spawn list
|
||||
2. Proceed to handleSpawnNext
|
||||
|
||||
### handleComplete
|
||||
|
||||
Triggered when all pipeline tasks are completed.
|
||||
|
||||
**Completion check by mode**:
|
||||
|
||||
| Mode | Completion Condition |
|
||||
|------|---------------------|
|
||||
| patch | DEV-001 + VERIFY-001 completed |
|
||||
| sprint | DESIGN-001 + DEV-001 + VERIFY-001 + REVIEW-001 (+ any GC tasks) completed |
|
||||
| multi-sprint | All sprint tasks (+ any GC tasks) completed |
|
||||
|
||||
1. Verify all tasks completed via TaskList()
|
||||
2. If any tasks not completed, return to handleSpawnNext
|
||||
3. **Multi-sprint check**: If multi-sprint AND more sprints planned:
|
||||
- Record sprint metrics to .msg/meta.json sprint_history
|
||||
- Evaluate downgrade eligibility (velocity >= expected, review avg >= 8)
|
||||
- Pause for user confirmation before Sprint N+1
|
||||
4. If all completed, transition to coordinator Phase 5 (Report + Completion Action)
|
||||
|
||||
## Phase 4: State Persistence
|
||||
|
||||
After every handler execution:
|
||||
|
||||
1. Update session.json with current state (gc_round, last event, active tasks)
|
||||
2. Update task-ledger.json metrics (completed count, in_progress count, velocity)
|
||||
3. Update .msg/meta.json gc_round if changed
|
||||
4. Verify task list consistency
|
||||
5. STOP and wait for next event
|
||||
@@ -1,153 +0,0 @@
|
||||
# Coordinator Role
|
||||
|
||||
Orchestrate team-iterdev: analyze -> dispatch -> spawn -> monitor -> report.
|
||||
|
||||
## Identity
|
||||
- Name: coordinator | Tag: [coordinator]
|
||||
- Responsibility: Analyze task -> Create team -> Dispatch tasks -> Monitor progress -> Report results
|
||||
|
||||
## Boundaries
|
||||
|
||||
### MUST
|
||||
- Use `team-worker` agent type for all worker spawns (NOT `general-purpose`)
|
||||
- Follow Command Execution Protocol for dispatch and monitor commands
|
||||
- Respect pipeline stage dependencies (blockedBy)
|
||||
- Stop after spawning workers -- wait for callbacks
|
||||
- Handle developer<->reviewer GC loop (max 3 rounds)
|
||||
- Maintain task-ledger.json for real-time progress
|
||||
- Execute completion action in Phase 5
|
||||
|
||||
### MUST NOT
|
||||
- Implement domain logic (designing, coding, testing, reviewing) -- workers handle this
|
||||
- Spawn workers without creating tasks first
|
||||
- Write source code directly
|
||||
- Force-advance pipeline past failed review/validation
|
||||
- Modify task outputs (workers own their deliverables)
|
||||
|
||||
## Command Execution Protocol
|
||||
|
||||
When coordinator needs to execute a command:
|
||||
1. Read `commands/<command>.md`
|
||||
2. Follow the workflow defined in the command
|
||||
3. Commands are inline execution guides, NOT separate agents
|
||||
4. Execute synchronously, complete before proceeding
|
||||
|
||||
## Entry Router
|
||||
|
||||
| Detection | Condition | Handler |
|
||||
|-----------|-----------|---------|
|
||||
| Worker callback | Message contains [architect], [developer], [tester], [reviewer] | -> handleCallback (monitor.md) |
|
||||
| Status check | Args contain "check" or "status" | -> handleCheck (monitor.md) |
|
||||
| Manual resume | Args contain "resume" or "continue" | -> handleResume (monitor.md) |
|
||||
| Pipeline complete | All tasks completed | -> handleComplete (monitor.md) |
|
||||
| Interrupted session | Active/paused session in .workflow/.team/IDS-* | -> Phase 0 |
|
||||
| New session | None of above | -> Phase 1 |
|
||||
|
||||
For callback/check/resume/complete: load @commands/monitor.md, execute handler, STOP.
|
||||
|
||||
## Phase 0: Session Resume Check
|
||||
|
||||
1. Scan `.workflow/.team/IDS-*/.msg/meta.json` for active/paused sessions
|
||||
2. No sessions -> Phase 1
|
||||
3. Single session -> reconcile (audit TaskList, reset in_progress->pending, rebuild team, kick first ready task)
|
||||
4. Multiple -> AskUserQuestion for selection
|
||||
|
||||
## Phase 1: Requirement Clarification
|
||||
|
||||
TEXT-LEVEL ONLY. No source code reading.
|
||||
|
||||
1. Parse user task description from $ARGUMENTS
|
||||
2. Delegate to @commands/analyze.md
|
||||
3. Assess complexity for pipeline selection:
|
||||
|
||||
| Signal | Weight |
|
||||
|--------|--------|
|
||||
| Changed files > 10 | +3 |
|
||||
| Changed files 3-10 | +2 |
|
||||
| Structural change (refactor, architect, restructure) | +3 |
|
||||
| Cross-cutting (multiple, across, cross) | +2 |
|
||||
| Simple fix (fix, bug, typo, patch) | -2 |
|
||||
|
||||
| Score | Pipeline |
|
||||
|-------|----------|
|
||||
| >= 5 | multi-sprint |
|
||||
| 2-4 | sprint |
|
||||
| 0-1 | patch |
|
||||
|
||||
4. Ask for missing parameters via AskUserQuestion (mode selection)
|
||||
5. Record requirement with scope, pipeline mode
|
||||
6. CRITICAL: Always proceed to Phase 2, never skip team workflow
|
||||
|
||||
## Phase 2: Session & Team Setup
|
||||
|
||||
1. Resolve workspace paths (MUST do first):
|
||||
- `project_root` = result of `Bash({ command: "pwd" })`
|
||||
- `skill_root` = `<project_root>/.claude/skills/team-iterdev`
|
||||
2. Generate session ID: `IDS-<slug>-<YYYY-MM-DD>`
|
||||
3. Create session folder structure:
|
||||
```
|
||||
mkdir -p .workflow/.team/<session-id>/{design,code,verify,review,wisdom}
|
||||
```
|
||||
4. Create team: `TeamCreate({ team_name: "iterdev" })`
|
||||
5. Read specs/pipelines.md -> select pipeline based on complexity
|
||||
6. Initialize wisdom directory (learnings.md, decisions.md, conventions.md, issues.md)
|
||||
7. Write session.json
|
||||
8. Initialize task-ledger.json
|
||||
9. Initialize meta.json with pipeline metadata:
|
||||
```typescript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", session_id: "<id>", from: "coordinator",
|
||||
type: "state_update", summary: "Session initialized",
|
||||
data: {
|
||||
pipeline_mode: "<patch|sprint|multi-sprint>",
|
||||
pipeline_stages: ["architect", "developer", "tester", "reviewer"],
|
||||
roles: ["coordinator", "architect", "developer", "tester", "reviewer"],
|
||||
team_name: "iterdev"
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Phase 3: Task Chain Creation
|
||||
|
||||
Delegate to @commands/dispatch.md:
|
||||
1. Read specs/pipelines.md for selected pipeline task registry
|
||||
2. Create tasks via TaskCreate, then TaskUpdate with addBlockedBy
|
||||
3. Update task-ledger.json
|
||||
|
||||
## Phase 4: Spawn-and-Stop
|
||||
|
||||
Delegate to @commands/monitor.md#handleSpawnNext:
|
||||
1. Find ready tasks (pending + all addBlockedBy dependencies resolved)
|
||||
2. Spawn team-worker agents (see SKILL.md Spawn Template)
|
||||
3. Output status summary
|
||||
4. STOP
|
||||
|
||||
## Phase 5: Report + Completion Action
|
||||
|
||||
1. Load session state -> count completed tasks, calculate duration
|
||||
2. Record sprint learning to .msg/meta.json sprint_history
|
||||
3. List deliverables:
|
||||
|
||||
| Deliverable | Path |
|
||||
|-------------|------|
|
||||
| Design Document | <session>/design/design-001.md |
|
||||
| Task Breakdown | <session>/design/task-breakdown.json |
|
||||
| Dev Log | <session>/code/dev-log.md |
|
||||
| Verification Results | <session>/verify/verify-001.json |
|
||||
| Review Report | <session>/review/review-001.md |
|
||||
|
||||
4. Execute completion action per session.completion_action:
|
||||
- interactive -> AskUserQuestion (Archive/Keep/Export)
|
||||
- auto_archive -> Archive & Clean (status=completed, TeamDelete)
|
||||
- auto_keep -> Keep Active (status=paused)
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Task too vague | AskUserQuestion for clarification |
|
||||
| Session corruption | Attempt recovery, fallback to manual |
|
||||
| Worker crash | Reset task to pending, respawn |
|
||||
| GC loop exceeds 3 rounds | Accept with warning, record in shared memory |
|
||||
| Sprint velocity drops below 50% | Alert user, suggest scope reduction |
|
||||
| Task ledger corrupted | Rebuild from TaskList state |
|
||||
@@ -1,74 +0,0 @@
|
||||
---
|
||||
role: developer
|
||||
prefix: DEV
|
||||
inner_loop: true
|
||||
message_types:
|
||||
success: dev_complete
|
||||
progress: dev_progress
|
||||
error: error
|
||||
---
|
||||
|
||||
# Developer
|
||||
|
||||
Code implementer. Implements code according to design, incremental delivery. Acts as Generator in Generator-Critic loop (paired with reviewer).
|
||||
|
||||
## Phase 2: Context Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Task description | From task subject/description | Yes |
|
||||
| Session path | Extracted from task description | Yes |
|
||||
| .msg/meta.json | <session>/.msg/meta.json | Yes |
|
||||
| Design document | <session>/design/design-001.md | For non-fix tasks |
|
||||
| Task breakdown | <session>/design/task-breakdown.json | For non-fix tasks |
|
||||
| Review feedback | <session>/review/*.md | For fix tasks |
|
||||
| Wisdom files | <session>/wisdom/ | No |
|
||||
|
||||
1. Extract session path from task description
|
||||
2. Read .msg/meta.json for shared context
|
||||
3. Detect task type:
|
||||
|
||||
| Task Type | Detection | Loading |
|
||||
|-----------|-----------|---------|
|
||||
| Fix task | Subject contains "fix" | Read latest review file for feedback |
|
||||
| Normal task | No "fix" in subject | Read design document + task breakdown |
|
||||
|
||||
4. Load previous implementation_context from .msg/meta.json
|
||||
5. Read wisdom files for conventions and known issues
|
||||
|
||||
## Phase 3: Code Implementation
|
||||
|
||||
**Implementation strategy selection**:
|
||||
|
||||
| Task Count | Complexity | Strategy |
|
||||
|------------|------------|----------|
|
||||
| <= 2 tasks | Low | Direct: inline Edit/Write |
|
||||
| 3-5 tasks | Medium | Single agent: one code-developer for all |
|
||||
| > 5 tasks | High | Batch agent: group by module, one agent per batch |
|
||||
|
||||
**Fix Task Mode** (GC Loop):
|
||||
- Focus on review feedback items only
|
||||
- Fix critical issues first, then high, then medium
|
||||
- Do NOT change code that was not flagged
|
||||
- Maintain existing code style and patterns
|
||||
|
||||
**Normal Task Mode**:
|
||||
- Read target files, apply changes using Edit or Write
|
||||
- Follow execution order from task breakdown
|
||||
- Validate syntax after each major change
|
||||
|
||||
## Phase 4: Self-Validation
|
||||
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| Syntax | tsc --noEmit or equivalent | No errors |
|
||||
| File existence | Verify all planned files exist | All files present |
|
||||
| Import resolution | Check no broken imports | All imports resolve |
|
||||
|
||||
1. Run syntax check: `tsc --noEmit` / `python -m py_compile` / equivalent
|
||||
2. Auto-fix if validation fails (max 2 attempts)
|
||||
3. Write dev log to `<session>/code/dev-log.md`:
|
||||
- Changed files count, syntax status, fix task flag, file list
|
||||
4. Update implementation_context in .msg/meta.json:
|
||||
- task, changed_files, is_fix, syntax_clean
|
||||
5. Write discoveries to wisdom/learnings.md
|
||||
@@ -1,66 +0,0 @@
|
||||
---
|
||||
role: reviewer
|
||||
prefix: REVIEW
|
||||
inner_loop: false
|
||||
message_types:
|
||||
success: review_passed
|
||||
revision: review_revision
|
||||
critical: review_critical
|
||||
error: error
|
||||
---
|
||||
|
||||
# Reviewer
|
||||
|
||||
Code reviewer. Multi-dimensional review, quality scoring, improvement suggestions. Acts as Critic in Generator-Critic loop (paired with developer).
|
||||
|
||||
## Phase 2: Context Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Task description | From task subject/description | Yes |
|
||||
| Session path | Extracted from task description | Yes |
|
||||
| .msg/meta.json | <session>/.msg/meta.json | Yes |
|
||||
| Design document | <session>/design/design-001.md | For requirements alignment |
|
||||
| Changed files | Git diff | Yes |
|
||||
|
||||
1. Extract session path from task description
|
||||
2. Read .msg/meta.json for shared context and previous review_feedback_trends
|
||||
3. Read design document for requirements alignment
|
||||
4. Get changed files via git diff, read file contents (limit 20 files)
|
||||
|
||||
## Phase 3: Multi-Dimensional Review
|
||||
|
||||
**Review dimensions**:
|
||||
|
||||
| Dimension | Weight | Focus Areas |
|
||||
|-----------|--------|-------------|
|
||||
| Correctness | 30% | Logic correctness, boundary handling |
|
||||
| Completeness | 25% | Coverage of design requirements |
|
||||
| Maintainability | 25% | Readability, code style, DRY |
|
||||
| Security | 20% | Vulnerabilities, input validation |
|
||||
|
||||
Per-dimension: scan modified files, record findings with severity (CRITICAL/HIGH/MEDIUM/LOW), include file:line references and suggestions.
|
||||
|
||||
**Scoring**: Weighted average of dimension scores (1-10 each).
|
||||
|
||||
**Output review report** (`<session>/review/review-<num>.md`):
|
||||
- Files reviewed count, quality score, issue counts by severity
|
||||
- Per-finding: severity, file:line, dimension, description, suggestion
|
||||
- Scoring breakdown by dimension
|
||||
- Signal: CRITICAL / REVISION_NEEDED / APPROVED
|
||||
- Design alignment notes
|
||||
|
||||
## Phase 4: Trend Analysis + Verdict
|
||||
|
||||
1. Compare with previous review_feedback_trends from .msg/meta.json
|
||||
2. Identify recurring issues, improvement areas, new issues
|
||||
|
||||
| Verdict Condition | Message Type |
|
||||
|-------------------|--------------|
|
||||
| criticalCount > 0 | review_critical |
|
||||
| score < 7 | review_revision |
|
||||
| else | review_passed |
|
||||
|
||||
3. Update review_feedback_trends in .msg/meta.json:
|
||||
- review_id, score, critical count, high count, dimensions, gc_round
|
||||
4. Write discoveries to wisdom/learnings.md
|
||||
@@ -1,88 +0,0 @@
|
||||
---
|
||||
role: tester
|
||||
prefix: VERIFY
|
||||
inner_loop: false
|
||||
message_types:
|
||||
success: verify_passed
|
||||
failure: verify_failed
|
||||
fix: fix_required
|
||||
error: error
|
||||
---
|
||||
|
||||
# Tester
|
||||
|
||||
Test validator. Test execution, fix cycles, and regression detection.
|
||||
|
||||
## Phase 2: Environment Detection
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Task description | From task subject/description | Yes |
|
||||
| Session path | Extracted from task description | Yes |
|
||||
| .msg/meta.json | <session>/.msg/meta.json | Yes |
|
||||
| Changed files | Git diff | Yes |
|
||||
|
||||
1. Extract session path from task description
|
||||
2. Read .msg/meta.json for shared context
|
||||
3. Get changed files via git diff
|
||||
4. Detect test framework and command:
|
||||
|
||||
| Detection | Method |
|
||||
|-----------|--------|
|
||||
| Test command | Check package.json scripts, pytest.ini, Makefile |
|
||||
| Coverage tool | Check for nyc, coverage.py, jest --coverage config |
|
||||
|
||||
Common commands: npm test, pytest, go test ./..., cargo test
|
||||
|
||||
## Phase 3: Execution + Fix Cycle
|
||||
|
||||
**Iterative test-fix cycle** (max 5 iterations):
|
||||
|
||||
| Step | Action |
|
||||
|------|--------|
|
||||
| 1 | Run test command |
|
||||
| 2 | Parse results, check pass rate |
|
||||
| 3 | Pass rate >= 95% -> exit loop (success) |
|
||||
| 4 | Extract failing test details |
|
||||
| 5 | Apply fix using CLI tool |
|
||||
| 6 | Increment iteration counter |
|
||||
| 7 | iteration >= MAX (5) -> exit loop (report failures) |
|
||||
| 8 | Go to Step 1 |
|
||||
|
||||
**Fix delegation**: Use CLI tool to fix failing tests:
|
||||
|
||||
```bash
|
||||
ccw cli -p "PURPOSE: Fix failing tests; success = all listed tests pass
|
||||
TASK: • Analyze test failure output • Identify root cause in changed files • Apply minimal fix
|
||||
MODE: write
|
||||
CONTEXT: @<changed-files> | Memory: Test output from current iteration
|
||||
EXPECTED: Code fixes that make failing tests pass without breaking other tests
|
||||
CONSTRAINTS: Only modify files in changed list | Minimal changes
|
||||
Test output: <test-failure-details>
|
||||
Changed files: <file-list>" --tool gemini --mode write --rule development-debug-runtime-issues
|
||||
```
|
||||
|
||||
Wait for CLI completion before re-running tests.
|
||||
|
||||
## Phase 4: Regression Check + Report
|
||||
|
||||
1. Run full test suite for regression: `<test-command> --all`
|
||||
|
||||
| Check | Method | Pass Criteria |
|
||||
|-------|--------|---------------|
|
||||
| Regression | Run full test suite | No FAIL in output |
|
||||
| Coverage | Run coverage tool | >= 80% (if configured) |
|
||||
|
||||
2. Write verification results to `<session>/verify/verify-<num>.json`:
|
||||
- verify_id, pass_rate, iterations, passed, timestamp, regression_passed
|
||||
|
||||
3. Determine message type:
|
||||
|
||||
| Condition | Message Type |
|
||||
|-----------|--------------|
|
||||
| passRate >= 0.95 | verify_passed |
|
||||
| passRate < 0.95 && iterations >= MAX | fix_required |
|
||||
| passRate < 0.95 | verify_failed |
|
||||
|
||||
4. Update .msg/meta.json with test_patterns entry
|
||||
5. Write discoveries to wisdom/issues.md
|
||||
@@ -1,94 +0,0 @@
|
||||
# IterDev Pipeline Definitions
|
||||
|
||||
## Three-Pipeline Architecture
|
||||
|
||||
### Patch Pipeline (2 beats, serial)
|
||||
|
||||
```
|
||||
DEV-001 -> VERIFY-001
|
||||
[developer] [tester]
|
||||
```
|
||||
|
||||
### Sprint Pipeline (4 beats, with parallel window)
|
||||
|
||||
```
|
||||
DESIGN-001 -> DEV-001 -> [VERIFY-001 + REVIEW-001] (parallel)
|
||||
[architect] [developer] [tester] [reviewer]
|
||||
```
|
||||
|
||||
### Multi-Sprint Pipeline (N beats, iterative)
|
||||
|
||||
```
|
||||
Sprint 1: DESIGN-001 -> DEV-001 -> DEV-002(incremental) -> VERIFY-001 -> DEV-fix -> REVIEW-001
|
||||
Sprint 2: DESIGN-002(refined) -> DEV-003 -> VERIFY-002 -> REVIEW-002
|
||||
...
|
||||
```
|
||||
|
||||
## Generator-Critic Loop (developer <-> reviewer)
|
||||
|
||||
```
|
||||
DEV -> REVIEW -> (if review.critical_count > 0 || review.score < 7)
|
||||
-> DEV-fix -> REVIEW-2 -> (if still issues) -> DEV-fix-2 -> REVIEW-3
|
||||
-> (max 3 rounds, then accept with warning)
|
||||
```
|
||||
|
||||
## Pipeline Selection Logic
|
||||
|
||||
| Signal | Score |
|
||||
|--------|-------|
|
||||
| Changed files > 10 | +3 |
|
||||
| Changed files 3-10 | +2 |
|
||||
| Structural change | +3 |
|
||||
| Cross-cutting concern | +2 |
|
||||
| Simple fix | -2 |
|
||||
|
||||
| Score | Pipeline |
|
||||
|-------|----------|
|
||||
| >= 5 | multi-sprint |
|
||||
| 2-4 | sprint |
|
||||
| 0-1 | patch |
|
||||
|
||||
## Task Metadata Registry
|
||||
|
||||
| Task ID | Role | Pipeline | Dependencies | Description |
|
||||
|---------|------|----------|-------------|-------------|
|
||||
| DESIGN-001 | architect | sprint/multi | (none) | Technical design and task breakdown |
|
||||
| DEV-001 | developer | all | DESIGN-001 (sprint/multi) or (none for patch) | Code implementation |
|
||||
| DEV-002 | developer | multi | DEV-001 | Incremental implementation |
|
||||
| DEV-fix | developer | sprint/multi | REVIEW-* (GC loop trigger) | Fix issues from review |
|
||||
| VERIFY-001 | tester | all | DEV-001 (or last DEV) | Test execution and fix cycles |
|
||||
| REVIEW-001 | reviewer | sprint/multi | DEV-001 (or last DEV) | Code review and quality scoring |
|
||||
|
||||
## Checkpoints
|
||||
|
||||
| Trigger Condition | Location | Behavior |
|
||||
|-------------------|----------|----------|
|
||||
| GC loop exceeds max rounds | After REVIEW-3 | Stop iteration, accept with warning, record in wisdom |
|
||||
| Sprint transition | End of Sprint N | Pause, retrospective, user confirms `resume` for Sprint N+1 |
|
||||
| Pipeline stall | No ready + no running tasks | Check missing tasks, report blockedBy chain to user |
|
||||
|
||||
## Multi-Sprint Dynamic Downgrade
|
||||
|
||||
If Sprint N metrics are strong (velocity >= expected, review avg >= 8), coordinator may downgrade Sprint N+1 from multi-sprint to sprint pipeline for efficiency.
|
||||
|
||||
## Task Ledger Schema
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `sprint_id` | Current sprint identifier |
|
||||
| `sprint_goal` | Sprint objective |
|
||||
| `tasks[]` | Array of task entries |
|
||||
| `metrics` | Aggregated metrics: total, completed, in_progress, blocked, velocity |
|
||||
|
||||
**Task Entry Fields**:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `id` | Task identifier |
|
||||
| `title` | Task title |
|
||||
| `owner` | Assigned role |
|
||||
| `status` | pending / in_progress / completed / blocked |
|
||||
| `started_at` / `completed_at` | Timestamps |
|
||||
| `gc_rounds` | Generator-Critic iteration count |
|
||||
| `review_score` | Reviewer score (null until reviewed) |
|
||||
| `test_pass_rate` | Tester pass rate (null until tested) |
|
||||
@@ -1,172 +0,0 @@
|
||||
{
|
||||
"team_name": "team-iterdev",
|
||||
"team_display_name": "Team IterDev",
|
||||
"description": "Iterative development team with Generator-Critic loop, task ledger, sprint learning, dynamic pipeline, conflict handling, concurrency control, rollback strategy, user feedback loop, and tech debt tracking",
|
||||
"version": "1.2.0",
|
||||
|
||||
"roles": {
|
||||
"coordinator": {
|
||||
"task_prefix": null,
|
||||
"responsibility": "Sprint planning, backlog management, task ledger maintenance, GC loop control, Phase 1: conflict handling, concurrency control, rollback strategy, Phase 3: user feedback loop, tech debt tracking",
|
||||
"message_types": [
|
||||
"sprint_started", "gc_loop_trigger", "sprint_complete", "task_unblocked", "error", "shutdown",
|
||||
"conflict_detected", "conflict_resolved", "resource_locked", "resource_unlocked", "resource_contention",
|
||||
"rollback_initiated", "rollback_completed", "rollback_failed",
|
||||
"user_feedback_received", "tech_debt_identified"
|
||||
]
|
||||
},
|
||||
"architect": {
|
||||
"task_prefix": "DESIGN",
|
||||
"responsibility": "Technical design, task decomposition, architecture decisions",
|
||||
"message_types": ["design_ready", "design_revision", "error"]
|
||||
},
|
||||
"developer": {
|
||||
"task_prefix": "DEV",
|
||||
"responsibility": "Code implementation, incremental delivery",
|
||||
"message_types": ["dev_complete", "dev_progress", "error"]
|
||||
},
|
||||
"tester": {
|
||||
"task_prefix": "VERIFY",
|
||||
"responsibility": "Test execution, fix cycle, regression detection",
|
||||
"message_types": ["verify_passed", "verify_failed", "fix_required", "error"]
|
||||
},
|
||||
"reviewer": {
|
||||
"task_prefix": "REVIEW",
|
||||
"responsibility": "Code review, quality scoring, improvement suggestions",
|
||||
"message_types": ["review_passed", "review_revision", "review_critical", "error"]
|
||||
}
|
||||
},
|
||||
|
||||
"pipelines": {
|
||||
"patch": {
|
||||
"description": "Simple fix: implement → verify",
|
||||
"task_chain": ["DEV-001", "VERIFY-001"],
|
||||
"gc_loops": 0
|
||||
},
|
||||
"sprint": {
|
||||
"description": "Standard feature: design → implement → verify + review (parallel)",
|
||||
"task_chain": ["DESIGN-001", "DEV-001", "VERIFY-001", "REVIEW-001"],
|
||||
"gc_loops": 3,
|
||||
"parallel_groups": [["VERIFY-001", "REVIEW-001"]]
|
||||
},
|
||||
"multi-sprint": {
|
||||
"description": "Large feature: multiple sprint cycles with incremental delivery",
|
||||
"task_chain": "dynamic — coordinator creates per-sprint chains",
|
||||
"gc_loops": 3,
|
||||
"sprint_count": "dynamic"
|
||||
}
|
||||
},
|
||||
|
||||
"innovation_patterns": {
|
||||
"generator_critic": {
|
||||
"generator": "developer",
|
||||
"critic": "reviewer",
|
||||
"max_rounds": 3,
|
||||
"convergence_trigger": "review.critical_count === 0 && review.score >= 7"
|
||||
},
|
||||
"task_ledger": {
|
||||
"file": "task-ledger.json",
|
||||
"updated_by": "coordinator",
|
||||
"tracks": ["status", "gc_rounds", "review_score", "test_pass_rate", "velocity"],
|
||||
"phase1_extensions": {
|
||||
"conflict_info": {
|
||||
"fields": ["status", "conflicting_files", "resolution_strategy", "resolved_by_task_id"],
|
||||
"default": { "status": "none", "conflicting_files": [], "resolution_strategy": null, "resolved_by_task_id": null }
|
||||
},
|
||||
"rollback_info": {
|
||||
"fields": ["snapshot_id", "rollback_procedure", "last_successful_state_id"],
|
||||
"default": { "snapshot_id": null, "rollback_procedure": null, "last_successful_state_id": null }
|
||||
}
|
||||
}
|
||||
},
|
||||
"shared_memory": {
|
||||
"file": "shared-memory.json",
|
||||
"fields": {
|
||||
"architect": "architecture_decisions",
|
||||
"developer": "implementation_context",
|
||||
"tester": "test_patterns",
|
||||
"reviewer": "review_feedback_trends"
|
||||
},
|
||||
"persistent_fields": ["sprint_history", "what_worked", "what_failed", "patterns_learned"],
|
||||
"phase1_extensions": {
|
||||
"resource_locks": {
|
||||
"description": "Concurrency control: resource locking state",
|
||||
"lock_timeout_ms": 300000,
|
||||
"deadlock_detection": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"dynamic_pipeline": {
|
||||
"selector": "coordinator",
|
||||
"criteria": "file_count + module_count + complexity_assessment",
|
||||
"downgrade_rule": "velocity >= expected && review_avg >= 8 → simplify next sprint"
|
||||
}
|
||||
},
|
||||
|
||||
"phase1_features": {
|
||||
"conflict_handling": {
|
||||
"enabled": true,
|
||||
"detection_strategy": "file_overlap",
|
||||
"resolution_strategies": ["manual", "auto_merge", "abort"]
|
||||
},
|
||||
"concurrency_control": {
|
||||
"enabled": true,
|
||||
"lock_timeout_minutes": 5,
|
||||
"deadlock_detection": true,
|
||||
"resources": ["task-ledger.json", "shared-memory.json"]
|
||||
},
|
||||
"rollback_strategy": {
|
||||
"enabled": true,
|
||||
"snapshot_trigger": "task_complete",
|
||||
"default_procedure": "git revert HEAD"
|
||||
}
|
||||
},
|
||||
|
||||
"phase2_features": {
|
||||
"external_dependency_management": {
|
||||
"enabled": true,
|
||||
"validation_trigger": "task_start",
|
||||
"supported_sources": ["npm", "maven", "pip", "git"],
|
||||
"version_check_command": {
|
||||
"npm": "npm list {name}",
|
||||
"pip": "pip show {name}",
|
||||
"maven": "mvn dependency:tree"
|
||||
}
|
||||
},
|
||||
"state_recovery": {
|
||||
"enabled": true,
|
||||
"checkpoint_trigger": "phase_complete",
|
||||
"max_checkpoints_per_task": 5,
|
||||
"checkpoint_dir": "checkpoints/"
|
||||
}
|
||||
},
|
||||
|
||||
"phase3_features": {
|
||||
"user_feedback_loop": {
|
||||
"enabled": true,
|
||||
"collection_trigger": "sprint_complete",
|
||||
"max_feedback_items": 50,
|
||||
"severity_levels": ["low", "medium", "high", "critical"],
|
||||
"status_flow": ["new", "reviewed", "addressed", "closed"]
|
||||
},
|
||||
"tech_debt_tracking": {
|
||||
"enabled": true,
|
||||
"detection_sources": ["review", "test", "architect"],
|
||||
"categories": ["code", "design", "test", "documentation"],
|
||||
"severity_levels": ["low", "medium", "high", "critical"],
|
||||
"status_flow": ["open", "in_progress", "resolved", "deferred"],
|
||||
"report_trigger": "sprint_retrospective"
|
||||
}
|
||||
},
|
||||
|
||||
"collaboration_patterns": ["CP-1", "CP-3", "CP-5", "CP-6"],
|
||||
|
||||
"session_dirs": {
|
||||
"base": ".workflow/.team/IDS-{slug}-{YYYY-MM-DD}/",
|
||||
"design": "design/",
|
||||
"code": "code/",
|
||||
"verify": "verify/",
|
||||
"review": "review/",
|
||||
"messages": ".workflow/.team-msg/{team-name}/"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: team-lifecycle-v4
|
||||
description: Full lifecycle team skill with clean architecture. SKILL.md is a universal router — all roles read it. Beat model is coordinator-only. Structure is roles/ + specs/ + templates/. Triggers on "team lifecycle v4".
|
||||
description: Full lifecycle team skill — plan, develop, test, review in one coordinated session. Role-based architecture with coordinator-driven beat model. Triggers on "team lifecycle v4".
|
||||
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Agent(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
|
||||
---
|
||||
|
||||
@@ -40,7 +40,7 @@ Skill(skill="team-lifecycle-v4", args="task description")
|
||||
| analyst | [roles/analyst/role.md](roles/analyst/role.md) | RESEARCH-* | false |
|
||||
| writer | [roles/writer/role.md](roles/writer/role.md) | DRAFT-* | true |
|
||||
| planner | [roles/planner/role.md](roles/planner/role.md) | PLAN-* | true |
|
||||
| executor | [roles/executor/role.md](roles/executor/role.md) | IMPL-* | true |
|
||||
| executor | [roles/executor/role.md](roles/executor/role.md) | IMPL-* | dynamic |
|
||||
| tester | [roles/tester/role.md](roles/tester/role.md) | TEST-* | false |
|
||||
| reviewer | [roles/reviewer/role.md](roles/reviewer/role.md) | REVIEW-*, QUALITY-*, IMPROVE-* | false |
|
||||
| supervisor | [roles/supervisor/role.md](roles/supervisor/role.md) | CHECKPOINT-* | false |
|
||||
|
||||
@@ -34,8 +34,20 @@ RoleSpec: ~ or <project>/.claude/skills/team-lifecycle-v4/roles/<role>/role.md
|
||||
|
||||
## InnerLoop Flag Rules
|
||||
|
||||
- true: Role has 2+ serial same-prefix tasks (writer: DRAFT-001->004)
|
||||
- false: Role has 1 task, or tasks are parallel
|
||||
- true: Role has 2+ serial same-prefix tasks (writer: DRAFT-001->004) where each blockedBy the previous
|
||||
- false: Role has 1 task, or tasks are parallel (no mutual blockedBy)
|
||||
|
||||
### Parallel Detection for IMPL Tasks
|
||||
|
||||
When creating IMPL-{1..N} tasks from PLAN-001 output:
|
||||
|
||||
1. Read plan.json → extract `tasks[]` with their `depends_on` fields
|
||||
2. Build dependency graph among IMPL tasks only
|
||||
3. Classify:
|
||||
- **Serial chain**: IMPL-002 blockedBy IMPL-001 → both get `InnerLoop: true`, single worker
|
||||
- **Parallel set**: IMPL-001..N all blockedBy PLAN-001 only (no mutual deps) → each gets `InnerLoop: false`, separate workers
|
||||
- **Mixed DAG**: Some parallel, some serial → group into independent chains, each chain gets one worker with `InnerLoop: true`; independent chains spawn in parallel
|
||||
4. Set `InnerLoop` in each task description accordingly
|
||||
|
||||
## CHECKPOINT Task Rules
|
||||
|
||||
|
||||
@@ -36,9 +36,29 @@ Worker completed. Process and advance.
|
||||
- CHECKPOINT-* with verdict "warn" -> log risks to wisdom, proceed normally
|
||||
- CHECKPOINT-* with verdict "pass" -> proceed normally
|
||||
- QUALITY-001 -> display quality gate, pause for user commands
|
||||
- PLAN-001 -> read plan.json complexity, create dynamic IMPL tasks per specs/pipelines.md routing
|
||||
- PLAN-001 -> dynamicImplDispatch (see below)
|
||||
6. -> handleSpawnNext
|
||||
|
||||
### dynamicImplDispatch (PLAN-001 callback)
|
||||
|
||||
When PLAN-001 completes, coordinator creates IMPL tasks based on complexity:
|
||||
|
||||
1. Read `<session>/plan/plan.json` → extract `complexity`, `tasks[]`
|
||||
2. Route by complexity (per specs/pipelines.md §6):
|
||||
|
||||
| Complexity | Action |
|
||||
|------------|--------|
|
||||
| Low (1-2 modules) | Create single IMPL-001, blockedBy: [PLAN-001], InnerLoop: true |
|
||||
| Medium (3-4 modules) | Create IMPL-{1..N}, each blockedBy: [PLAN-001] only, InnerLoop: false |
|
||||
| High (5+ modules) | Create IMPL-{1..N} with DAG deps from plan.json, InnerLoop per dispatch rules |
|
||||
|
||||
3. For each IMPL task: TaskCreate with structured description (dispatch.md template)
|
||||
4. Set blockedBy:
|
||||
- **Parallel tasks**: blockedBy: [PLAN-001] (or [CHECKPOINT-003] if supervision enabled)
|
||||
- **Serial chain within DAG**: blockedBy includes upstream IMPL task IDs
|
||||
5. Update team-session.json: `pipeline.tasks_total`, `pipeline.impl_topology: "single"|"parallel"|"dag"`
|
||||
6. Log via team_msg: `{ type: "state_update", data: { impl_count: N, topology: "..." } }`
|
||||
|
||||
## handleCheck
|
||||
|
||||
Read-only status report, then STOP.
|
||||
@@ -71,7 +91,9 @@ Find ready tasks, spawn workers, STOP.
|
||||
2. No ready + work in progress -> report waiting, STOP
|
||||
3. No ready + nothing in progress -> handleComplete
|
||||
4. Has ready -> for each:
|
||||
a. Check if inner loop role with active worker -> skip (worker picks up)
|
||||
a. Check inner_loop: parse task description `InnerLoop:` field (NOT role.md default)
|
||||
- InnerLoop: true AND same-role worker already active -> skip (worker picks up next task)
|
||||
- InnerLoop: false OR no active same-role worker -> spawn new worker
|
||||
b. **CHECKPOINT-* task** -> wake resident supervisor (see below)
|
||||
c. Other tasks -> standard spawn:
|
||||
- TaskUpdate -> in_progress
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
role: executor
|
||||
prefix: IMPL
|
||||
inner_loop: true
|
||||
inner_loop: dynamic
|
||||
message_types:
|
||||
success: impl_complete
|
||||
progress: impl_progress
|
||||
@@ -12,6 +12,8 @@ message_types:
|
||||
|
||||
Code implementation worker with dual execution modes.
|
||||
|
||||
> **inner_loop: dynamic** — Dispatch sets per-task: `true` for serial IMPL chains (IMPL-001→002→003 with inter-dependencies), `false` for parallel IMPL sets (independent modules). When false, each IMPL task gets its own worker.
|
||||
|
||||
## Identity
|
||||
- Tag: [executor] | Prefix: IMPL-*
|
||||
- Responsibility: Implement code from plan tasks via agent or CLI delegation
|
||||
|
||||
129
.claude/skills/team-motion-design/SKILL.md
Normal file
129
.claude/skills/team-motion-design/SKILL.md
Normal file
@@ -0,0 +1,129 @@
|
||||
---
|
||||
name: team-motion-design
|
||||
description: Unified team skill for motion design. Animation token systems, scroll choreography, GPU-accelerated transforms, reduced-motion fallback. Uses team-worker agent architecture. Triggers on "team motion design", "animation system".
|
||||
allowed-tools: Agent, AskUserQuestion, Read, Write, Edit, Bash, Glob, Grep, TaskList, TaskGet, TaskUpdate, TaskCreate, TeamCreate, TeamDelete, SendMessage, mcp__ccw-tools__read_file, mcp__ccw-tools__write_file, mcp__ccw-tools__edit_file, mcp__ccw-tools__team_msg, mcp__chrome-devtools__performance_start_trace, mcp__chrome-devtools__performance_stop_trace, mcp__chrome-devtools__performance_analyze_insight, mcp__chrome-devtools__evaluate_script, mcp__chrome-devtools__take_screenshot
|
||||
---
|
||||
|
||||
# Team Motion Design
|
||||
|
||||
Systematic motion design pipeline: research -> choreography -> animation -> performance testing. Built on **team-worker agent architecture** -- all worker roles share a single agent definition with role-specific Phase 2-4 loaded from `roles/<role>/role.md`.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Skill(skill="team-motion-design", args="task description")
|
||||
|
|
||||
SKILL.md (this file) = Router
|
||||
|
|
||||
+--------------+--------------+
|
||||
| |
|
||||
no --role flag --role <name>
|
||||
| |
|
||||
Coordinator Worker
|
||||
roles/coordinator/role.md roles/<name>/role.md
|
||||
|
|
||||
+-- analyze -> dispatch -> spawn workers -> STOP
|
||||
|
|
||||
+-------+-------+-------+-------+
|
||||
v v v v
|
||||
[team-worker agents, each loads roles/<role>/role.md]
|
||||
motion-researcher choreographer animator motion-tester
|
||||
```
|
||||
|
||||
## Role Registry
|
||||
|
||||
| Role | Path | Prefix | Inner Loop |
|
||||
|------|------|--------|------------|
|
||||
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | -- | -- |
|
||||
| motion-researcher | [roles/motion-researcher/role.md](roles/motion-researcher/role.md) | MRESEARCH-* | false |
|
||||
| choreographer | [roles/choreographer/role.md](roles/choreographer/role.md) | CHOREO-* | false |
|
||||
| animator | [roles/animator/role.md](roles/animator/role.md) | ANIM-* | true |
|
||||
| motion-tester | [roles/motion-tester/role.md](roles/motion-tester/role.md) | MTEST-* | false |
|
||||
|
||||
## Role Router
|
||||
|
||||
Parse `$ARGUMENTS`:
|
||||
- Has `--role <name>` -> Read `roles/<name>/role.md`, execute Phase 2-4
|
||||
- No `--role` -> `@roles/coordinator/role.md`, execute entry router
|
||||
|
||||
## Shared Constants
|
||||
|
||||
- **Session prefix**: `MD`
|
||||
- **Session path**: `.workflow/.team/MD-<slug>-<date>/`
|
||||
- **CLI tools**: `ccw cli --mode analysis` (read-only), `ccw cli --mode write` (modifications)
|
||||
- **Message bus**: `mcp__ccw-tools__team_msg(session_id=<session-id>, ...)`
|
||||
- **Max GC rounds**: 2
|
||||
|
||||
## Worker Spawn Template
|
||||
|
||||
Coordinator spawns workers using this template:
|
||||
|
||||
```
|
||||
Agent({
|
||||
subagent_type: "team-worker",
|
||||
description: "Spawn <role> worker for <task-id>",
|
||||
team_name: "motion-design",
|
||||
name: "<role>",
|
||||
run_in_background: true,
|
||||
prompt: `## Role Assignment
|
||||
role: <role>
|
||||
role_spec: <skill_root>/roles/<role>/role.md
|
||||
session: <session-folder>
|
||||
session_id: <session-id>
|
||||
team_name: motion-design
|
||||
requirement: <task-description>
|
||||
inner_loop: <true|false>
|
||||
|
||||
Read role_spec file (@<skill_root>/roles/<role>/role.md) to load Phase 2-4 domain instructions.
|
||||
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).`
|
||||
})
|
||||
```
|
||||
|
||||
## User Commands
|
||||
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| `check` / `status` | View execution status graph |
|
||||
| `resume` / `continue` | Advance to next step |
|
||||
|
||||
## Specs Reference
|
||||
|
||||
- [specs/pipelines.md](specs/pipelines.md) -- Pipeline definitions and task registry
|
||||
- [specs/motion-tokens.md](specs/motion-tokens.md) -- Animation token schema
|
||||
- [specs/gpu-constraints.md](specs/gpu-constraints.md) -- Compositor-only animation rules
|
||||
- [specs/reduced-motion.md](specs/reduced-motion.md) -- Accessibility motion preferences
|
||||
|
||||
## Session Directory
|
||||
|
||||
```
|
||||
.workflow/.team/MD-<slug>-<date>/
|
||||
+-- .msg/
|
||||
| +-- messages.jsonl # Team message bus
|
||||
| +-- meta.json # Pipeline config + GC state
|
||||
+-- research/ # Motion researcher output
|
||||
| +-- perf-traces/ # Chrome DevTools performance traces
|
||||
| +-- animation-inventory.json
|
||||
| +-- performance-baseline.json
|
||||
| +-- easing-catalog.json
|
||||
+-- choreography/ # Choreographer output
|
||||
| +-- motion-tokens.json
|
||||
| +-- sequences/ # Scroll choreography sequences
|
||||
+-- animations/ # Animator output
|
||||
| +-- keyframes/ # CSS @keyframes files
|
||||
| +-- orchestrators/ # JS animation orchestrators
|
||||
+-- testing/ # Motion tester output
|
||||
| +-- traces/ # Performance trace data
|
||||
| +-- reports/ # Performance reports
|
||||
+-- wisdom/ # Cross-task knowledge
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Unknown command | Error with available command list |
|
||||
| Role not found | Error with role registry |
|
||||
| Session corruption | Attempt recovery, fallback to manual |
|
||||
| Fast-advance conflict | Coordinator reconciles on next callback |
|
||||
| Completion action fails | Default to Keep Active |
|
||||
| GC loop stuck > 2 rounds | Escalate to user: accept / retry / terminate |
|
||||
194
.claude/skills/team-motion-design/roles/animator/role.md
Normal file
194
.claude/skills/team-motion-design/roles/animator/role.md
Normal file
@@ -0,0 +1,194 @@
|
||||
---
|
||||
role: animator
|
||||
prefix: ANIM
|
||||
inner_loop: true
|
||||
message_types: [state_update]
|
||||
---
|
||||
|
||||
# Animation Implementer
|
||||
|
||||
Implement CSS animations/transitions and JS orchestration from choreography specs. Build @keyframes with motion tokens as custom properties, IntersectionObserver-based scroll triggers, requestAnimationFrame coordination, and prefers-reduced-motion overrides. GPU-accelerated, compositor-only animations.
|
||||
|
||||
## Phase 2: Context & Artifact Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Motion tokens | <session>/choreography/motion-tokens.json | Yes |
|
||||
| Choreography sequences | <session>/choreography/sequences/*.md | Yes (component/page) |
|
||||
| Research artifacts | <session>/research/*.json | Yes |
|
||||
| GPU constraints | specs/gpu-constraints.md | Yes |
|
||||
| Reduced motion spec | specs/reduced-motion.md | Yes |
|
||||
| Performance report | <session>/testing/reports/perf-report-*.md | Only for GC fix tasks |
|
||||
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
|
||||
|
||||
1. Extract session path from task description
|
||||
2. Read motion tokens from choreography/motion-tokens.json
|
||||
3. Read choreography sequences (if applicable) from choreography/sequences/*.md
|
||||
4. Read research artifacts for existing animation context
|
||||
5. Read GPU constraints and reduced motion specs
|
||||
6. Detect task type from subject: "token" -> Token CSS, "section" -> Section animation, "fix" -> GC fix
|
||||
7. If GC fix task: read latest performance report from testing/reports/
|
||||
|
||||
## Phase 3: Implementation Execution
|
||||
|
||||
### Token CSS Implementation (ANIM-001 in tokens mode)
|
||||
|
||||
Generate CSS custom properties and utility classes:
|
||||
|
||||
**File: `<session>/animations/keyframes/motion-tokens.css`**:
|
||||
```css
|
||||
:root {
|
||||
/* Easing functions */
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
||||
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
|
||||
/* Duration scale */
|
||||
--duration-fast: 0.15s;
|
||||
--duration-base: 0.3s;
|
||||
--duration-slow: 0.6s;
|
||||
--duration-slower: 0.8s;
|
||||
--duration-slowest: 1.2s;
|
||||
|
||||
/* Stagger */
|
||||
--stagger-increment: 0.05s;
|
||||
}
|
||||
|
||||
/* Reduced motion overrides */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**File: `<session>/animations/keyframes/utility-animations.css`**:
|
||||
- `@keyframes fade-in` (opacity 0->1)
|
||||
- `@keyframes fade-up` (opacity 0->1, translateY 20px->0)
|
||||
- `@keyframes fade-down` (opacity 0->1, translateY -20px->0)
|
||||
- `@keyframes slide-in-left` (translateX -100%->0)
|
||||
- `@keyframes slide-in-right` (translateX 100%->0)
|
||||
- `@keyframes scale-in` (scale 0.95->1, opacity 0->1)
|
||||
- Utility classes: `.animate-fade-in`, `.animate-fade-up`, etc.
|
||||
- All animations consume motion token custom properties
|
||||
- All use compositor-only properties (transform, opacity)
|
||||
|
||||
### Component/Section Animation (ANIM-001..N in component/page mode)
|
||||
|
||||
For each section or component defined in choreography sequences:
|
||||
|
||||
**CSS @keyframes** (`<session>/animations/keyframes/<name>.css`):
|
||||
- Define @keyframes consuming motion tokens via `var(--ease-out)`, `var(--duration-slow)`
|
||||
- Use `will-change: transform, opacity` on animated elements (remove after animation via JS)
|
||||
- Only animate compositor-safe properties: transform (translate, scale, rotate), opacity, filter
|
||||
- NEVER animate: width, height, top, left, margin, padding, border, color, background-color
|
||||
|
||||
**JS Orchestrator** (`<session>/animations/orchestrators/<name>.js`):
|
||||
```javascript
|
||||
// IntersectionObserver-based scroll trigger
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('is-visible');
|
||||
observer.unobserve(entry.target); // one-shot
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.2, rootMargin: '0px 0px -100px 0px' });
|
||||
|
||||
// Staggered animation orchestrator
|
||||
function staggerReveal(container, itemSelector) {
|
||||
const items = container.querySelectorAll(itemSelector);
|
||||
const increment = parseFloat(getComputedStyle(document.documentElement)
|
||||
.getPropertyValue('--stagger-increment')) || 0.05;
|
||||
|
||||
items.forEach((item, index) => {
|
||||
item.style.transitionDelay = `${index * increment}s`;
|
||||
});
|
||||
// Trigger via IntersectionObserver on container
|
||||
observer.observe(container);
|
||||
}
|
||||
|
||||
// Reduced motion detection
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
if (prefersReducedMotion.matches) {
|
||||
// Skip parallax, disable springs, use instant transitions
|
||||
}
|
||||
|
||||
// requestAnimationFrame for scroll-linked effects (parallax)
|
||||
function parallaxScroll(element, rate) {
|
||||
if (prefersReducedMotion.matches) return; // skip for reduced motion
|
||||
let ticking = false;
|
||||
window.addEventListener('scroll', () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(() => {
|
||||
const scrolled = window.pageYOffset;
|
||||
element.style.transform = `translateY(${scrolled * rate}px)`;
|
||||
ticking = false;
|
||||
});
|
||||
ticking = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Height Animation Workaround
|
||||
Since `height` triggers layout (NEVER animate), use the grid trick:
|
||||
```css
|
||||
.expandable {
|
||||
display: grid;
|
||||
grid-template-rows: 0fr;
|
||||
transition: grid-template-rows var(--duration-normal) var(--ease-out-quart);
|
||||
}
|
||||
.expandable.open {
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
.expandable > .content {
|
||||
overflow: hidden;
|
||||
}
|
||||
```
|
||||
This achieves smooth height animation using only grid layout changes (compositor-friendly).
|
||||
|
||||
### Perceived Performance
|
||||
- **80ms threshold**: Any response under 80ms feels instant to the human brain
|
||||
- **Preemptive starts**: Begin animation on `pointerdown` not `click` (saves ~80-120ms perceived)
|
||||
- **Early completion**: Visual feedback can "finish" before actual operation completes (optimistic UI)
|
||||
- **Ease-in compresses perceived time**: Use ease-in for waiting states (progress bars) — makes them feel faster
|
||||
- **Ease-out satisfies entrances**: Use ease-out for content appearing — natural deceleration feels "settled"
|
||||
|
||||
### GC Fix Mode (ANIM-fix-N)
|
||||
|
||||
- Parse performance report for specific issues
|
||||
- Replace layout-triggering properties with compositor-only alternatives:
|
||||
- `width/height` -> `transform: scale()`
|
||||
- `top/left` -> `transform: translate()`
|
||||
- `background-color` -> `opacity` on overlay
|
||||
- Reduce will-change elements to max 3-4 simultaneous
|
||||
- Add missing prefers-reduced-motion overrides
|
||||
- Signal `animation_revision` instead of `animation_ready`
|
||||
|
||||
## Phase 4: Self-Validation & Output
|
||||
|
||||
1. Animation integrity checks:
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| no_layout_triggers | No width, height, top, left, margin, padding in @keyframes |
|
||||
| will_change_budget | Max 3-4 elements with will-change simultaneously |
|
||||
| reduced_motion | @media (prefers-reduced-motion: reduce) query present |
|
||||
| token_consumption | Animations use var(--token) references, no hardcoded values |
|
||||
| compositor_only | Only transform, opacity, filter in animation properties |
|
||||
|
||||
2. JS orchestrator checks:
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| intersection_observer | IntersectionObserver used for scroll triggers (not scroll events) |
|
||||
| raf_throttled | requestAnimationFrame used with ticking guard for scroll |
|
||||
| reduced_motion_js | `matchMedia('(prefers-reduced-motion: reduce)')` check present |
|
||||
| cleanup | will-change removed after animation completes (if applicable) |
|
||||
|
||||
3. Update `<session>/wisdom/.msg/meta.json` under `animator` namespace:
|
||||
- Read existing -> merge `{ "animator": { task_type, keyframe_count, orchestrator_count, uses_intersection_observer, has_parallax, has_stagger } }` -> write back
|
||||
164
.claude/skills/team-motion-design/roles/choreographer/role.md
Normal file
164
.claude/skills/team-motion-design/roles/choreographer/role.md
Normal file
@@ -0,0 +1,164 @@
|
||||
---
|
||||
role: choreographer
|
||||
prefix: CHOREO
|
||||
inner_loop: false
|
||||
message_types: [state_update]
|
||||
---
|
||||
|
||||
# Motion Choreographer
|
||||
|
||||
Design animation token systems (easing functions, duration/delay scales), scroll-triggered reveal sequences, and transition state diagrams. Consume research findings from motion-researcher. Define the motion language that the animator implements.
|
||||
|
||||
## Phase 2: Context & Artifact Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| Research artifacts | <session>/research/*.json | Yes |
|
||||
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
|
||||
| Motion token spec | specs/motion-tokens.md | Yes |
|
||||
| GPU constraints | specs/gpu-constraints.md | Yes |
|
||||
| Reduced motion spec | specs/reduced-motion.md | Yes |
|
||||
|
||||
1. Extract session path from task description
|
||||
2. Read research findings: animation-inventory.json, performance-baseline.json, easing-catalog.json
|
||||
3. Read motion token schema from specs/motion-tokens.md
|
||||
4. Read GPU constraints from specs/gpu-constraints.md for safe property list
|
||||
5. Read reduced motion guidelines from specs/reduced-motion.md
|
||||
|
||||
## Phase 3: Design Execution
|
||||
|
||||
### Motion Token System
|
||||
|
||||
Define complete token system as CSS custom properties + JSON:
|
||||
|
||||
**Easing Functions**:
|
||||
- `--ease-out`: `cubic-bezier(0.16, 1, 0.3, 1)` -- emphasis exit, deceleration
|
||||
- `--ease-in-out`: `cubic-bezier(0.65, 0, 0.35, 1)` -- smooth symmetrical
|
||||
- `--ease-spring`: `cubic-bezier(0.34, 1.56, 0.64, 1)` -- overshoot bounce
|
||||
- Integrate existing easing functions from research (avoid duplicates, reconcile naming)
|
||||
|
||||
**Duration Scale**:
|
||||
- `--duration-fast`: `0.15s` -- micro-interactions (button press, toggle)
|
||||
- `--duration-base`: `0.3s` -- standard transitions (hover, focus)
|
||||
- `--duration-slow`: `0.6s` -- content reveals, panel slides
|
||||
- `--duration-slower`: `0.8s` -- page transitions, large moves
|
||||
- `--duration-slowest`: `1.2s` -- hero animations, splash
|
||||
|
||||
**Delay Scale**:
|
||||
- `--stagger-base`: `0s` -- first item in stagger sequence
|
||||
- `--stagger-increment`: `0.05s` to `0.1s` -- per-item delay addition
|
||||
- Formula: `delay = base_delay + (index * stagger_increment)`
|
||||
- Max visible stagger: 8 items (avoid >0.8s total delay)
|
||||
|
||||
**Reduced Motion Overrides**:
|
||||
- All durations -> `0.01ms`
|
||||
- All easings -> `linear` (instant)
|
||||
- No parallax, no bounce/spring
|
||||
- Opacity-only fades allowed (<0.15s)
|
||||
|
||||
Output: `<session>/choreography/motion-tokens.json`
|
||||
```json
|
||||
{
|
||||
"easing": {
|
||||
"ease-out": { "value": "cubic-bezier(0.16, 1, 0.3, 1)", "use": "exit emphasis, deceleration" },
|
||||
"ease-in-out": { "value": "cubic-bezier(0.65, 0, 0.35, 1)", "use": "smooth symmetrical" },
|
||||
"ease-spring": { "value": "cubic-bezier(0.34, 1.56, 0.64, 1)", "use": "overshoot bounce" }
|
||||
},
|
||||
"duration": {
|
||||
"fast": { "value": "0.15s", "use": "micro-interactions" },
|
||||
"base": { "value": "0.3s", "use": "standard transitions" },
|
||||
"slow": { "value": "0.6s", "use": "content reveals" },
|
||||
"slower": { "value": "0.8s", "use": "page transitions" },
|
||||
"slowest": { "value": "1.2s", "use": "hero animations" }
|
||||
},
|
||||
"stagger": {
|
||||
"base_delay": "0s",
|
||||
"increment": "0.05s",
|
||||
"max_items": 8
|
||||
},
|
||||
"reduced_motion": {
|
||||
"duration_override": "0.01ms",
|
||||
"easing_override": "linear",
|
||||
"allowed": ["opacity"],
|
||||
"disallowed": ["parallax", "bounce", "spring", "infinite-loop"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Scroll Choreography Sequences
|
||||
|
||||
For component and page modes, define reveal sequences:
|
||||
|
||||
- IntersectionObserver thresholds per section (typical: 0.1 to 0.3)
|
||||
- Entry direction: fade-up, fade-in, slide-left, slide-right
|
||||
- Stagger groups: which elements stagger together, with calculated delays
|
||||
- Parallax depths: foreground (1x), midground (0.5x), background (0.2x) scroll rates
|
||||
- Scroll-linked effects: progress-based opacity, transform interpolation
|
||||
|
||||
Output per section: `<session>/choreography/sequences/<section-name>.md`
|
||||
```markdown
|
||||
# Section: <name>
|
||||
|
||||
## Trigger
|
||||
- Observer threshold: 0.2
|
||||
- Root margin: "0px 0px -100px 0px"
|
||||
|
||||
## Sequence
|
||||
1. Heading: fade-up, duration-slow, ease-out, delay 0s
|
||||
2. Subheading: fade-up, duration-slow, ease-out, delay 0.05s
|
||||
3. Cards[0..N]: fade-up, duration-slow, ease-out, stagger 0.08s each
|
||||
|
||||
## Parallax (if applicable)
|
||||
- Background image: 0.2x scroll rate
|
||||
- Foreground elements: 1x (normal)
|
||||
|
||||
## Reduced Motion Fallback
|
||||
- All elements: opacity fade only, duration-fast
|
||||
- No parallax, no directional movement
|
||||
```
|
||||
|
||||
### Transition State Diagrams
|
||||
|
||||
Define state transitions for interactive elements:
|
||||
|
||||
| State Pair | Properties | Duration | Easing |
|
||||
|------------|-----------|----------|--------|
|
||||
| hidden -> visible (entry) | opacity: 0->1, transform: translateY(20px)->0 | duration-slow | ease-out |
|
||||
| visible -> hidden (exit) | opacity: 1->0, transform: 0->translateY(-10px) | duration-base | ease-in-out |
|
||||
| idle -> hover | opacity: 1->0.8, transform: scale(1)->scale(1.02) | duration-fast | ease-out |
|
||||
| idle -> focus | outline: none->2px solid, outline-offset: 0->2px | duration-fast | ease-out |
|
||||
| idle -> active (pressed) | transform: scale(1)->scale(0.98) | duration-fast | ease-out |
|
||||
| idle -> loading | opacity: 1->0.6, add pulse animation | duration-base | ease-in-out |
|
||||
|
||||
All transitions use compositor-only properties (transform, opacity) per GPU constraints.
|
||||
|
||||
## Phase 4: Self-Validation
|
||||
|
||||
1. Token completeness checks:
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| easing_complete | All 3 easing functions defined with valid cubic-bezier |
|
||||
| duration_complete | All 5 duration steps defined |
|
||||
| stagger_defined | Base delay, increment, and max items specified |
|
||||
| reduced_motion | Override values defined for all token categories |
|
||||
|
||||
2. Sequence checks (if applicable):
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| threshold_valid | IntersectionObserver threshold between 0 and 1 |
|
||||
| safe_properties | Only compositor-safe properties in animations |
|
||||
| stagger_budget | No stagger sequence exceeds 0.8s total |
|
||||
| fallback_present | Reduced motion fallback defined for each sequence |
|
||||
|
||||
3. State diagram checks:
|
||||
|
||||
| Check | Pass Criteria |
|
||||
|-------|---------------|
|
||||
| states_covered | entry, exit, hover, focus, active states defined |
|
||||
| compositor_only | All animated properties are transform or opacity |
|
||||
| durations_use_tokens | All durations reference token scale values |
|
||||
|
||||
4. Update `<session>/wisdom/.msg/meta.json` under `choreographer` namespace:
|
||||
- Read existing -> merge `{ "choreographer": { token_count, sequence_count, state_diagrams, has_parallax, has_stagger } }` -> write back
|
||||
@@ -0,0 +1,64 @@
|
||||
# Analyze Task
|
||||
|
||||
Parse user task -> detect motion design scope -> build dependency graph -> determine pipeline mode.
|
||||
|
||||
**CONSTRAINT**: Text-level analysis only. NO source code reading, NO codebase exploration.
|
||||
|
||||
## Signal Detection
|
||||
|
||||
| Keywords | Capability | Pipeline Hint |
|
||||
|----------|------------|---------------|
|
||||
| easing, cubic-bezier, duration, timing | token system | tokens |
|
||||
| scroll, parallax, reveal, stagger, intersection | scroll choreography | page |
|
||||
| transition, hover, focus, state change | component animation | component |
|
||||
| @keyframes, will-change, transform, opacity | animation implementation | component |
|
||||
| page transition, route animation, full page | page-level motion | page |
|
||||
| motion tokens, animation system, design system | token system | tokens |
|
||||
| spring, bounce, overshoot | easing design | tokens |
|
||||
| reduced-motion, prefers-reduced-motion, a11y | accessibility | component or tokens |
|
||||
|
||||
## Scope Determination
|
||||
|
||||
| Signal | Pipeline Mode |
|
||||
|--------|---------------|
|
||||
| Token/easing/duration system mentioned | tokens |
|
||||
| Animate specific component(s) | component |
|
||||
| Full page scroll choreography or page transitions | page |
|
||||
| Unclear | ask user |
|
||||
|
||||
## Complexity Scoring
|
||||
|
||||
| Factor | Points |
|
||||
|--------|--------|
|
||||
| Single easing/token system | +1 |
|
||||
| Component animation | +2 |
|
||||
| Full page choreography | +3 |
|
||||
| Multiple scroll sections | +1 |
|
||||
| Parallax effects | +1 |
|
||||
| Reduced-motion required | +1 |
|
||||
| Performance constraints mentioned | +1 |
|
||||
|
||||
Results: 1-2 Low (tokens), 3-4 Medium (component), 5+ High (page)
|
||||
|
||||
## Framework Detection
|
||||
|
||||
| Keywords | Framework |
|
||||
|----------|-----------|
|
||||
| react, jsx, tsx | React |
|
||||
| vue, v-bind | Vue |
|
||||
| svelte | Svelte |
|
||||
| vanilla, plain js | Vanilla JS |
|
||||
| css-only, pure css | CSS-only |
|
||||
| Default | CSS + Vanilla JS |
|
||||
|
||||
## Output
|
||||
|
||||
Write scope context to coordinator memory:
|
||||
```json
|
||||
{
|
||||
"pipeline_mode": "<tokens|component|page>",
|
||||
"scope": "<description>",
|
||||
"framework": "<detected-framework>",
|
||||
"complexity": { "score": 0, "level": "Low|Medium|High" }
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,203 @@
|
||||
# Command: Dispatch
|
||||
|
||||
Create the motion design task chain with correct dependencies and structured task descriptions. Supports tokens, component, and page pipeline modes.
|
||||
|
||||
## Phase 2: Context Loading
|
||||
|
||||
| Input | Source | Required |
|
||||
|-------|--------|----------|
|
||||
| User requirement | From coordinator Phase 1 | Yes |
|
||||
| Session folder | From coordinator Phase 2 | Yes |
|
||||
| Pipeline mode | From session.json `pipeline` | Yes |
|
||||
| Framework config | From session.json `framework` | Yes |
|
||||
|
||||
1. Load user requirement and motion scope from session.json
|
||||
2. Load pipeline stage definitions from specs/pipelines.md
|
||||
3. Read `pipeline` and `framework` from session.json
|
||||
|
||||
## Phase 3: Task Chain Creation (Mode-Branched)
|
||||
|
||||
### Task Description Template
|
||||
|
||||
Every task description uses structured format:
|
||||
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "<TASK-ID>",
|
||||
description: "PURPOSE: <what this task achieves> | Success: <measurable completion criteria>
|
||||
TASK:
|
||||
- <step 1: specific action>
|
||||
- <step 2: specific action>
|
||||
- <step 3: specific action>
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <motion-scope>
|
||||
- Framework: <framework>
|
||||
- Upstream artifacts: <artifact-1>, <artifact-2>
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <deliverable path> + <quality criteria>
|
||||
CONSTRAINTS: <scope limits, focus areas>"
|
||||
})
|
||||
TaskUpdate({ taskId: "<TASK-ID>", addBlockedBy: [<dependency-list>], owner: "<role>" })
|
||||
```
|
||||
|
||||
### Mode Router
|
||||
|
||||
| Mode | Action |
|
||||
|------|--------|
|
||||
| `tokens` | Create 4 tasks: MRESEARCH -> CHOREO -> ANIM -> MTEST |
|
||||
| `component` | Create 4 tasks: MRESEARCH -> CHOREO -> ANIM -> MTEST (GC loop) |
|
||||
| `page` | Create 4+ tasks: MRESEARCH -> CHOREO -> [ANIM-001..N parallel] -> MTEST |
|
||||
|
||||
---
|
||||
|
||||
### Tokens Pipeline Task Chain
|
||||
|
||||
**MRESEARCH-001** (motion-researcher):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "MRESEARCH-001",
|
||||
description: "PURPOSE: Audit existing animations, measure performance baseline, catalog easing patterns | Success: 3 research artifacts produced with valid data
|
||||
TASK:
|
||||
- Scan codebase for existing CSS @keyframes, transitions, JS animation code
|
||||
- Measure paint/composite costs via Chrome DevTools performance traces (if available)
|
||||
- Catalog existing easing functions and timing patterns
|
||||
- Identify properties being animated (safe vs unsafe for compositor)
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <motion-scope>
|
||||
- Framework: <framework>
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/research/*.json | All 3 research files with valid JSON
|
||||
CONSTRAINTS: Read-only analysis | Focus on existing animation patterns"
|
||||
})
|
||||
TaskUpdate({ taskId: "MRESEARCH-001", owner: "motion-researcher" })
|
||||
```
|
||||
|
||||
**CHOREO-001** (choreographer):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "CHOREO-001",
|
||||
description: "PURPOSE: Design animation token system with easing functions, duration scale, stagger formulas | Success: Complete motion-tokens.json with all token categories
|
||||
TASK:
|
||||
- Define easing functions (ease-out, ease-in-out, ease-spring) as cubic-bezier values
|
||||
- Define duration scale (fast, base, slow, slower, slowest)
|
||||
- Define stagger formula with base delay and increment
|
||||
- Define reduced-motion fallback tokens
|
||||
- Reference specs/motion-tokens.md for token schema
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <motion-scope>
|
||||
- Framework: <framework>
|
||||
- Upstream artifacts: research/*.json
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/choreography/motion-tokens.json | Complete token system
|
||||
CONSTRAINTS: Follow motion-tokens.md schema | All tokens must have reduced-motion fallback"
|
||||
})
|
||||
TaskUpdate({ taskId: "CHOREO-001", addBlockedBy: ["MRESEARCH-001"], owner: "choreographer" })
|
||||
```
|
||||
|
||||
**ANIM-001** (animator):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "ANIM-001",
|
||||
description: "PURPOSE: Implement CSS custom properties and utility classes from motion tokens | Success: Production-ready CSS with token consumption and reduced-motion overrides
|
||||
TASK:
|
||||
- Generate CSS custom properties from motion-tokens.json
|
||||
- Create utility animation classes consuming tokens
|
||||
- Add prefers-reduced-motion media query overrides
|
||||
- Ensure compositor-only properties (transform, opacity) per specs/gpu-constraints.md
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <motion-scope>
|
||||
- Framework: <framework>
|
||||
- Upstream artifacts: choreography/motion-tokens.json
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/animations/keyframes/*.css | Token CSS + utility classes + reduced-motion
|
||||
CONSTRAINTS: Compositor-only animations | No layout-triggering properties | will-change budget"
|
||||
})
|
||||
TaskUpdate({ taskId: "ANIM-001", addBlockedBy: ["CHOREO-001"], owner: "animator" })
|
||||
```
|
||||
|
||||
**MTEST-001** (motion-tester):
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "MTEST-001",
|
||||
description: "PURPOSE: Verify animation performance and accessibility compliance | Success: 60fps confirmed, no layout thrashing, reduced-motion present
|
||||
TASK:
|
||||
- Start Chrome DevTools performance trace (if available)
|
||||
- Verify compositor-only animations (no paint/layout triggers)
|
||||
- Check will-change usage (not excessive, max 3-4 elements)
|
||||
- Validate prefers-reduced-motion @media query presence
|
||||
- Static code analysis as fallback if Chrome DevTools unavailable
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Scope: <motion-scope>
|
||||
- Framework: <framework>
|
||||
- Upstream artifacts: animations/keyframes/*.css, choreography/motion-tokens.json
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/testing/reports/perf-report-001.md | Performance validation report
|
||||
CONSTRAINTS: Target 60fps | Flag any layout-triggering properties"
|
||||
})
|
||||
TaskUpdate({ taskId: "MTEST-001", addBlockedBy: ["ANIM-001"], owner: "motion-tester" })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Component Pipeline Task Chain
|
||||
|
||||
Same as Tokens pipeline with enhanced task descriptions:
|
||||
|
||||
- **MRESEARCH-001**: Same as tokens, plus focus on target component(s) existing animation
|
||||
- **CHOREO-001**: Same token design, plus transition state diagrams (entry/exit/hover/focus/loading) and scroll-triggered reveal sequences for the component(s)
|
||||
- **ANIM-001**: Implement component-specific animations: @keyframes, IntersectionObserver triggers, rAF coordination, staggered orchestration
|
||||
- **MTEST-001**: Same as tokens, plus GC loop -- if FPS < 60 or layout thrashing, send `fix_required` signal
|
||||
|
||||
GC loop between animator and motion-tester (max 2 rounds).
|
||||
|
||||
---
|
||||
|
||||
### Page Pipeline Task Chain
|
||||
|
||||
**MRESEARCH-001** and **CHOREO-001**: Same as component, but scope is full page with multiple scroll sections.
|
||||
|
||||
**CHOREO-001** additionally defines scroll section boundaries, parallax depths, and staggered entry sequences per section.
|
||||
|
||||
**ANIM-001..N** (parallel): One ANIM task per scroll section or page area:
|
||||
```
|
||||
TaskCreate({
|
||||
subject: "ANIM-<NNN>",
|
||||
description: "PURPOSE: Implement animations for <section-name> | Success: Scroll-triggered reveals with 60fps performance
|
||||
TASK:
|
||||
- Implement IntersectionObserver-based scroll triggers for <section-name>
|
||||
- Apply staggered entry animations with calculated delays
|
||||
- Add scroll-linked parallax (if specified in choreography)
|
||||
- Ensure prefers-reduced-motion fallback
|
||||
CONTEXT:
|
||||
- Session: <session-folder>
|
||||
- Section: <section-name>
|
||||
- Upstream artifacts: choreography/sequences/<section>.md, choreography/motion-tokens.json
|
||||
- Shared memory: <session>/wisdom/.msg/meta.json
|
||||
EXPECTED: <session>/animations/keyframes/<section>.css + orchestrators/<section>.js
|
||||
CONSTRAINTS: Compositor-only | will-change budget | Follow motion-tokens"
|
||||
})
|
||||
TaskUpdate({ taskId: "ANIM-<NNN>", addBlockedBy: ["CHOREO-001"], owner: "animator" })
|
||||
```
|
||||
|
||||
**MTEST-001**: Blocked by all ANIM tasks. Full page performance validation.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Validation
|
||||
|
||||
Verify task chain integrity:
|
||||
|
||||
| Check | Method | Expected |
|
||||
|-------|--------|----------|
|
||||
| Task count correct | TaskList count | tokens: 4, component: 4, page: 4+N |
|
||||
| Dependencies correct | Trace dependency graph | Acyclic, correct blockedBy |
|
||||
| No circular dependencies | Trace dependency graph | Acyclic |
|
||||
| Task IDs use correct prefixes | Pattern check | MRESEARCH/CHOREO/ANIM/MTEST |
|
||||
| Structured descriptions complete | Each has PURPOSE/TASK/CONTEXT/EXPECTED/CONSTRAINTS | All present |
|
||||
|
||||
If validation fails, fix the specific task and re-validate.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user