diff --git a/.claude/commands/workflow/analyze-with-file.md b/.claude/commands/workflow/analyze-with-file.md index 33c80c4d..f8fbab5d 100644 --- a/.claude/commands/workflow/analyze-with-file.md +++ b/.claude/commands/workflow/analyze-with-file.md @@ -238,8 +238,24 @@ Session: ${sessionFolder} ## MANDATORY FIRST STEPS 1. Run: ccw tool exec get_modules_by_depth '{}' -2. Execute relevant searches based on topic keywords -3. Read: .workflow/project-tech.json (if exists) +2. Read: .workflow/project-tech.json (if exists) + +## Layered Exploration (MUST follow all 3 layers) + +### Layer 1 — Module Discovery (Breadth) +- Search codebase by topic keywords, identify ALL relevant files +- Map module boundaries and entry points +- Output: relevant_files[] with file role annotations + +### Layer 2 — Structure Tracing (Depth) +- For top 3-5 key files from Layer 1: trace call chains (2-3 levels deep) +- Identify data flow paths and dependency relationships +- Output: call_chains[], data_flows[] + +### Layer 3 — Code Anchor Extraction (Detail) +- For each key finding: extract the actual code snippet (20-50 lines) with file:line reference +- Annotate WHY this code matters to the analysis topic +- Output: code_anchors[] — these are CRITICAL for subsequent analysis quality ## Exploration Focus ${dimensions.map(d => `- ${d}: Identify relevant code patterns and structures`).join('\n')} @@ -247,7 +263,7 @@ ${dimensions.map(d => `- ${d}: Identify relevant code patterns and structures`). ## Output Write findings to: ${sessionFolder}/exploration-codebase.json -Schema: {relevant_files, patterns, key_findings, questions_for_user, _metadata} +Schema: {relevant_files, patterns, key_findings, code_anchors: [{file, lines, snippet, significance}], call_chains: [{entry, chain, files}], questions_for_user, _metadata} ` }) ``` @@ -268,8 +284,21 @@ Session: ${sessionFolder} ## MANDATORY FIRST STEPS 1. Run: ccw tool exec get_modules_by_depth '{}' -2. Execute searches focused on ${perspective.focus} -3. Read: .workflow/project-tech.json (if exists) +2. Read: .workflow/project-tech.json (if exists) + +## Layered Exploration (${perspective.name} angle, MUST follow all 3 layers) + +### Layer 1 — Module Discovery +- Search codebase focused on ${perspective.focus} +- Identify ALL relevant files for this perspective + +### Layer 2 — Structure Tracing +- For top 3-5 key files: trace call chains (2-3 levels deep) +- Map data flows relevant to ${perspective.focus} + +### Layer 3 — Code Anchor Extraction +- For each key finding: extract actual code snippet (20-50 lines) with file:line +- Annotate significance for ${perspective.name} analysis ## Exploration Focus (${perspective.name} angle) ${perspective.exploration_tasks.map(t => `- ${t}`).join('\n')} @@ -277,7 +306,7 @@ ${perspective.exploration_tasks.map(t => `- ${t}`).join('\n')} ## Output Write findings to: ${sessionFolder}/explorations/${perspective.name}.json -Schema: {relevant_files, patterns, key_findings, perspective_insights, _metadata} +Schema: {relevant_files, patterns, key_findings, code_anchors: [{file, lines, snippet, significance}], call_chains: [{entry, chain, files}], perspective_insights, _metadata} ` }) }) @@ -301,11 +330,14 @@ PRIOR EXPLORATION CONTEXT: - Key files: ${explorationResults.relevant_files.slice(0,5).map(f => f.path).join(', ')} - Patterns found: ${explorationResults.patterns.slice(0,3).join(', ')} - Key findings: ${explorationResults.key_findings.slice(0,3).join(', ')} +- Code anchors (actual code snippets): +${(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('; ')} TASK: -• Build on exploration findings above -• Analyze common patterns and anti-patterns -• Highlight potential issues or opportunities +• Build on exploration findings above — reference specific code anchors in analysis +• Analyze common patterns and anti-patterns with code evidence +• Highlight potential issues or opportunities with file:line references • Generate discussion points for user clarification MODE: analysis @@ -324,7 +356,10 @@ const explorationContext = ` PRIOR EXPLORATION CONTEXT: - Key files: ${explorationResults.relevant_files.slice(0,5).map(f => f.path).join(', ')} - Patterns found: ${explorationResults.patterns.slice(0,3).join(', ')} -- Key findings: ${explorationResults.key_findings.slice(0,3).join(', ')}` +- Key findings: ${explorationResults.key_findings.slice(0,3).join(', ')} +- Code anchors: +${(explorationResults.code_anchors || []).slice(0,5).map(a => ` [${a.file}:${a.lines}] ${a.significance}`).join('\n')} +- Call chains: ${(explorationResults.call_chains || []).slice(0,3).map(c => `${c.entry} → ${c.chain.join(' → ')}`).join('; ')}` // Launch parallel CLI calls based on selected perspectives (max 4) selectedPerspectives.forEach(perspective => { @@ -368,6 +403,8 @@ CONSTRAINTS: ${perspective.constraints} - `dimensions[]`: Analysis dimensions - `sources[]`: {type, file/summary} - `key_findings[]`: Main insights +- `code_anchors[]`: {file, lines, snippet, significance} +- `call_chains[]`: {entry, chain, files} - `discussion_points[]`: Questions for user - `open_questions[]`: Unresolved questions @@ -378,7 +415,9 @@ CONSTRAINTS: ${perspective.constraints} - `dimensions[]`: Analysis dimensions - `perspectives[]`: [{name, tool, findings, insights, questions}] - `synthesis`: {convergent_themes, conflicting_views, unique_contributions} -- `aggregated_findings[]`: Main insights across perspectives +- `key_findings[]`: Main insights across perspectives +- `code_anchors[]`: {file, lines, snippet, significance, perspective} +- `call_chains[]`: {entry, chain, files, perspective} - `discussion_points[]`: Questions for user - `open_questions[]`: Unresolved questions @@ -423,9 +462,14 @@ CONSTRAINTS: ${perspective.constraints} - If direction changed, record a full Decision Record **Agree, Deepen**: - - Continue analysis in current direction - - Use CLI for deeper exploration - - **📌 Record**: Which assumptions were confirmed, specific angles for deeper exploration + - AskUserQuestion for deepen direction (single-select): + - **代码细节**: Read specific files, trace call chains deeper → cli-explore-agent with targeted file list + - **边界条件**: Analyze error handling, edge cases, failure paths → Gemini CLI focused on error paths + - **替代方案**: Compare different implementation approaches → Gemini CLI comparative analysis + - **性能/安全**: Analyze hot paths, complexity, or security vectors → cli-explore-agent + domain prompt + - Launch new cli-explore-agent or CLI call with **narrower scope + deeper depth requirement** + - Merge new code_anchors and call_chains into existing exploration results + - **📌 Record**: Which assumptions were confirmed, specific angles for deeper exploration, deepen direction chosen **Adjust Direction**: - AskUserQuestion for adjusted focus (code details / architecture / best practices) @@ -471,7 +515,10 @@ CONSTRAINTS: ${perspective.constraints} | User Choice | Action | Tool | Description | |-------------|--------|------|-------------| -| Deepen | Continue current direction | Gemini CLI | Deeper analysis in same focus | +| Deepen → 代码细节 | Read files, trace call chains | cli-explore-agent | Targeted deep-dive into specific files | +| Deepen → 边界条件 | Analyze error/edge cases | Gemini CLI | Focus on failure paths and edge cases | +| Deepen → 替代方案 | Compare approaches | Gemini CLI | Comparative analysis | +| Deepen → 性能/安全 | Analyze hot paths/vectors | cli-explore-agent | Domain-specific deep analysis | | Adjust | Change analysis angle | Selected CLI | New exploration with adjusted scope | | Questions | Answer specific questions | CLI or analysis | Address user inquiries | | Complete | Exit discussion loop | - | Proceed to synthesis | @@ -629,7 +676,8 @@ DO NOT reference any analyze-with-file phase instructions beyond this point. - `completed`: Completion timestamp - `total_rounds`: Number of discussion rounds - `summary`: Executive summary -- `key_conclusions[]`: {point, evidence, confidence} +- `key_conclusions[]`: {point, evidence, confidence, code_anchor_refs[]} +- `code_anchors[]`: {file, lines, snippet, significance} - `recommendations[]`: {action, rationale, priority} - `open_questions[]`: Unresolved questions - `follow_up_suggestions[]`: {type, summary} diff --git a/.claude/skills/spec-generator/README.md b/.claude/skills/spec-generator/README.md index c47a6ea9..65ffd74a 100644 --- a/.claude/skills/spec-generator/README.md +++ b/.claude/skills/spec-generator/README.md @@ -17,33 +17,42 @@ Structured specification document generator producing a complete document chain spec-generator/ |- SKILL.md # Entry point: metadata + architecture + flow |- phases/ -| |- 01-discovery.md # Seed analysis + codebase exploration -| |- 02-product-brief.md # Multi-CLI product brief generation -| |- 03-requirements.md # PRD with MoSCoW priorities -| |- 04-architecture.md # Architecture decisions + review +| |- 01-discovery.md # Seed analysis + codebase exploration + spec type selection +| |- 01-5-requirement-clarification.md # Interactive requirement expansion +| |- 02-product-brief.md # Multi-CLI product brief + glossary generation +| |- 03-requirements.md # PRD with MoSCoW priorities + RFC 2119 constraints +| |- 04-architecture.md # Architecture + state machine + config model + observability | |- 05-epics-stories.md # Epic/Story decomposition -| |- 06-readiness-check.md # Quality validation + handoff +| |- 06-readiness-check.md # Quality validation + handoff + iterate option +| |- 06-5-auto-fix.md # Auto-fix loop for readiness issues (max 2 iterations) |- specs/ | |- document-standards.md # Format, frontmatter, naming rules -| |- quality-gates.md # Per-phase quality criteria +| |- quality-gates.md # Per-phase quality criteria + iteration tracking +| |- glossary-template.json # Terminology glossary schema |- templates/ -| |- product-brief.md # Product brief template +| |- product-brief.md # Product brief template (+ Concepts & Non-Goals) | |- requirements-prd.md # PRD template -| |- architecture-doc.md # Architecture document template -| |- epics-template.md # Epic/Story template +| |- architecture-doc.md # Architecture template (+ state machine, config, observability) +| |- epics-template.md # Epic/Story template (+ versioning) +| |- profiles/ # Spec type specialization profiles +| |- service-profile.md # Service spec: lifecycle, observability, trust +| |- api-profile.md # API spec: endpoints, auth, rate limiting +| |- library-profile.md # Library spec: public API, examples, compatibility |- README.md # This file ``` ## 6-Phase Pipeline -| Phase | Name | Output | CLI Tools | -|-------|------|--------|-----------| -| 1 | Discovery | spec-config.json | Gemini (analysis) | -| 2 | Product Brief | product-brief.md | Gemini + Codex + Claude (parallel) | -| 3 | Requirements | requirements.md | Gemini (analysis) | -| 4 | Architecture | architecture.md | Gemini + Codex (sequential) | -| 5 | Epics & Stories | epics.md | Gemini (analysis) | -| 6 | Readiness Check | readiness-report.md, spec-summary.md | Gemini (validation) | +| Phase | Name | Output | CLI Tools | Key Features | +|-------|------|--------|-----------|-------------| +| 1 | Discovery | spec-config.json | Gemini (analysis) | Spec type selection | +| 1.5 | Req Expansion | refined-requirements.json | Gemini (analysis) | Multi-round interactive | +| 2 | Product Brief | product-brief.md, glossary.json | Gemini + Codex + Claude (parallel) | Terminology glossary | +| 3 | Requirements | requirements/ | Gemini (analysis) | RFC 2119, data model | +| 4 | Architecture | architecture/ | Gemini + Codex (sequential) | State machine, config, observability | +| 5 | Epics & Stories | epics/ | Gemini (analysis) | Glossary consistency | +| 6 | Readiness Check | readiness-report.md, spec-summary.md | Gemini (validation) | Terminology + scope validation | +| 6.5 | Auto-Fix | Updated phase docs | Gemini (analysis) | Max 2 iterations | ## Runtime Output @@ -51,12 +60,21 @@ spec-generator/ .workflow/.spec/SPEC-{slug}-{YYYY-MM-DD}/ |- spec-config.json # Session state |- discovery-context.json # Codebase context (optional) +|- refined-requirements.json # Phase 1.5 (requirement expansion) +|- glossary.json # Phase 2 (terminology) |- product-brief.md # Phase 2 -|- requirements.md # Phase 3 -|- architecture.md # Phase 4 -|- epics.md # Phase 5 +|- requirements/ # Phase 3 (directory) +| |- _index.md +| |- REQ-*.md +| └── NFR-*.md +|- architecture/ # Phase 4 (directory) +| |- _index.md +| └── ADR-*.md +|- epics/ # Phase 5 (directory) +| |- _index.md +| └── EPIC-*.md |- readiness-report.md # Phase 6 -|- spec-summary.md # Phase 6 +└── spec-summary.md # Phase 6 ``` ## Flags @@ -64,6 +82,9 @@ spec-generator/ - `-y|--yes`: Auto mode - skip all interactive confirmations - `-c|--continue`: Resume from last completed phase +Spec type is selected interactively in Phase 1 (defaults to `service` in auto mode) +Available types: `service`, `api`, `library`, `platform` + ## Handoff After Phase 6, choose execution path: @@ -79,3 +100,6 @@ After Phase 6, choose execution path: - **Template-driven**: Consistent format via templates + frontmatter - **Resumable**: spec-config.json tracks completed phases - **Pure documentation**: No code generation - clean handoff to execution workflows +- **Type-specialized**: Profiles adapt templates to service/api/library/platform requirements +- **Iterative quality**: Phase 6.5 auto-fix repairs issues, max 2 iterations before handoff +- **Terminology-first**: glossary.json ensures consistent terminology across all documents diff --git a/.claude/skills/spec-generator/SKILL.md b/.claude/skills/spec-generator/SKILL.md index 06a44972..9664d94f 100644 --- a/.claude/skills/spec-generator/SKILL.md +++ b/.claude/skills/spec-generator/SKILL.md @@ -14,20 +14,26 @@ Structured specification document generator producing a complete specification p Phase 0: Specification Study (Read specs/ + templates/ - mandatory prerequisite) | Phase 1: Discovery -> spec-config.json + discovery-context.json - | + | (includes spec_type selection) Phase 1.5: Req Expansion -> refined-requirements.json (interactive discussion + CLI gap analysis) | (-y auto mode: auto-expansion, skip interaction) -Phase 2: Product Brief -> product-brief.md (multi-CLI parallel analysis) +Phase 2: Product Brief -> product-brief.md + glossary.json (multi-CLI parallel analysis) | Phase 3: Requirements (PRD) -> requirements/ (_index.md + REQ-*.md + NFR-*.md) - | + | (RFC 2119 keywords, data model definitions) Phase 4: Architecture -> architecture/ (_index.md + ADR-*.md, multi-CLI review) - | + | (state machine, config model, error handling, observability) Phase 5: Epics & Stories -> epics/ (_index.md + EPIC-*.md) | Phase 6: Readiness Check -> readiness-report.md + spec-summary.md - | - Handoff to execution workflows + | (terminology + scope consistency validation) + ├── Pass (>=80%): Handoff to execution workflows + ├── Review (60-79%): Handoff with caveats + └── Fail (<60%): Phase 6.5 Auto-Fix (max 2 iterations) + | +Phase 6.5: Auto-Fix -> Updated Phase 2-5 documents + | + └── Re-run Phase 6 validation ``` ## Key Design Principles @@ -38,6 +44,9 @@ Phase 6: Readiness Check -> readiness-report.md + spec-summary.md 4. **Resumable Sessions**: `spec-config.json` tracks completed phases; `-c` flag resumes from last checkpoint 5. **Template-Driven**: All documents generated from standardized templates with YAML frontmatter 6. **Pure Documentation**: No code generation or execution - clean handoff to existing execution workflows +7. **Spec Type Specialization**: Templates adapt to spec type (service/api/library/platform) via profiles for domain-specific depth +8. **Iterative Quality**: Phase 6.5 auto-fix loop repairs issues found in readiness check (max 2 iterations) +9. **Terminology Consistency**: glossary.json generated in Phase 2, injected into all subsequent phases --- @@ -78,6 +87,7 @@ Phase 1: Discovery & Seed Analysis |- Parse input (text or file reference) |- Gemini CLI seed analysis (problem, users, domain, dimensions) |- Codebase exploration (conditional, if project detected) + |- Spec type selection: service|api|library|platform (interactive, -y defaults to service) |- User confirmation (interactive, -y skips) |- Output: spec-config.json, discovery-context.json (optional) @@ -95,13 +105,17 @@ Phase 2: Product Brief |- Ref: phases/02-product-brief.md |- 3 parallel CLI analyses: Product (Gemini) + Technical (Codex) + User (Claude) |- Synthesize perspectives: convergent themes + conflicts + |- Generate glossary.json (terminology from product brief + CLI analysis) |- Interactive refinement (-y skips) - |- Output: product-brief.md (from template) + |- Output: product-brief.md (from template), glossary.json Phase 3: Requirements / PRD |- Ref: phases/03-requirements.md |- Gemini CLI: expand goals into functional + non-functional requirements |- Generate acceptance criteria per requirement + |- RFC 2119 behavioral constraints (MUST/SHOULD/MAY) + |- Core entity data model definitions + |- Glossary injection for terminology consistency |- User priority sorting: MoSCoW (interactive, -y auto-assigns) |- Output: requirements/ directory (_index.md + REQ-*.md + NFR-*.md, from template) @@ -109,6 +123,12 @@ Phase 4: Architecture |- Ref: phases/04-architecture.md |- Gemini CLI: core components, tech stack, ADRs |- Codebase integration mapping (conditional) + |- State machine generation (ASCII diagrams for lifecycle entities) + |- Configuration model definition (fields, types, defaults, constraints) + |- Error handling strategy (per-component classification + recovery) + |- Observability specification (metrics, logs, health checks) + |- Spec type profile injection (templates/profiles/{type}-profile.md) + |- Glossary injection for terminology consistency |- Codex CLI: architecture challenge + review |- Interactive ADR decisions (-y auto-accepts) |- Output: architecture/ directory (_index.md + ADR-*.md, from template) @@ -125,9 +145,20 @@ Phase 6: Readiness Check |- Ref: phases/06-readiness-check.md |- Cross-document validation (completeness, consistency, traceability) |- Quality scoring per dimension + |- Terminology consistency validation (glossary compliance) + |- Scope containment validation (PRD <= Brief scope) |- Output: readiness-report.md, spec-summary.md |- Handoff options: lite-plan, req-plan, plan, issue:new, export only, iterate +Phase 6.5: Auto-Fix (conditional, triggered when Phase 6 score < 60%) + |- Ref: phases/06-5-auto-fix.md + |- Parse readiness-report.md for Error/Warning items + |- Group issues by originating Phase (2-5) + |- Re-generate affected sections via CLI with error context + |- Re-run Phase 6 validation + |- Max 2 iterations, then force handoff + |- Output: Updated Phase 2-5 documents + Complete: Full specification package ready for execution Phase 6 → Handoff Bridge (conditional, based on user selection): @@ -161,6 +192,7 @@ Bash(`mkdir -p "${workDir}"`); ├── spec-config.json # Session configuration + phase state ├── discovery-context.json # Codebase exploration results (optional) ├── refined-requirements.json # Phase 1.5: Confirmed requirements after discussion +├── glossary.json # Phase 2: Terminology glossary for cross-doc consistency ├── product-brief.md # Phase 2: Product brief ├── requirements/ # Phase 3: Detailed PRD (directory) │ ├── _index.md # Summary, MoSCoW table, traceability, links @@ -189,6 +221,9 @@ Bash(`mkdir -p "${workDir}"`); "complexity": "moderate", "depth": "standard", "focus_areas": [], + "spec_type": "service", + "iteration_count": 0, + "iteration_history": [], "seed_analysis": { "problem_statement": "...", "target_users": [], @@ -217,6 +252,9 @@ Bash(`mkdir -p "${workDir}"`); 5. **DO NOT STOP**: Continuous 6-phase pipeline until all phases complete or user exits 6. **Respect -y Flag**: When auto mode, skip all AskUserQuestion calls, use recommended defaults 7. **Respect -c Flag**: When continue mode, load spec-config.json and resume from checkpoint +8. **Inject Glossary**: From Phase 3 onward, inject glossary.json terms into every CLI prompt +9. **Load Profile**: Read templates/profiles/{spec_type}-profile.md and inject requirements into Phase 2-5 prompts +10. **Iterate on Failure**: When Phase 6 score < 60%, auto-trigger Phase 6.5 (max 2 iterations) ## Reference Documents by Phase @@ -224,6 +262,7 @@ Bash(`mkdir -p "${workDir}"`); | Document | Purpose | When to Use | |----------|---------|-------------| | [phases/01-discovery.md](phases/01-discovery.md) | Seed analysis and session setup | Phase start | +| [templates/profiles/](templates/profiles/) | Spec type profiles | Spec type selection | | [specs/document-standards.md](specs/document-standards.md) | Frontmatter format for spec-config.json | Config generation | ### Phase 1.5: Requirement Expansion & Clarification @@ -237,6 +276,7 @@ Bash(`mkdir -p "${workDir}"`); |----------|---------|-------------| | [phases/02-product-brief.md](phases/02-product-brief.md) | Multi-CLI analysis orchestration | Phase start | | [templates/product-brief.md](templates/product-brief.md) | Document template | Document generation | +| [specs/glossary-template.json](specs/glossary-template.json) | Glossary schema | Glossary generation | ### Phase 3: Requirements | Document | Purpose | When to Use | @@ -262,6 +302,12 @@ Bash(`mkdir -p "${workDir}"`); | [phases/06-readiness-check.md](phases/06-readiness-check.md) | Cross-document validation | Phase start | | [specs/quality-gates.md](specs/quality-gates.md) | Quality scoring criteria | Validation | +### Phase 6.5: Auto-Fix +| Document | Purpose | When to Use | +|----------|---------|-------------| +| [phases/06-5-auto-fix.md](phases/06-5-auto-fix.md) | Auto-fix workflow for readiness issues | When Phase 6 score < 60% | +| [specs/quality-gates.md](specs/quality-gates.md) | Iteration exit criteria | Validation | + ### Debugging & Troubleshooting | Issue | Solution Document | |-------|-------------------| @@ -284,6 +330,8 @@ Bash(`mkdir -p "${workDir}"`); | Phase 4 | Architecture review fails | No | Skip review, proceed with initial analysis | | Phase 5 | Story generation fails | No | Generate epics without detailed stories | | Phase 6 | Validation CLI fails | No | Generate partial report with available data | +| Phase 6.5 | Auto-fix CLI fails | No | Log failure, proceed to handoff with Review status | +| Phase 6.5 | Max iterations reached | No | Force handoff, report remaining issues | ### CLI Fallback Chain diff --git a/.claude/skills/spec-generator/phases/01-discovery.md b/.claude/skills/spec-generator/phases/01-discovery.md index e9056afa..b7b5cf76 100644 --- a/.claude/skills/spec-generator/phases/01-discovery.md +++ b/.claude/skills/spec-generator/phases/01-discovery.md @@ -185,6 +185,17 @@ if (!autoMode) { header: "Focus", multiSelect: true, options: seedAnalysis.dimensions.map(d => ({ label: d, description: `Explore ${d} in depth` })) + }, + { + question: "What type of specification is this?", + header: "Spec Type", + multiSelect: false, + options: [ + { label: "Service (Recommended)", description: "Long-running service with lifecycle, state machine, observability" }, + { label: "API", description: "REST/GraphQL API with endpoints, auth, rate limiting" }, + { label: "Library/SDK", description: "Reusable package with public API surface, examples" }, + { label: "Platform", description: "Multi-component system, uses Service profile" } + ] } ] }); @@ -192,6 +203,7 @@ if (!autoMode) { // Auto mode defaults depth = "standard"; focusAreas = seedAnalysis.dimensions; + specType = "service"; // default for auto mode } ``` @@ -209,6 +221,9 @@ const specConfig = { focus_areas: focusAreas, seed_analysis: seedAnalysis, has_codebase: hasCodebase, + spec_type: specType, // "service" | "api" | "library" | "platform" + iteration_count: 0, + iteration_history: [], phasesCompleted: [ { phase: 1, diff --git a/.claude/skills/spec-generator/phases/02-product-brief.md b/.claude/skills/spec-generator/phases/02-product-brief.md index ab876465..7c9a1e87 100644 --- a/.claude/skills/spec-generator/phases/02-product-brief.md +++ b/.claude/skills/spec-generator/phases/02-product-brief.md @@ -227,6 +227,33 @@ specConfig.phasesCompleted.push({ Write(`${workDir}/spec-config.json`, JSON.stringify(specConfig, null, 2)); ``` +### Step 5.5: Generate glossary.json + +```javascript +// Extract terminology from product brief and CLI analysis +// Generate structured glossary for cross-document consistency + +const glossary = { + session_id: specConfig.session_id, + terms: [ + // Extract from product brief content: + // - Key domain nouns from problem statement + // - User persona names + // - Technical terms from multi-perspective synthesis + // Each term should have: + // { term: "...", definition: "...", aliases: [], first_defined_in: "product-brief.md", category: "core|technical|business" } + ] +}; + +Write(`${workDir}/glossary.json`, JSON.stringify(glossary, null, 2)); +``` + +**Glossary Injection**: In all subsequent phase prompts, inject the following into the CONTEXT section: +``` +TERMINOLOGY GLOSSARY (use these terms consistently): +${JSON.stringify(glossary.terms, null, 2)} +``` + ## Output - **File**: `product-brief.md` diff --git a/.claude/skills/spec-generator/phases/03-requirements.md b/.claude/skills/spec-generator/phases/03-requirements.md index 1960d518..577b8e5b 100644 --- a/.claude/skills/spec-generator/phases/03-requirements.md +++ b/.claude/skills/spec-generator/phases/03-requirements.md @@ -60,6 +60,11 @@ TASK: - Should: Important but has workaround - Could: Nice-to-have, enhances experience - Won't: Explicitly deferred +- Use RFC 2119 keywords (MUST, SHOULD, MAY, MUST NOT, SHOULD NOT) to define behavioral constraints for each requirement. Example: 'The system MUST return a 401 response within 100ms for invalid tokens.' +- For each core domain entity referenced in requirements, define its data model: fields, types, constraints, and relationships to other entities +- Maintain terminology consistency with the glossary below: + TERMINOLOGY GLOSSARY: + \${glossary ? JSON.stringify(glossary.terms, null, 2) : 'N/A - generate terms inline'} MODE: analysis EXPECTED: Structured requirements with: ID, title, description, user story, acceptance criteria, priority, traceability to goals diff --git a/.claude/skills/spec-generator/phases/04-architecture.md b/.claude/skills/spec-generator/phases/04-architecture.md index 5a67d8db..66cd8c6f 100644 --- a/.claude/skills/spec-generator/phases/04-architecture.md +++ b/.claude/skills/spec-generator/phases/04-architecture.md @@ -33,6 +33,19 @@ if (specConfig.has_codebase) { discoveryContext = JSON.parse(Read(`${workDir}/discovery-context.json`)); } catch (e) { /* no context */ } } + +// Load glossary for terminology consistency +let glossary = null; +try { + glossary = JSON.parse(Read(`${workDir}/glossary.json`)); +} catch (e) { /* proceed without */ } + +// Load spec type profile for specialized sections +const specType = specConfig.spec_type || 'service'; +let profile = null; +try { + profile = Read(`templates/profiles/${specType}-profile.md`); +} catch (e) { /* use base template only */ } ``` ### Step 2: Architecture Analysis via Gemini CLI @@ -66,6 +79,28 @@ TASK: - Identify security architecture: auth, authorization, data protection - List API endpoints (high-level) ${discoveryContext ? '- Map new components to existing codebase modules' : ''} +- For each core entity with a lifecycle, create an ASCII state machine diagram showing: + - All states and transitions + - Trigger events for each transition + - Side effects of transitions + - Error states and recovery paths +- Define a Configuration Model: list all configurable fields with name, type, default value, constraint, and description +- Define Error Handling strategy: + - Classify errors (transient/permanent/degraded) + - Per-component error behavior using RFC 2119 keywords + - Recovery mechanisms +- Define Observability requirements: + - Key metrics (name, type: counter/gauge/histogram, labels) + - Structured log format and key log events + - Health check endpoints +\${profile ? \` +SPEC TYPE PROFILE REQUIREMENTS (\${specType}): +\${profile} +\` : ''} +\${glossary ? \` +TERMINOLOGY GLOSSARY (use consistently): +\${JSON.stringify(glossary.terms, null, 2)} +\` : ''} MODE: analysis EXPECTED: Complete architecture with: style justification, component diagram, tech stack table, ADRs, data model, security controls, API overview diff --git a/.claude/skills/spec-generator/phases/05-epics-stories.md b/.claude/skills/spec-generator/phases/05-epics-stories.md index bb3d1807..b248d098 100644 --- a/.claude/skills/spec-generator/phases/05-epics-stories.md +++ b/.claude/skills/spec-generator/phases/05-epics-stories.md @@ -26,6 +26,11 @@ const specConfig = JSON.parse(Read(`${workDir}/spec-config.json`)); const productBrief = Read(`${workDir}/product-brief.md`); const requirements = Read(`${workDir}/requirements.md`); const architecture = Read(`${workDir}/architecture.md`); + +let glossary = null; +try { + glossary = JSON.parse(Read(`${workDir}/glossary.json`)); +} catch (e) { /* proceed without */ } ``` ### Step 2: Epic Decomposition via Gemini CLI @@ -69,10 +74,11 @@ TASK: MODE: analysis EXPECTED: Structured output with: Epic list (ID, title, priority, MVP flag), Stories per Epic (ID, user story, AC, size, trace), dependency Mermaid diagram, execution order, MVP definition -CONSTRAINTS: +CONSTRAINTS: - Every Must-have requirement must appear in at least one Story - Stories must be small enough to implement independently (no XL stories in MVP) - Dependencies should be minimized across Epics +\${glossary ? \`- Maintain terminology consistency with glossary: \${glossary.terms.map(t => t.term).join(', ')}\` : ''} " --tool gemini --mode analysis`, run_in_background: true }); diff --git a/.claude/skills/spec-generator/phases/06-5-auto-fix.md b/.claude/skills/spec-generator/phases/06-5-auto-fix.md new file mode 100644 index 00000000..651de53d --- /dev/null +++ b/.claude/skills/spec-generator/phases/06-5-auto-fix.md @@ -0,0 +1,144 @@ +# Phase 6.5: Auto-Fix + +Automatically repair specification issues identified in Phase 6 Readiness Check. + +## Objective + +- Parse readiness-report.md to extract Error and Warning items +- Group issues by originating Phase (2-5) +- Re-generate affected sections with error context injected into CLI prompts +- Re-run Phase 6 validation after fixes + +## Input + +- Dependency: `{workDir}/readiness-report.md` (Phase 6 output) +- Config: `{workDir}/spec-config.json` (with iteration_count) +- All Phase 2-5 outputs + +## Execution Steps + +### Step 1: Parse Readiness Report + +```javascript +const readinessReport = Read(`${workDir}/readiness-report.md`); +const specConfig = JSON.parse(Read(`${workDir}/spec-config.json`)); + +// Load glossary for terminology consistency during fixes +let glossary = null; +try { + glossary = JSON.parse(Read(`${workDir}/glossary.json`)); +} catch (e) { /* proceed without */ } + +// Extract issues from readiness report +// Parse Error and Warning severity items +// Group by originating phase: +// Phase 2 issues: vision, problem statement, scope, personas +// Phase 3 issues: requirements, acceptance criteria, priority, traceability +// Phase 4 issues: architecture, ADRs, tech stack, data model, state machine +// Phase 5 issues: epics, stories, dependencies, MVP scope + +const issuesByPhase = { + 2: [], // product brief issues + 3: [], // requirements issues + 4: [], // architecture issues + 5: [] // epics issues +}; + +// Parse structured issues from report +// Each issue: { severity: "Error"|"Warning", description: "...", location: "file:section" } + +// Map phase numbers to output files +const phaseOutputFile = { + 2: 'product-brief.md', + 3: 'requirements/_index.md', + 4: 'architecture/_index.md', + 5: 'epics/_index.md' +}; +``` + +### Step 2: Fix Affected Phases (Sequential) + +For each phase with issues (in order 2 -> 3 -> 4 -> 5): + +```javascript +for (const [phase, issues] of Object.entries(issuesByPhase)) { + if (issues.length === 0) continue; + + const errorContext = issues.map(i => `[${i.severity}] ${i.description} (at ${i.location})`).join('\n'); + + // Read current phase output + const currentOutput = Read(`${workDir}/${phaseOutputFile[phase]}`); + + Bash({ + command: `ccw cli -p "PURPOSE: Fix specification issues identified in readiness check for Phase ${phase}. +Success: All listed issues resolved while maintaining consistency with other documents. + +CURRENT DOCUMENT: +${currentOutput.slice(0, 5000)} + +ISSUES TO FIX: +${errorContext} + +${glossary ? `GLOSSARY (maintain consistency): +${JSON.stringify(glossary.terms, null, 2)}` : ''} + +TASK: +- Address each listed issue specifically +- Maintain all existing content that is not flagged +- Ensure terminology consistency with glossary +- Preserve YAML frontmatter and cross-references +- Use RFC 2119 keywords for behavioral requirements +- Increment document version number + +MODE: analysis +EXPECTED: Corrected document content addressing all listed issues +CONSTRAINTS: Minimal changes - only fix flagged issues, do not restructure unflagged sections +" --tool gemini --mode analysis`, + run_in_background: true + }); + + // Wait for result, apply fixes to document + // Update document version in frontmatter +} +``` + +### Step 3: Update State + +```javascript +specConfig.phasesCompleted.push({ + phase: 6.5, + name: "auto-fix", + iteration: specConfig.iteration_count, + phases_fixed: Object.keys(issuesByPhase).filter(p => issuesByPhase[p].length > 0), + completed_at: new Date().toISOString() +}); +Write(`${workDir}/spec-config.json`, JSON.stringify(specConfig, null, 2)); +``` + +### Step 4: Re-run Phase 6 Validation + +```javascript +// Re-execute Phase 6: Readiness Check +// This creates a new readiness-report.md +// If still Fail and iteration_count < 2: loop back to Step 1 +// If Pass or iteration_count >= 2: proceed to handoff +``` + +## Output + +- **Updated**: Phase 2-5 documents (only affected ones) +- **Updated**: `spec-config.json` (iteration tracking) +- **Triggers**: Phase 6 re-validation + +## Quality Checklist + +- [ ] All Error-severity issues addressed +- [ ] Warning-severity issues attempted (best effort) +- [ ] Document versions incremented for modified files +- [ ] Terminology consistency maintained +- [ ] Cross-references still valid after fixes +- [ ] Iteration count not exceeded (max 2) + +## Next Phase + +Re-run [Phase 6: Readiness Check](06-readiness-check.md) to validate fixes. diff --git a/.claude/skills/spec-generator/phases/06-readiness-check.md b/.claude/skills/spec-generator/phases/06-readiness-check.md index fd62d2b2..a01942c3 100644 --- a/.claude/skills/spec-generator/phases/06-readiness-check.md +++ b/.claude/skills/spec-generator/phases/06-readiness-check.md @@ -70,8 +70,12 @@ Perform 4-dimension validation: 2. CONSISTENCY (25%): - Terminology uniform across documents? + - Terminology glossary compliance: all core terms used consistently per glossary.json definitions? + - No synonym drift (e.g., "user" vs "client" vs "consumer" for same concept)? - User personas consistent? - Scope consistent (PRD does not exceed brief)? + - Scope containment: PRD requirements do not exceed product brief's defined scope? + - Non-Goals respected: no requirement or story contradicts explicit Non-Goals? - Tech stack references match between architecture and epics? - Score 0-100 with inconsistencies listed @@ -223,6 +227,10 @@ AskUserQuestion({ { label: "Create Issues", description: "Generate issues for each Epic via /issue:new" + }, + { + label: "Iterate & improve", + description: "Re-run failed phases based on readiness report issues (max 2 iterations)" } ] } @@ -386,6 +394,29 @@ if (selection === "Create Issues") { } // If user selects "Other": Export only or return to specific phase + +if (selection === "Iterate & improve") { + // Check iteration count + if (specConfig.iteration_count >= 2) { + // Max iterations reached, force handoff + // Present handoff options again without iterate + return; + } + + // Update iteration tracking + specConfig.iteration_count = (specConfig.iteration_count || 0) + 1; + specConfig.iteration_history.push({ + iteration: specConfig.iteration_count, + timestamp: new Date().toISOString(), + readiness_score: overallScore, + errors_found: errorCount, + phases_to_fix: affectedPhases + }); + Write(`${workDir}/spec-config.json`, JSON.stringify(specConfig, null, 2)); + + // Proceed to Phase 6.5: Auto-Fix + // Read phases/06-5-auto-fix.md and execute +} ``` #### Helper Functions Reference (pseudocode) diff --git a/.claude/skills/spec-generator/specs/document-standards.md b/.claude/skills/spec-generator/specs/document-standards.md index d5efb808..e2d61b92 100644 --- a/.claude/skills/spec-generator/specs/document-standards.md +++ b/.claude/skills/spec-generator/specs/document-standards.md @@ -82,6 +82,7 @@ Examples: | `spec-config.json` | 1 | Session configuration and state | | `discovery-context.json` | 1 | Codebase exploration results (optional) | | `refined-requirements.json` | 1.5 | Confirmed requirements after discussion | +| `glossary.json` | 2 | Terminology glossary for cross-document consistency | | `product-brief.md` | 2 | Product brief document | | `requirements.md` | 3 | PRD document | | `architecture.md` | 4 | Architecture decisions document | @@ -169,6 +170,17 @@ Derived from [REQ-001](requirements.md#req-001). "dimensions": ["string array - 3-5 exploration dimensions"] }, "has_codebase": "boolean", + "spec_type": "service|api|library|platform (required) - type of specification", + "iteration_count": "number (required, default 0) - number of auto-fix iterations completed", + "iteration_history": [ + { + "iteration": "number", + "timestamp": "ISO8601", + "readiness_score": "number (0-100)", + "errors_found": "number", + "phases_fixed": ["number array - phase numbers that were re-generated"] + } + ], "refined_requirements_file": "string (optional) - path to refined-requirements.json", "phasesCompleted": [ { @@ -237,6 +249,34 @@ Derived from [REQ-001](requirements.md#req-001). --- +## glossary.json Schema + +```json +{ + "session_id": "string (required) - matches spec-config.json", + "generated_at": "ISO8601 (required)", + "version": "number (required, default 1) - incremented on updates", + "terms": [ + { + "term": "string (required) - the canonical term", + "definition": "string (required) - concise definition", + "aliases": ["string array - acceptable alternative names"], + "first_defined_in": "string (required) - source document path", + "category": "core|technical|business (required)" + } + ] +} +``` + +### Glossary Usage Rules + +- Terms MUST be defined before first use in any document +- All documents MUST use the canonical term from glossary; aliases are for reference only +- Glossary is generated in Phase 2 and injected into all subsequent phase prompts +- Phase 6 validates glossary compliance across all documents + +--- + ## Validation Checklist - [ ] Every document starts with valid YAML frontmatter @@ -246,3 +286,7 @@ Derived from [REQ-001](requirements.md#req-001). - [ ] Heading hierarchy is correct (no skipped levels) - [ ] Technical identifiers use correct prefixes - [ ] Output files are in the correct directory +- [ ] `glossary.json` created with >= 5 terms +- [ ] `spec_type` field set in spec-config.json +- [ ] All documents use glossary terms consistently +- [ ] Non-Goals section present in product brief (if applicable) diff --git a/.claude/skills/spec-generator/specs/glossary-template.json b/.claude/skills/spec-generator/specs/glossary-template.json new file mode 100644 index 00000000..4a2fd194 --- /dev/null +++ b/.claude/skills/spec-generator/specs/glossary-template.json @@ -0,0 +1,29 @@ +{ + "$schema": "glossary-v1", + "description": "Template for terminology glossary used across spec-generator documents", + "session_id": "", + "generated_at": "", + "version": 1, + "terms": [ + { + "term": "", + "definition": "", + "aliases": [], + "first_defined_in": "product-brief.md", + "category": "core" + } + ], + "_usage_notes": { + "category_values": { + "core": "Domain-specific terms central to the product (e.g., 'Workspace', 'Session')", + "technical": "Technical terms specific to the architecture (e.g., 'gRPC', 'event bus')", + "business": "Business/process terms (e.g., 'Sprint', 'SLA', 'stakeholder')" + }, + "rules": [ + "Terms MUST be defined before first use in any document", + "All documents MUST use the canonical 'term' field consistently", + "Aliases are for reference only - prefer canonical term in all documents", + "Phase 6 validates glossary compliance across all documents" + ] + } +} diff --git a/.claude/skills/spec-generator/specs/quality-gates.md b/.claude/skills/spec-generator/specs/quality-gates.md index 34411fc5..00c8627c 100644 --- a/.claude/skills/spec-generator/specs/quality-gates.md +++ b/.claude/skills/spec-generator/specs/quality-gates.md @@ -111,6 +111,9 @@ Content provides sufficient detail for execution teams. | Success metrics | >= 2 quantifiable metrics | Warning | | Scope boundaries | In-scope and out-of-scope listed | Warning | | Multi-perspective | >= 2 CLI perspectives synthesized | Info | +| Terminology glossary generated | glossary.json created with >= 5 terms | Warning | +| Non-Goals section present | At least 1 non-goal with rationale | Warning | +| Concepts section present | Terminology table in product brief | Warning | ### Phase 3: Requirements (PRD) @@ -122,6 +125,8 @@ Content provides sufficient detail for execution teams. | Non-functional requirements | >= 1 (performance, security, etc.) | Warning | | User stories | >= 1 per Must-have requirement | Warning | | Traceability | Requirements trace to product brief goals | Warning | +| RFC 2119 keywords used | Behavioral requirements use MUST/SHOULD/MAY | Warning | +| Data model defined | Core entities have field-level definitions | Warning | ### Phase 4: Architecture @@ -134,6 +139,12 @@ Content provides sufficient detail for execution teams. | Integration points | External systems/APIs identified | Warning | | Data model | Key entities and relationships described | Warning | | Codebase mapping | Mapped to existing code (if has_codebase) | Info | +| State machine defined | >= 1 lifecycle state diagram (if service/platform type) | Warning | +| Configuration model defined | All config fields with type/default/constraint (if service type) | Warning | +| Error handling strategy | Per-component error classification and recovery | Warning | +| Observability metrics | >= 3 metrics defined (if service/platform type) | Warning | +| Trust model defined | Trust levels documented (if service type) | Info | +| Implementation guidance | Key decisions for implementers listed | Info | ### Phase 5: Epics & Stories @@ -171,6 +182,8 @@ Product Brief goals -> Requirements (each goal has >= 1 requirement) Requirements -> Architecture (each Must requirement has design coverage) Requirements -> Epics (each Must requirement appears in >= 1 story) Architecture ADRs -> Epics (tech choices reflected in implementation stories) +Glossary terms -> All Documents (core terms used consistently) +Non-Goals (Brief) -> Requirements + Epics (no contradictions) ``` ### Consistency Checks @@ -181,6 +194,9 @@ Architecture ADRs -> Epics (tech choices reflected in implementation stories | User personas | Brief + PRD + Epics | Same user names/roles throughout | | Scope | Brief + PRD | PRD scope does not exceed brief scope | | Tech stack | Architecture + Epics | Stories reference correct technologies | +| Glossary compliance | All | Core terms match glossary.json definitions, no synonym drift | +| Scope containment | Brief + PRD | PRD requirements do not introduce scope beyond brief boundaries | +| Non-Goals respected | Brief + PRD + Epics | No requirement/story contradicts explicit Non-Goals | ### Traceability Matrix Format @@ -217,3 +233,23 @@ Architecture ADRs -> Epics (tech choices reflected in implementation stories - Consider additional ADR alternatives - Story estimation hints missing - Mermaid diagrams could be more detailed + +--- + +## Iteration Quality Tracking + +When Phase 6.5 (Auto-Fix) is triggered: + +| Iteration | Expected Improvement | Max Iterations | +|-----------|---------------------|----------------| +| 1st | Fix all Error-severity issues | - | +| 2nd | Fix remaining Warnings, improve scores | Max reached | + +### Iteration Exit Criteria + +| Condition | Action | +|-----------|--------| +| Overall score >= 80% after fix | Pass, proceed to handoff | +| Overall score 60-79% after 2 iterations | Review, proceed with caveats | +| Overall score < 60% after 2 iterations | Fail, manual intervention required | +| No Error-severity issues remaining | Eligible for handoff regardless of score | diff --git a/.claude/skills/spec-generator/templates/architecture-doc.md b/.claude/skills/spec-generator/templates/architecture-doc.md index 5106de03..6a325536 100644 --- a/.claude/skills/spec-generator/templates/architecture-doc.md +++ b/.claude/skills/spec-generator/templates/architecture-doc.md @@ -181,6 +181,125 @@ erDiagram | Scalability | {target} | {how measured} | [ADR-{NNN}](ADR-{NNN}-{slug}.md) | | Reliability | {target} | {how measured} | [ADR-{NNN}](ADR-{NNN}-{slug}.md) | +## State Machine + +{For each core entity with a lifecycle (e.g., Order, Session, Task):} + +### {Entity} Lifecycle + +``` +{ASCII state diagram showing all states, transitions, triggers, and error paths} + + ┌──────────┐ + │ Created │ + └─────┬────┘ + │ start() + ▼ + ┌──────────┐ error ┌──────────┐ + │ Running │ ──────────▶ │ Failed │ + └─────┬────┘ └──────────┘ + │ complete() + ▼ + ┌──────────┐ + │ Completed │ + └──────────┘ +``` + +| From State | Event | To State | Side Effects | Error Handling | +|-----------|-------|----------|-------------|----------------| +| {from} | {event} | {to} | {side_effects} | {error_behavior} | + +## Configuration Model + +### Required Configuration + +| Field | Type | Default | Constraint | Description | +|-------|------|---------|------------|-------------| +| {field_name} | {string/number/boolean/enum} | {default_value} | {validation rule} | {description} | + +### Optional Configuration + +| Field | Type | Default | Constraint | Description | +|-------|------|---------|------------|-------------| +| {field_name} | {type} | {default} | {constraint} | {description} | + +### Environment Variables + +| Variable | Maps To | Required | +|----------|---------|----------| +| {ENV_VAR} | {config_field} | {yes/no} | + +## Error Handling + +### Error Classification + +| Category | Severity | Retry | Example | +|----------|----------|-------|---------| +| Transient | Low | Yes, with backoff | Network timeout, rate limit | +| Permanent | High | No | Invalid configuration, auth failure | +| Degraded | Medium | Partial | Dependency unavailable, fallback active | + +### Per-Component Error Strategy + +| Component | Error Scenario | Behavior | Recovery | +|-----------|---------------|----------|----------| +| {component} | {scenario} | {MUST/SHOULD behavior} | {recovery strategy} | + +## Observability + +### Metrics + +| Metric Name | Type | Labels | Description | +|-------------|------|--------|-------------| +| {metric_name} | {counter/gauge/histogram} | {label1, label2} | {what it measures} | + +### Logging + +| Event | Level | Fields | Description | +|-------|-------|--------|-------------| +| {event_name} | {INFO/WARN/ERROR} | {structured fields} | {when logged} | + +### Health Checks + +| Check | Endpoint | Interval | Failure Action | +|-------|----------|----------|----------------| +| {check_name} | {/health/xxx} | {duration} | {action on failure} | + +## Trust & Safety + +### Trust Levels + +| Level | Description | Approval Required | Allowed Operations | +|-------|-------------|-------------------|-------------------| +| High Trust | {description} | None | {operations} | +| Standard | {description} | {approval type} | {operations} | +| Low Trust | {description} | {approval type} | {operations} | + +### Security Controls + +{Detailed security controls beyond the basic auth covered in Security Architecture} + +## Implementation Guidance + +### Key Decisions for Implementers + +| Decision | Options | Recommendation | Rationale | +|----------|---------|---------------|-----------| +| {decision_area} | {option_1, option_2} | {recommended} | {why} | + +### Implementation Order + +1. {component/module 1}: {why first} +2. {component/module 2}: {depends on #1} + +### Testing Strategy + +| Layer | Scope | Tools | Coverage Target | +|-------|-------|-------|-----------------| +| Unit | {scope} | {tools} | {target} | +| Integration | {scope} | {tools} | {target} | +| E2E | {scope} | {tools} | {target} | + ## Risks & Mitigations | Risk | Impact | Probability | Mitigation | diff --git a/.claude/skills/spec-generator/templates/epics-template.md b/.claude/skills/spec-generator/templates/epics-template.md index 939d933c..a05e67fc 100644 --- a/.claude/skills/spec-generator/templates/epics-template.md +++ b/.claude/skills/spec-generator/templates/epics-template.md @@ -101,6 +101,19 @@ graph LR |------|---------------|------------| | {risk description} | [EPIC-{NNN}](EPIC-{NNN}-{slug}.md) | {mitigation} | +## Versioning & Changelog + +### Version Strategy +- **Versioning Scheme**: {semver/calver/custom} +- **Breaking Change Definition**: {what constitutes a breaking change} +- **Deprecation Policy**: {how deprecated features are handled} + +### Changelog + +| Version | Date | Type | Description | +|---------|------|------|-------------| +| {version} | {date} | {Added/Changed/Fixed/Removed} | {description} | + ## Open Questions - [ ] {question about scope or implementation 1} diff --git a/.claude/skills/spec-generator/templates/product-brief.md b/.claude/skills/spec-generator/templates/product-brief.md index ffbdf437..05b50440 100644 --- a/.claude/skills/spec-generator/templates/product-brief.md +++ b/.claude/skills/spec-generator/templates/product-brief.md @@ -30,6 +30,15 @@ dependencies: {executive_summary - 2-3 sentences capturing the essence of the product/feature} +## Concepts & Terminology + +| Term | Definition | Aliases | +|------|-----------|---------| +| {term_1} | {definition} | {comma-separated aliases if any} | +| {term_2} | {definition} | | + +{Note: All documents in this specification MUST use these terms consistently.} + ## Vision {vision_statement - clear, aspirational 1-3 sentence statement of what success looks like} @@ -70,6 +79,15 @@ dependencies: - {explicitly excluded item 1} - {explicitly excluded item 2} +### Non-Goals + +{Explicit list of things this project will NOT do, with rationale for each:} + +| Non-Goal | Rationale | +|----------|-----------| +| {non_goal_1} | {why this is explicitly excluded} | +| {non_goal_2} | {why this is explicitly excluded} | + ### Assumptions - {key assumption 1} - {key assumption 2} @@ -130,4 +148,6 @@ dependencies: | `{product_name}` | Seed analysis | Product/feature name | | `{executive_summary}` | CLI synthesis | 2-3 sentence summary | | `{vision_statement}` | CLI product perspective | Aspirational vision | +| `{term_1}`, `{term_2}` | CLI synthesis | Domain terms with definitions and optional aliases | +| `{non_goal_1}`, `{non_goal_2}` | CLI synthesis | Explicit exclusions with rationale | | All `{...}` fields | CLI analysis outputs | Filled from multi-perspective analysis | diff --git a/.claude/skills/spec-generator/templates/profiles/api-profile.md b/.claude/skills/spec-generator/templates/profiles/api-profile.md new file mode 100644 index 00000000..fe274449 --- /dev/null +++ b/.claude/skills/spec-generator/templates/profiles/api-profile.md @@ -0,0 +1,27 @@ +# API Spec Profile + +Defines additional required sections for API-type specifications. + +## Required Sections (in addition to base template) + +### In Architecture Document +- **Endpoint Definition**: MUST list all endpoints with method, path, auth, request/response schema +- **Authentication Model**: MUST define auth mechanism (OAuth2/JWT/API Key), token lifecycle +- **Rate Limiting**: MUST define rate limits per tier/endpoint, throttling behavior +- **Error Codes**: MUST define error response format, standard error codes with descriptions +- **API Versioning**: MUST define versioning strategy (URL/header/query), deprecation policy +- **Pagination**: SHOULD define pagination strategy for list endpoints +- **Idempotency**: SHOULD define idempotency requirements for write operations + +### In Requirements Document +- **Endpoint Acceptance Criteria**: Each requirement SHOULD map to specific endpoints +- **SLA Definitions**: MUST define response time, availability targets per endpoint tier + +### Quality Gate Additions +| Check | Criteria | Severity | +|-------|----------|----------| +| Endpoints documented | All endpoints with method + path | Error | +| Auth model defined | Authentication mechanism specified | Error | +| Error codes defined | Standard error format + codes | Warning | +| Rate limits defined | Per-endpoint or per-tier limits | Warning | +| API versioning strategy | Versioning approach specified | Warning | diff --git a/.claude/skills/spec-generator/templates/profiles/library-profile.md b/.claude/skills/spec-generator/templates/profiles/library-profile.md new file mode 100644 index 00000000..78189362 --- /dev/null +++ b/.claude/skills/spec-generator/templates/profiles/library-profile.md @@ -0,0 +1,25 @@ +# Library Spec Profile + +Defines additional required sections for library/SDK-type specifications. + +## Required Sections (in addition to base template) + +### In Architecture Document +- **Public API Surface**: MUST define all public interfaces with signatures, parameters, return types +- **Usage Examples**: MUST provide >= 3 code examples showing common usage patterns +- **Compatibility Matrix**: MUST define supported language versions, runtime environments +- **Dependency Policy**: MUST define transitive dependency policy, version constraints +- **Extension Points**: SHOULD define plugin/extension mechanisms if applicable +- **Bundle Size**: SHOULD define target bundle size and tree-shaking strategy + +### In Requirements Document +- **API Ergonomics**: Requirements SHOULD address developer experience and API consistency +- **Error Reporting**: MUST define error types, messages, and recovery hints for consumers + +### Quality Gate Additions +| Check | Criteria | Severity | +|-------|----------|----------| +| Public API documented | All public interfaces with types | Error | +| Usage examples | >= 3 working examples | Warning | +| Compatibility matrix | Supported environments listed | Warning | +| Dependency policy | Transitive deps strategy defined | Info | diff --git a/.claude/skills/spec-generator/templates/profiles/service-profile.md b/.claude/skills/spec-generator/templates/profiles/service-profile.md new file mode 100644 index 00000000..9fe915a1 --- /dev/null +++ b/.claude/skills/spec-generator/templates/profiles/service-profile.md @@ -0,0 +1,28 @@ +# Service Spec Profile + +Defines additional required sections for service-type specifications. + +## Required Sections (in addition to base template) + +### In Architecture Document +- **Concepts & Terminology**: MUST define all domain terms with consistent aliases +- **State Machine**: MUST include ASCII state diagram for each entity with a lifecycle +- **Configuration Model**: MUST define all configurable fields with types, defaults, constraints +- **Error Handling**: MUST define per-component error classification and recovery strategies +- **Observability**: MUST define >= 3 metrics, structured log format, health check endpoints +- **Trust & Safety**: SHOULD define trust levels and approval matrix +- **Graceful Shutdown**: MUST describe shutdown sequence and cleanup procedures +- **Implementation Guidance**: SHOULD provide implementation order and key decisions + +### In Requirements Document +- **Behavioral Constraints**: MUST use RFC 2119 keywords (MUST/SHOULD/MAY) for all requirements +- **Data Model**: MUST define core entities with field-level detail (type, constraint, relation) + +### Quality Gate Additions +| Check | Criteria | Severity | +|-------|----------|----------| +| State machine present | >= 1 lifecycle state diagram | Error | +| Configuration model | All config fields documented | Warning | +| Observability metrics | >= 3 metrics defined | Warning | +| Error handling defined | Per-component strategy | Warning | +| RFC keywords used | Behavioral requirements use MUST/SHOULD/MAY | Warning | diff --git a/.claude/skills/team-ux-improve/SKILL.md b/.claude/skills/team-ux-improve/SKILL.md index 9ca38800..5c595d74 100644 --- a/.claude/skills/team-ux-improve/SKILL.md +++ b/.claude/skills/team-ux-improve/SKILL.md @@ -264,9 +264,15 @@ AskUserQuestion({ │ └── test-report.md ← tester output ├── explorations/ ← explorer cache │ └── cache-index.json -└── wisdom/ ← Knowledge base - ├── ui-patterns.md - └── state-management.md +└── wisdom/ ← Session knowledge base + ├── contributions/ ← Worker contributions (write-only for workers) + ├── principles/ ← Core principles + │ └── general-ux.md + ├── patterns/ ← Solution patterns + │ ├── ui-feedback.md + │ └── state-management.md + └── anti-patterns/ ← Issues to avoid + └── common-ux-pitfalls.md ``` ## Error Handling diff --git a/.claude/skills/team-ux-improve/role-specs/designer.md b/.claude/skills/team-ux-improve/role-specs/designer.md index 2af86395..6d541a46 100644 --- a/.claude/skills/team-ux-improve/role-specs/designer.md +++ b/.claude/skills/team-ux-improve/role-specs/designer.md @@ -22,6 +22,13 @@ Design feedback mechanisms (loading/error/success states) and state management p | React | useState, useRef | onClick, onChange | | Vue | ref, reactive | @click, @change | +### Wisdom Input + +1. Read `/wisdom/patterns/ui-feedback.md` for established feedback design patterns +2. Read `/wisdom/patterns/state-management.md` for state handling patterns +3. Read `/wisdom/principles/general-ux.md` for UX design principles +4. Apply patterns when designing solutions for identified issues + ### Complex Design (use CLI) For complex multi-component solutions: @@ -166,6 +173,13 @@ const handleUpload = async (event: React.FormEvent) => { ``` 2. Write guide to `/artifacts/design-guide.md` + +### Wisdom Contribution + +If novel design patterns created: +1. Write new patterns to `/wisdom/contributions/designer-pattern-.md` +2. Format: Problem context, solution design, implementation hints, trade-offs + 3. Share state via team_msg: ``` team_msg(operation="log", session_id=, from="designer", diff --git a/.claude/skills/team-ux-improve/role-specs/diagnoser.md b/.claude/skills/team-ux-improve/role-specs/diagnoser.md index d8d54ce3..c24920bf 100644 --- a/.claude/skills/team-ux-improve/role-specs/diagnoser.md +++ b/.claude/skills/team-ux-improve/role-specs/diagnoser.md @@ -14,6 +14,13 @@ Diagnose root causes of UI issues: state management problems, event binding fail 1. Load scan report from `/artifacts/scan-report.md` 2. Load scanner state via `team_msg(operation="get_state", session_id=, role="scanner")` + +### Wisdom Input + +1. Read `/wisdom/patterns/ui-feedback.md` and `/wisdom/patterns/state-management.md` if available +2. Use patterns to identify root causes of UI interaction issues +3. Reference `/wisdom/anti-patterns/common-ux-pitfalls.md` for common causes + 3. Assess issue complexity: | Complexity | Criteria | Strategy | @@ -82,6 +89,13 @@ For each issue from scan report: ``` 2. Write report to `/artifacts/diagnosis.md` + +### Wisdom Contribution + +If new root cause patterns discovered: +1. Write diagnosis patterns to `/wisdom/contributions/diagnoser-patterns-.md` +2. Format: Symptom, root cause, detection method, fix approach + 3. Share state via team_msg: ``` team_msg(operation="log", session_id=, from="diagnoser", diff --git a/.claude/skills/team-ux-improve/role-specs/explorer.md b/.claude/skills/team-ux-improve/role-specs/explorer.md index d3df9c16..dc24702f 100644 --- a/.claude/skills/team-ux-improve/role-specs/explorer.md +++ b/.claude/skills/team-ux-improve/role-specs/explorer.md @@ -15,6 +15,12 @@ Explore codebase for UI component patterns, state management conventions, and fr 1. Parse exploration request from task description 2. Determine file patterns based on framework: +### Wisdom Input + +1. Read `/wisdom/patterns/ui-feedback.md` and `/wisdom/patterns/state-management.md` if available +2. Use known patterns as reference when exploring codebase for component structures +3. Check `/wisdom/anti-patterns/common-ux-pitfalls.md` to identify problematic patterns during exploration + | Framework | Patterns | |-----------|----------| | React | `**/*.tsx`, `**/*.jsx`, `**/use*.ts`, `**/store*.ts` | @@ -80,6 +86,18 @@ For each dimension, collect: 2. Cache results to `/explorations/cache-index.json` 3. Write summary to `/explorations/exploration-summary.md` + +### Wisdom Contribution + +If new component patterns or framework conventions discovered: +1. Write pattern summaries to `/wisdom/contributions/explorer-patterns-.md` +2. Format: + - Pattern Name: Descriptive name + - Framework: React/Vue/etc. + - Use Case: When to apply this pattern + - Code Example: Representative snippet + - Adoption: How widely used in codebase + 4. Share state via team_msg: ``` team_msg(operation="log", session_id=, from="explorer", diff --git a/.claude/skills/team-ux-improve/role-specs/implementer.md b/.claude/skills/team-ux-improve/role-specs/implementer.md index 1e6710bf..6fd6c8d6 100644 --- a/.claude/skills/team-ux-improve/role-specs/implementer.md +++ b/.claude/skills/team-ux-improve/role-specs/implementer.md @@ -15,7 +15,12 @@ Generate executable fix code with proper state management, event handling, and U 1. Extract session path from task description 2. Read design guide: `/artifacts/design-guide.md` 3. Extract implementation tasks from design guide -4. Load framework conventions from wisdom files (if available) +4. **Wisdom Input**: + - Read `/wisdom/patterns/state-management.md` for state handling patterns + - Read `/wisdom/patterns/ui-feedback.md` for UI feedback implementation patterns + - Read `/wisdom/principles/general-ux.md` for implementation principles + - Load framework-specific conventions if available + - Apply these patterns and principles when generating code to ensure consistency and quality 5. **For inner loop**: Load context_accumulator from prior IMPL tasks ### Context Accumulator (Inner Loop) @@ -123,3 +128,37 @@ team_msg(operation="log", session_id=, from="implementer", validation_passed: true }) ``` + +### Wisdom Contribution + +If reusable code patterns or snippets created: +1. Write code snippets to `/wisdom/contributions/implementer-snippets-.md` +2. Format: Use case, code snippet with comments, framework compatibility notes + +Example contribution format: +```markdown +# Implementer Snippets - + +## Loading State Pattern (React) + +### Use Case +Async operations requiring loading indicator + +### Code Snippet +```tsx +const [isLoading, setIsLoading] = useState(false); + +const handleAsyncAction = async () => { + setIsLoading(true); + try { + await performAction(); + } finally { + setIsLoading(false); + } +}; +``` + +### Framework Compatibility +- React 16.8+ (hooks) +- Next.js compatible +``` diff --git a/.claude/skills/team-ux-improve/role-specs/scanner.md b/.claude/skills/team-ux-improve/role-specs/scanner.md index 7387dea5..31fa8917 100644 --- a/.claude/skills/team-ux-improve/role-specs/scanner.md +++ b/.claude/skills/team-ux-improve/role-specs/scanner.md @@ -32,6 +32,12 @@ Scan UI components to identify interaction issues: unresponsive buttons, missing - React: `**/*.tsx`, `**/*.jsx`, `**/use*.ts` - Vue: `**/*.vue`, `**/composables/*.ts` +### Wisdom Input + +1. Read `/wisdom/anti-patterns/common-ux-pitfalls.md` if available +2. Use anti-patterns to identify known UX issues during scanning +3. Check `/wisdom/patterns/ui-feedback.md` for expected feedback patterns + ### Complex Analysis (use CLI) For large projects with many components: @@ -103,3 +109,9 @@ For each component file: scanned_files: }) ``` + +### Wisdom Contribution + +If novel UX issues discovered that aren't in anti-patterns: +1. Write findings to `/wisdom/contributions/scanner-issues-.md` +2. Format: Issue description, detection criteria, affected components diff --git a/.claude/skills/team-ux-improve/role-specs/tester.md b/.claude/skills/team-ux-improve/role-specs/tester.md index 39b302fb..0233edb2 100644 --- a/.claude/skills/team-ux-improve/role-specs/tester.md +++ b/.claude/skills/team-ux-improve/role-specs/tester.md @@ -29,6 +29,12 @@ Generate and run tests to verify fixes (loading states, error handling, state up 3. Load test strategy from design guide +### Wisdom Input + +1. Read `/wisdom/anti-patterns/common-ux-pitfalls.md` for common issues to test +2. Read `/wisdom/patterns/ui-feedback.md` for expected feedback behaviors to verify +3. Use wisdom to design comprehensive test cases covering known edge cases + ## Phase 3: Test Generation & Execution ### Test Generation @@ -96,6 +102,12 @@ Iterative test-fix cycle (max 5 iterations): ## Phase 4: Test Report +### Wisdom Contribution + +If new edge cases or test patterns discovered: +1. Write test findings to `/wisdom/contributions/tester-edge-cases-.md` +2. Format: Edge case description, test scenario, expected behavior, actual behavior + Generate test report: ```markdown diff --git a/.claude/skills/team-ux-improve/roles/coordinator/role.md b/.claude/skills/team-ux-improve/roles/coordinator/role.md index 3e1efa46..61c7427c 100644 --- a/.claude/skills/team-ux-improve/roles/coordinator/role.md +++ b/.claude/skills/team-ux-improve/roles/coordinator/role.md @@ -114,6 +114,23 @@ For callback/check/resume: load `commands/monitor.md` and execute handler, then ``` 3. TeamCreate(team_name="ux-improve") 4. Initialize meta.json with pipeline config: + +### Wisdom Initialization + +After creating session directory, initialize wisdom from skill's permanent knowledge base: + +1. Copy `.claude/skills/team-ux-improve/wisdom/` contents to `/wisdom/` +2. Create `/wisdom/contributions/` directory if not exists +3. This provides workers with initial patterns, principles, and anti-patterns + +Example: +```bash +# Copy permanent wisdom to session +cp -r .claude/skills/team-ux-improve/wisdom/* /wisdom/ +mkdir -p /wisdom/contributions/ +``` + +5. Initialize meta.json with pipeline config: ``` team_msg(operation="log", session_id=, from="coordinator", type="state_update", @@ -182,6 +199,32 @@ Execute built-in Phase 1 (task discovery) -> role-spec Phase 2-4 -> built-in Pha - artifacts/design-guide.md - artifacts/fixes/ - artifacts/test-report.md + +### Wisdom Consolidation + +Before pipeline completion, handle knowledge contributions: + +1. Check if `/wisdom/contributions/` has any files +2. If contributions exist: + - Summarize contributions for user review + - Use AskUserQuestion to ask if user wants to merge valuable contributions back to permanent wisdom + - If approved, copy selected contributions to `.claude/skills/team-ux-improve/wisdom/` (classify into patterns/, anti-patterns/, etc.) + +Example interaction: +``` +AskUserQuestion({ + questions: [{ + question: "Workers contributed new knowledge during this session. Merge to permanent wisdom?", + header: "Knowledge", + options: [ + { label: "Merge All", description: "Add all contributions to permanent wisdom" }, + { label: "Review First", description: "Show contributions before deciding" }, + { label: "Skip", description: "Keep contributions in session only" } + ] + }] +}) +``` + 3. **Completion Action** (interactive mode): ``` diff --git a/.claude/skills/team-ux-improve/wisdom/anti-patterns/common-ux-pitfalls.md b/.claude/skills/team-ux-improve/wisdom/anti-patterns/common-ux-pitfalls.md new file mode 100644 index 00000000..ee86ebe7 --- /dev/null +++ b/.claude/skills/team-ux-improve/wisdom/anti-patterns/common-ux-pitfalls.md @@ -0,0 +1,17 @@ +# Common UX Pitfalls + +## Interaction Issues +- Buttons without loading states during async operations +- Missing error handling with user feedback +- State changes without visual updates +- Double-click vulnerabilities + +## State Issues +- Stale data after mutations +- Race conditions in async operations +- Missing rollback for failed optimistic updates + +## Feedback Issues +- Silent failures without user notification +- Generic error messages without actionable guidance +- Missing confirmation for destructive actions diff --git a/.claude/skills/team-ux-improve/wisdom/contributions/.gitkeep b/.claude/skills/team-ux-improve/wisdom/contributions/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.claude/skills/team-ux-improve/wisdom/patterns/state-management.md b/.claude/skills/team-ux-improve/wisdom/patterns/state-management.md new file mode 100644 index 00000000..2c2ed9e8 --- /dev/null +++ b/.claude/skills/team-ux-improve/wisdom/patterns/state-management.md @@ -0,0 +1,14 @@ +# State Management Patterns + +## Local Component State +- Use for UI-only state (open/closed, hover, focus) +- Keep close to where it's used + +## Shared State +- Lift state to lowest common ancestor +- Use context or state management library for deep trees + +## Async State +- Track loading, error, and success states +- Handle race conditions with request cancellation +- Implement retry logic with exponential backoff diff --git a/.claude/skills/team-ux-improve/wisdom/patterns/ui-feedback.md b/.claude/skills/team-ux-improve/wisdom/patterns/ui-feedback.md new file mode 100644 index 00000000..c7b67921 --- /dev/null +++ b/.claude/skills/team-ux-improve/wisdom/patterns/ui-feedback.md @@ -0,0 +1,16 @@ +# UI Feedback Patterns + +## Loading States +- Use skeleton loaders for content areas +- Disable buttons during async operations +- Show progress indicators for long operations + +## Error Handling +- Display errors inline when possible +- Provide actionable error messages +- Allow retry for transient failures + +## Success Feedback +- Toast notifications for non-critical successes +- Inline confirmation for critical actions +- Auto-dismiss non-critical notifications diff --git a/.claude/skills/team-ux-improve/wisdom/principles/general-ux.md b/.claude/skills/team-ux-improve/wisdom/principles/general-ux.md new file mode 100644 index 00000000..b51697d8 --- /dev/null +++ b/.claude/skills/team-ux-improve/wisdom/principles/general-ux.md @@ -0,0 +1,16 @@ +# General UX Principles + +## Feedback & Responsiveness +- Every user action should have immediate visual feedback +- Loading states must be shown for operations >200ms +- Success/error states should be clearly communicated + +## State Management +- UI state should reflect the underlying data state +- Optimistic updates should have rollback mechanisms +- State changes should be atomic and predictable + +## Accessibility +- Interactive elements must be keyboard accessible +- Color should not be the only indicator of state +- Focus states must be visible diff --git a/SPEC.md b/SPEC.md new file mode 100644 index 00000000..47d6abe7 --- /dev/null +++ b/SPEC.md @@ -0,0 +1,2110 @@ +# Symphony Service Specification + +Status: Draft v1 (language-agnostic) + +Purpose: Define a service that orchestrates coding agents to get project work done. + +## 1. Problem Statement + +Symphony is a long-running automation service that continuously reads work from an issue tracker +(Linear in this specification version), creates an isolated workspace for each issue, and runs a +coding agent session for that issue inside the workspace. + +The service solves four operational problems: + +- It turns issue execution into a repeatable daemon workflow instead of manual scripts. +- It isolates agent execution in per-issue workspaces so agent commands run only inside per-issue + workspace directories. +- It keeps the workflow policy in-repo (`WORKFLOW.md`) so teams version the agent prompt and runtime + settings with their code. +- It provides enough observability to operate and debug multiple concurrent agent runs. + +Implementations are expected to document their trust and safety posture explicitly. This +specification does not require a single approval, sandbox, or operator-confirmation policy; some +implementations may target trusted environments with a high-trust configuration, while others may +require stricter approvals or sandboxing. + +Important boundary: + +- Symphony is a scheduler/runner and tracker reader. +- Ticket writes (state transitions, comments, PR links) are typically performed by the coding agent + using tools available in the workflow/runtime environment. +- A successful run may end at a workflow-defined handoff state (for example `Human Review`), not + necessarily `Done`. + +## 2. Goals and Non-Goals + +### 2.1 Goals + +- Poll the issue tracker on a fixed cadence and dispatch work with bounded concurrency. +- Maintain a single authoritative orchestrator state for dispatch, retries, and reconciliation. +- Create deterministic per-issue workspaces and preserve them across runs. +- Stop active runs when issue state changes make them ineligible. +- Recover from transient failures with exponential backoff. +- Load runtime behavior from a repository-owned `WORKFLOW.md` contract. +- Expose operator-visible observability (at minimum structured logs). +- Support restart recovery without requiring a persistent database. + +### 2.2 Non-Goals + +- Rich web UI or multi-tenant control plane. +- Prescribing a specific dashboard or terminal UI implementation. +- General-purpose workflow engine or distributed job scheduler. +- Built-in business logic for how to edit tickets, PRs, or comments. (That logic lives in the + workflow prompt and agent tooling.) +- Mandating strong sandbox controls beyond what the coding agent and host OS provide. +- Mandating a single default approval, sandbox, or operator-confirmation posture for all + implementations. + +## 3. System Overview + +### 3.1 Main Components + +1. `Workflow Loader` + - Reads `WORKFLOW.md`. + - Parses YAML front matter and prompt body. + - Returns `{config, prompt_template}`. + +2. `Config Layer` + - Exposes typed getters for workflow config values. + - Applies defaults and environment variable indirection. + - Performs validation used by the orchestrator before dispatch. + +3. `Issue Tracker Client` + - Fetches candidate issues in active states. + - Fetches current states for specific issue IDs (reconciliation). + - Fetches terminal-state issues during startup cleanup. + - Normalizes tracker payloads into a stable issue model. + +4. `Orchestrator` + - Owns the poll tick. + - Owns the in-memory runtime state. + - Decides which issues to dispatch, retry, stop, or release. + - Tracks session metrics and retry queue state. + +5. `Workspace Manager` + - Maps issue identifiers to workspace paths. + - Ensures per-issue workspace directories exist. + - Runs workspace lifecycle hooks. + - Cleans workspaces for terminal issues. + +6. `Agent Runner` + - Creates workspace. + - Builds prompt from issue + workflow template. + - Launches the coding agent app-server client. + - Streams agent updates back to the orchestrator. + +7. `Status Surface` (optional) + - Presents human-readable runtime status (for example terminal output, dashboard, or other + operator-facing view). + +8. `Logging` + - Emits structured runtime logs to one or more configured sinks. + +### 3.2 Abstraction Levels + +Symphony is easiest to port when kept in these layers: + +1. `Policy Layer` (repo-defined) + - `WORKFLOW.md` prompt body. + - Team-specific rules for ticket handling, validation, and handoff. + +2. `Configuration Layer` (typed getters) + - Parses front matter into typed runtime settings. + - Handles defaults, environment tokens, and path normalization. + +3. `Coordination Layer` (orchestrator) + - Polling loop, issue eligibility, concurrency, retries, reconciliation. + +4. `Execution Layer` (workspace + agent subprocess) + - Filesystem lifecycle, workspace preparation, coding-agent protocol. + +5. `Integration Layer` (Linear adapter) + - API calls and normalization for tracker data. + +6. `Observability Layer` (logs + optional status surface) + - Operator visibility into orchestrator and agent behavior. + +### 3.3 External Dependencies + +- Issue tracker API (Linear for `tracker.kind: linear` in this specification version). +- Local filesystem for workspaces and logs. +- Optional workspace population tooling (for example Git CLI, if used). +- Coding-agent executable that supports JSON-RPC-like app-server mode over stdio. +- Host environment authentication for the issue tracker and coding agent. + +## 4. Core Domain Model + +### 4.1 Entities + +#### 4.1.1 Issue + +Normalized issue record used by orchestration, prompt rendering, and observability output. + +Fields: + +- `id` (string) + - Stable tracker-internal ID. +- `identifier` (string) + - Human-readable ticket key (example: `ABC-123`). +- `title` (string) +- `description` (string or null) +- `priority` (integer or null) + - Lower numbers are higher priority in dispatch sorting. +- `state` (string) + - Current tracker state name. +- `branch_name` (string or null) + - Tracker-provided branch metadata if available. +- `url` (string or null) +- `labels` (list of strings) + - Normalized to lowercase. +- `blocked_by` (list of blocker refs) + - Each blocker ref contains: + - `id` (string or null) + - `identifier` (string or null) + - `state` (string or null) +- `created_at` (timestamp or null) +- `updated_at` (timestamp or null) + +#### 4.1.2 Workflow Definition + +Parsed `WORKFLOW.md` payload: + +- `config` (map) + - YAML front matter root object. +- `prompt_template` (string) + - Markdown body after front matter, trimmed. + +#### 4.1.3 Service Config (Typed View) + +Typed runtime values derived from `WorkflowDefinition.config` plus environment resolution. + +Examples: + +- poll interval +- workspace root +- active and terminal issue states +- concurrency limits +- coding-agent executable/args/timeouts +- workspace hooks + +#### 4.1.4 Workspace + +Filesystem workspace assigned to one issue identifier. + +Fields (logical): + +- `path` (workspace path; current runtime typically uses absolute paths, but relative roots are + possible if configured without path separators) +- `workspace_key` (sanitized issue identifier) +- `created_now` (boolean, used to gate `after_create` hook) + +#### 4.1.5 Run Attempt + +One execution attempt for one issue. + +Fields (logical): + +- `issue_id` +- `issue_identifier` +- `attempt` (integer or null, `null` for first run, `>=1` for retries/continuation) +- `workspace_path` +- `started_at` +- `status` +- `error` (optional) + +#### 4.1.6 Live Session (Agent Session Metadata) + +State tracked while a coding-agent subprocess is running. + +Fields: + +- `session_id` (string, `-`) +- `thread_id` (string) +- `turn_id` (string) +- `codex_app_server_pid` (string or null) +- `last_codex_event` (string/enum or null) +- `last_codex_timestamp` (timestamp or null) +- `last_codex_message` (summarized payload) +- `codex_input_tokens` (integer) +- `codex_output_tokens` (integer) +- `codex_total_tokens` (integer) +- `last_reported_input_tokens` (integer) +- `last_reported_output_tokens` (integer) +- `last_reported_total_tokens` (integer) +- `turn_count` (integer) + - Number of coding-agent turns started within the current worker lifetime. + +#### 4.1.7 Retry Entry + +Scheduled retry state for an issue. + +Fields: + +- `issue_id` +- `identifier` (best-effort human ID for status surfaces/logs) +- `attempt` (integer, 1-based for retry queue) +- `due_at_ms` (monotonic clock timestamp) +- `timer_handle` (runtime-specific timer reference) +- `error` (string or null) + +#### 4.1.8 Orchestrator Runtime State + +Single authoritative in-memory state owned by the orchestrator. + +Fields: + +- `poll_interval_ms` (current effective poll interval) +- `max_concurrent_agents` (current effective global concurrency limit) +- `running` (map `issue_id -> running entry`) +- `claimed` (set of issue IDs reserved/running/retrying) +- `retry_attempts` (map `issue_id -> RetryEntry`) +- `completed` (set of issue IDs; bookkeeping only, not dispatch gating) +- `codex_totals` (aggregate tokens + runtime seconds) +- `codex_rate_limits` (latest rate-limit snapshot from agent events) + +### 4.2 Stable Identifiers and Normalization Rules + +- `Issue ID` + - Use for tracker lookups and internal map keys. +- `Issue Identifier` + - Use for human-readable logs and workspace naming. +- `Workspace Key` + - Derive from `issue.identifier` by replacing any character not in `[A-Za-z0-9._-]` with `_`. + - Use the sanitized value for the workspace directory name. +- `Normalized Issue State` + - Compare states after `trim` + `lowercase`. +- `Session ID` + - Compose from coding-agent `thread_id` and `turn_id` as `-`. + +## 5. Workflow Specification (Repository Contract) + +### 5.1 File Discovery and Path Resolution + +Workflow file path precedence: + +1. Explicit application/runtime setting (set by CLI startup path). +2. Default: `WORKFLOW.md` in the current process working directory. + +Loader behavior: + +- If the file cannot be read, return `missing_workflow_file` error. +- The workflow file is expected to be repository-owned and version-controlled. + +### 5.2 File Format + +`WORKFLOW.md` is a Markdown file with optional YAML front matter. + +Design note: + +- `WORKFLOW.md` should be self-contained enough to describe and run different workflows (prompt, + runtime settings, hooks, and tracker selection/config) without requiring out-of-band + service-specific configuration. + +Parsing rules: + +- If file starts with `---`, parse lines until the next `---` as YAML front matter. +- Remaining lines become the prompt body. +- If front matter is absent, treat the entire file as prompt body and use an empty config map. +- YAML front matter must decode to a map/object; non-map YAML is an error. +- Prompt body is trimmed before use. + +Returned workflow object: + +- `config`: front matter root object (not nested under a `config` key). +- `prompt_template`: trimmed Markdown body. + +### 5.3 Front Matter Schema + +Top-level keys: + +- `tracker` +- `polling` +- `workspace` +- `hooks` +- `agent` +- `codex` + +Unknown keys should be ignored for forward compatibility. + +Note: + +- The workflow front matter is extensible. Optional extensions may define additional top-level keys + (for example `server`) without changing the core schema above. +- Extensions should document their field schema, defaults, validation rules, and whether changes + apply dynamically or require restart. +- Common extension: `server.port` (integer) enables the optional HTTP server described in Section + 13.7. + +#### 5.3.1 `tracker` (object) + +Fields: + +- `kind` (string) + - Required for dispatch. + - Current supported value: `linear` +- `endpoint` (string) + - Default for `tracker.kind == "linear"`: `https://api.linear.app/graphql` +- `api_key` (string) + - May be a literal token or `$VAR_NAME`. + - Canonical environment variable for `tracker.kind == "linear"`: `LINEAR_API_KEY`. + - If `$VAR_NAME` resolves to an empty string, treat the key as missing. +- `project_slug` (string) + - Required for dispatch when `tracker.kind == "linear"`. +- `active_states` (list of strings or comma-separated string) + - Default: `Todo`, `In Progress` +- `terminal_states` (list of strings or comma-separated string) + - Default: `Closed`, `Cancelled`, `Canceled`, `Duplicate`, `Done` + +#### 5.3.2 `polling` (object) + +Fields: + +- `interval_ms` (integer or string integer) + - Default: `30000` + - Changes should be re-applied at runtime and affect future tick scheduling without restart. + +#### 5.3.3 `workspace` (object) + +Fields: + +- `root` (path string or `$VAR`) + - Default: `/symphony_workspaces` + - `~` and strings containing path separators are expanded. + - Bare strings without path separators are preserved as-is (relative roots are allowed but + discouraged). + +#### 5.3.4 `hooks` (object) + +Fields: + +- `after_create` (multiline shell script string, optional) + - Runs only when a workspace directory is newly created. + - Failure aborts workspace creation. +- `before_run` (multiline shell script string, optional) + - Runs before each agent attempt after workspace preparation and before launching the coding + agent. + - Failure aborts the current attempt. +- `after_run` (multiline shell script string, optional) + - Runs after each agent attempt (success, failure, timeout, or cancellation) once the workspace + exists. + - Failure is logged but ignored. +- `before_remove` (multiline shell script string, optional) + - Runs before workspace deletion if the directory exists. + - Failure is logged but ignored; cleanup still proceeds. +- `timeout_ms` (integer, optional) + - Default: `60000` + - Applies to all workspace hooks. + - Non-positive values should be treated as invalid and fall back to the default. + - Changes should be re-applied at runtime for future hook executions. + +#### 5.3.5 `agent` (object) + +Fields: + +- `max_concurrent_agents` (integer or string integer) + - Default: `10` + - Changes should be re-applied at runtime and affect subsequent dispatch decisions. +- `max_retry_backoff_ms` (integer or string integer) + - Default: `300000` (5 minutes) + - Changes should be re-applied at runtime and affect future retry scheduling. +- `max_concurrent_agents_by_state` (map `state_name -> positive integer`) + - Default: empty map. + - State keys are normalized (`trim` + `lowercase`) for lookup. + - Invalid entries (non-positive or non-numeric) are ignored. + +#### 5.3.6 `codex` (object) + +Fields: + +For Codex-owned config values such as `approval_policy`, `thread_sandbox`, and +`turn_sandbox_policy`, supported values are defined by the targeted Codex app-server version. +Implementors should treat them as pass-through Codex config values rather than relying on a +hand-maintained enum in this spec. To inspect the installed Codex schema, run +`codex app-server generate-json-schema --out ` and inspect the relevant definitions referenced +by `v2/ThreadStartParams.json` and `v2/TurnStartParams.json`. Implementations may validate these +fields locally if they want stricter startup checks. + +- `command` (string shell command) + - Default: `codex app-server` + - The runtime launches this command via `bash -lc` in the workspace directory. + - The launched process must speak a compatible app-server protocol over stdio. +- `approval_policy` (Codex `AskForApproval` value) + - Default: implementation-defined. +- `thread_sandbox` (Codex `SandboxMode` value) + - Default: implementation-defined. +- `turn_sandbox_policy` (Codex `SandboxPolicy` value) + - Default: implementation-defined. +- `turn_timeout_ms` (integer) + - Default: `3600000` (1 hour) +- `read_timeout_ms` (integer) + - Default: `5000` +- `stall_timeout_ms` (integer) + - Default: `300000` (5 minutes) + - If `<= 0`, stall detection is disabled. + +### 5.4 Prompt Template Contract + +The Markdown body of `WORKFLOW.md` is the per-issue prompt template. + +Rendering requirements: + +- Use a strict template engine (Liquid-compatible semantics are sufficient). +- Unknown variables must fail rendering. +- Unknown filters must fail rendering. + +Template input variables: + +- `issue` (object) + - Includes all normalized issue fields, including labels and blockers. +- `attempt` (integer or null) + - `null`/absent on first attempt. + - Integer on retry or continuation run. + +Fallback prompt behavior: + +- If the workflow prompt body is empty, the runtime may use a minimal default prompt + (`You are working on an issue from Linear.`). +- Workflow file read/parse failures are configuration/validation errors and should not silently fall + back to a prompt. + +### 5.5 Workflow Validation and Error Surface + +Error classes: + +- `missing_workflow_file` +- `workflow_parse_error` +- `workflow_front_matter_not_a_map` +- `template_parse_error` (during prompt rendering) +- `template_render_error` (unknown variable/filter, invalid interpolation) + +Dispatch gating behavior: + +- Workflow file read/YAML errors block new dispatches until fixed. +- Template errors fail only the affected run attempt. + +## 6. Configuration Specification + +### 6.1 Source Precedence and Resolution Semantics + +Configuration precedence: + +1. Workflow file path selection (runtime setting -> cwd default). +2. YAML front matter values. +3. Environment indirection via `$VAR_NAME` inside selected YAML values. +4. Built-in defaults. + +Value coercion semantics: + +- Path/command fields support: + - `~` home expansion + - `$VAR` expansion for env-backed path values + - Apply expansion only to values intended to be local filesystem paths; do not rewrite URIs or + arbitrary shell command strings. + +### 6.2 Dynamic Reload Semantics + +Dynamic reload is required: + +- The software should watch `WORKFLOW.md` for changes. +- On change, it should re-read and re-apply workflow config and prompt template without restart. +- The software should attempt to adjust live behavior to the new config (for example polling + cadence, concurrency limits, active/terminal states, codex settings, workspace paths/hooks, and + prompt content for future runs). +- Reloaded config applies to future dispatch, retry scheduling, reconciliation decisions, hook + execution, and agent launches. +- Implementations are not required to restart in-flight agent sessions automatically when config + changes. +- Extensions that manage their own listeners/resources (for example an HTTP server port change) may + require restart unless the implementation explicitly supports live rebind. +- Implementations should also re-validate/reload defensively during runtime operations (for example + before dispatch) in case filesystem watch events are missed. +- Invalid reloads should not crash the service; keep operating with the last known good effective + configuration and emit an operator-visible error. + +### 6.3 Dispatch Preflight Validation + +This validation is a scheduler preflight run before attempting to dispatch new work. It validates +the workflow/config needed to poll and launch workers, not a full audit of all possible workflow +behavior. + +Startup validation: + +- Validate configuration before starting the scheduling loop. +- If startup validation fails, fail startup and emit an operator-visible error. + +Per-tick dispatch validation: + +- Re-validate before each dispatch cycle. +- If validation fails, skip dispatch for that tick, keep reconciliation active, and emit an + operator-visible error. + +Validation checks: + +- Workflow file can be loaded and parsed. +- `tracker.kind` is present and supported. +- `tracker.api_key` is present after `$` resolution. +- `tracker.project_slug` is present when required by the selected tracker kind. +- `codex.command` is present and non-empty. + +### 6.4 Config Fields Summary (Cheat Sheet) + +This section is intentionally redundant so a coding agent can implement the config layer quickly. + +- `tracker.kind`: string, required, currently `linear` +- `tracker.endpoint`: string, default `https://api.linear.app/graphql` when `tracker.kind=linear` +- `tracker.api_key`: string or `$VAR`, canonical env `LINEAR_API_KEY` when `tracker.kind=linear` +- `tracker.project_slug`: string, required when `tracker.kind=linear` +- `tracker.active_states`: list/string, default `Todo, In Progress` +- `tracker.terminal_states`: list/string, default `Closed, Cancelled, Canceled, Duplicate, Done` +- `polling.interval_ms`: integer, default `30000` +- `workspace.root`: path, default `/symphony_workspaces` +- `hooks.after_create`: shell script or null +- `hooks.before_run`: shell script or null +- `hooks.after_run`: shell script or null +- `hooks.before_remove`: shell script or null +- `hooks.timeout_ms`: integer, default `60000` +- `agent.max_concurrent_agents`: integer, default `10` +- `agent.max_turns`: integer, default `20` +- `agent.max_retry_backoff_ms`: integer, default `300000` (5m) +- `agent.max_concurrent_agents_by_state`: map of positive integers, default `{}` +- `codex.command`: shell command string, default `codex app-server` +- `codex.approval_policy`: Codex `AskForApproval` value, default implementation-defined +- `codex.thread_sandbox`: Codex `SandboxMode` value, default implementation-defined +- `codex.turn_sandbox_policy`: Codex `SandboxPolicy` value, default implementation-defined +- `codex.turn_timeout_ms`: integer, default `3600000` +- `codex.read_timeout_ms`: integer, default `5000` +- `codex.stall_timeout_ms`: integer, default `300000` +- `server.port` (extension): integer, optional; enables the optional HTTP server, `0` may be used + for ephemeral local bind, and CLI `--port` overrides it + +## 7. Orchestration State Machine + +The orchestrator is the only component that mutates scheduling state. All worker outcomes are +reported back to it and converted into explicit state transitions. + +### 7.1 Issue Orchestration States + +This is not the same as tracker states (`Todo`, `In Progress`, etc.). This is the service's internal +claim state. + +1. `Unclaimed` + - Issue is not running and has no retry scheduled. + +2. `Claimed` + - Orchestrator has reserved the issue to prevent duplicate dispatch. + - In practice, claimed issues are either `Running` or `RetryQueued`. + +3. `Running` + - Worker task exists and the issue is tracked in `running` map. + +4. `RetryQueued` + - Worker is not running, but a retry timer exists in `retry_attempts`. + +5. `Released` + - Claim removed because issue is terminal, non-active, missing, or retry path completed without + re-dispatch. + +Important nuance: + +- A successful worker exit does not mean the issue is done forever. +- The worker may continue through multiple back-to-back coding-agent turns before it exits. +- After each normal turn completion, the worker re-checks the tracker issue state. +- If the issue is still in an active state, the worker should start another turn on the same live + coding-agent thread in the same workspace, up to `agent.max_turns`. +- The first turn should use the full rendered task prompt. +- Continuation turns should send only continuation guidance to the existing thread, not resend the + original task prompt that is already present in thread history. +- Once the worker exits normally, the orchestrator still schedules a short continuation retry + (about 1 second) so it can re-check whether the issue remains active and needs another worker + session. + +### 7.2 Run Attempt Lifecycle + +A run attempt transitions through these phases: + +1. `PreparingWorkspace` +2. `BuildingPrompt` +3. `LaunchingAgentProcess` +4. `InitializingSession` +5. `StreamingTurn` +6. `Finishing` +7. `Succeeded` +8. `Failed` +9. `TimedOut` +10. `Stalled` +11. `CanceledByReconciliation` + +Distinct terminal reasons are important because retry logic and logs differ. + +### 7.3 Transition Triggers + +- `Poll Tick` + - Reconcile active runs. + - Validate config. + - Fetch candidate issues. + - Dispatch until slots are exhausted. + +- `Worker Exit (normal)` + - Remove running entry. + - Update aggregate runtime totals. + - Schedule continuation retry (attempt `1`) after the worker exhausts or finishes its in-process + turn loop. + +- `Worker Exit (abnormal)` + - Remove running entry. + - Update aggregate runtime totals. + - Schedule exponential-backoff retry. + +- `Codex Update Event` + - Update live session fields, token counters, and rate limits. + +- `Retry Timer Fired` + - Re-fetch active candidates and attempt re-dispatch, or release claim if no longer eligible. + +- `Reconciliation State Refresh` + - Stop runs whose issue states are terminal or no longer active. + +- `Stall Timeout` + - Kill worker and schedule retry. + +### 7.4 Idempotency and Recovery Rules + +- The orchestrator serializes state mutations through one authority to avoid duplicate dispatch. +- `claimed` and `running` checks are required before launching any worker. +- Reconciliation runs before dispatch on every tick. +- Restart recovery is tracker-driven and filesystem-driven (no durable orchestrator DB required). +- Startup terminal cleanup removes stale workspaces for issues already in terminal states. + +## 8. Polling, Scheduling, and Reconciliation + +### 8.1 Poll Loop + +At startup, the service validates config, performs startup cleanup, schedules an immediate tick, and +then repeats every `polling.interval_ms`. + +The effective poll interval should be updated when workflow config changes are re-applied. + +Tick sequence: + +1. Reconcile running issues. +2. Run dispatch preflight validation. +3. Fetch candidate issues from tracker using active states. +4. Sort issues by dispatch priority. +5. Dispatch eligible issues while slots remain. +6. Notify observability/status consumers of state changes. + +If per-tick validation fails, dispatch is skipped for that tick, but reconciliation still happens +first. + +### 8.2 Candidate Selection Rules + +An issue is dispatch-eligible only if all are true: + +- It has `id`, `identifier`, `title`, and `state`. +- Its state is in `active_states` and not in `terminal_states`. +- It is not already in `running`. +- It is not already in `claimed`. +- Global concurrency slots are available. +- Per-state concurrency slots are available. +- Blocker rule for `Todo` state passes: + - If the issue state is `Todo`, do not dispatch when any blocker is non-terminal. + +Sorting order (stable intent): + +1. `priority` ascending (1..4 are preferred; null/unknown sorts last) +2. `created_at` oldest first +3. `identifier` lexicographic tie-breaker + +### 8.3 Concurrency Control + +Global limit: + +- `available_slots = max(max_concurrent_agents - running_count, 0)` + +Per-state limit: + +- `max_concurrent_agents_by_state[state]` if present (state key normalized) +- otherwise fallback to global limit + +The runtime counts issues by their current tracked state in the `running` map. + +### 8.4 Retry and Backoff + +Retry entry creation: + +- Cancel any existing retry timer for the same issue. +- Store `attempt`, `identifier`, `error`, `due_at_ms`, and new timer handle. + +Backoff formula: + +- Normal continuation retries after a clean worker exit use a short fixed delay of `1000` ms. +- Failure-driven retries use `delay = min(10000 * 2^(attempt - 1), agent.max_retry_backoff_ms)`. +- Power is capped by the configured max retry backoff (default `300000` / 5m). + +Retry handling behavior: + +1. Fetch active candidate issues (not all issues). +2. Find the specific issue by `issue_id`. +3. If not found, release claim. +4. If found and still candidate-eligible: + - Dispatch if slots are available. + - Otherwise requeue with error `no available orchestrator slots`. +5. If found but no longer active, release claim. + +Note: + +- Terminal-state workspace cleanup is handled by startup cleanup and active-run reconciliation + (including terminal transitions for currently running issues). +- Retry handling mainly operates on active candidates and releases claims when the issue is absent, + rather than performing terminal cleanup itself. + +### 8.5 Active Run Reconciliation + +Reconciliation runs every tick and has two parts. + +Part A: Stall detection + +- For each running issue, compute `elapsed_ms` since: + - `last_codex_timestamp` if any event has been seen, else + - `started_at` +- If `elapsed_ms > codex.stall_timeout_ms`, terminate the worker and queue a retry. +- If `stall_timeout_ms <= 0`, skip stall detection entirely. + +Part B: Tracker state refresh + +- Fetch current issue states for all running issue IDs. +- For each running issue: + - If tracker state is terminal: terminate worker and clean workspace. + - If tracker state is still active: update the in-memory issue snapshot. + - If tracker state is neither active nor terminal: terminate worker without workspace cleanup. +- If state refresh fails, keep workers running and try again on the next tick. + +### 8.6 Startup Terminal Workspace Cleanup + +When the service starts: + +1. Query tracker for issues in terminal states. +2. For each returned issue identifier, remove the corresponding workspace directory. +3. If the terminal-issues fetch fails, log a warning and continue startup. + +This prevents stale terminal workspaces from accumulating after restarts. + +## 9. Workspace Management and Safety + +### 9.1 Workspace Layout + +Workspace root: + +- `workspace.root` (normalized path; the current config layer expands path-like values and preserves + bare relative names) + +Per-issue workspace path: + +- `/` + +Workspace persistence: + +- Workspaces are reused across runs for the same issue. +- Successful runs do not auto-delete workspaces. + +### 9.2 Workspace Creation and Reuse + +Input: `issue.identifier` + +Algorithm summary: + +1. Sanitize identifier to `workspace_key`. +2. Compute workspace path under workspace root. +3. Ensure the workspace path exists as a directory. +4. Mark `created_now=true` only if the directory was created during this call; otherwise + `created_now=false`. +5. If `created_now=true`, run `after_create` hook if configured. + +Notes: + +- This section does not assume any specific repository/VCS workflow. +- Workspace preparation beyond directory creation (for example dependency bootstrap, checkout/sync, + code generation) is implementation-defined and is typically handled via hooks. + +### 9.3 Optional Workspace Population (Implementation-Defined) + +The spec does not require any built-in VCS or repository bootstrap behavior. + +Implementations may populate or synchronize the workspace using implementation-defined logic and/or +hooks (for example `after_create` and/or `before_run`). + +Failure handling: + +- Workspace population/synchronization failures return an error for the current attempt. +- If failure happens while creating a brand-new workspace, implementations may remove the partially + prepared directory. +- Reused workspaces should not be destructively reset on population failure unless that policy is + explicitly chosen and documented. + +### 9.4 Workspace Hooks + +Supported hooks: + +- `hooks.after_create` +- `hooks.before_run` +- `hooks.after_run` +- `hooks.before_remove` + +Execution contract: + +- Execute in a local shell context appropriate to the host OS, with the workspace directory as + `cwd`. +- On POSIX systems, `sh -lc