- name
- spec-setup
- description
- Initialize project-level state and configure specs via interactive questionnaire.
- argument-hint
- [--regenerate] [--skip-specs] [--reset]
- allowed-tools
- spawn_agent, wait_agent, send_message, followup_task, close_agent, request_user_input, Read, Write, Edit, Bash, Glob, Grep
# Workflow Spec Setup Command
## Overview
Initialize `.workflow/project-tech.json` and `.ccw/specs/*.md` with comprehensive project understanding by delegating analysis to **cli-explore-agent**, then interactively configure project guidelines through a multi-round questionnaire.
**Dual File System**:
- `project-tech.json`: Auto-generated technical analysis (stack, architecture, components)
- `specs/*.md`: User-maintained rules and constraints (created and populated interactively)
**Design Principle**: Questions are dynamically generated based on the project's tech stack, architecture, and patterns -- not generic boilerplate.
**Note**: This command may be called by other workflow commands. Upon completion, return immediately to continue the calling workflow without interrupting the task flow.
## Usage
```bash
$spec-setup # Initialize (skip if exists)
$spec-setup --regenerate # Force regeneration of project-tech.json
$spec-setup --skip-specs # Initialize project-tech only, skip spec initialization and questionnaire
$spec-setup --reset # Reset specs content before questionnaire
```
## Execution Process
```
Input Parsing:
|- Parse --regenerate flag -> regenerate = true | false
|- Parse --skip-specs flag -> skipSpecs = true | false
+- Parse --reset flag -> reset = true | false
Decision:
|- BOTH_EXIST + no --regenerate + no --reset -> Exit: "Already initialized"
|- EXISTS + --regenerate -> Backup existing -> Continue analysis
|- EXISTS + --reset -> Reset specs, keep project-tech -> Skip to questionnaire
+- NOT_FOUND -> Continue full flow
Full Flow:
|- Step 1: Parse input and check existing state
|- Step 2: Get project metadata (name, root)
|- Step 3: Invoke cli-explore-agent (subagent)
| |- Structural scan (get_modules_by_depth.sh, find, wc)
| |- Semantic analysis (Gemini CLI)
| |- Synthesis and merge
| +- Write .workflow/project-tech.json
|- Step 4: Initialize Spec System (if not --skip-specs)
| |- Check if specs/*.md exist
| |- If NOT_FOUND -> Run ccw spec init
| +- Run ccw spec rebuild
|- Step 5: Multi-Round Interactive Questionnaire (if not --skip-specs)
| |- Check if guidelines already populated -> Ask: "Append / Reset / Cancel"
| |- Load project context from project-tech.json
| |- Round 1: Coding Conventions (coding_style, naming_patterns)
| |- Round 2: File & Documentation Conventions (file_structure, documentation)
| |- Round 3: Architecture & Tech Constraints (architecture, tech_stack)
| |- Round 4: Performance & Security Constraints (performance, security)
| +- Round 5: Quality Rules (quality_rules)
|- Step 6: Write specs/*.md (if not --skip-specs)
+- Step 7: Display Summary
Output:
|- .workflow/project-tech.json (+ .backup if regenerate)
+- .ccw/specs/*.md (scaffold or configured, unless --skip-specs)
```
## Implementation
### Step 1: Parse Input and Check Existing State
**Parse flags**:
```javascript
const regenerate = $ARGUMENTS.includes('--regenerate')
const skipSpecs = $ARGUMENTS.includes('--skip-specs')
const reset = $ARGUMENTS.includes('--reset')
```
**Check existing state**:
```bash
bash(test -f .workflow/project-tech.json && echo "TECH_EXISTS" || echo "TECH_NOT_FOUND")
bash(test -f .ccw/specs/coding-conventions.md && echo "SPECS_EXISTS" || echo "SPECS_NOT_FOUND")
```
**If BOTH_EXIST and no --regenerate and no --reset**: Exit early
```
Project already initialized:
- Tech analysis: .workflow/project-tech.json
- Guidelines: .ccw/specs/*.md
Use $spec-setup --regenerate to rebuild tech analysis
Use $spec-setup --reset to reconfigure guidelines
Use $spec-add to add individual rules
Use $workflow-status --project to view state
```
### Step 2: Get Project Metadata
```bash
bash(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")
bash(git rev-parse --show-toplevel 2>/dev/null || pwd)
bash(mkdir -p .workflow)
```
### Step 3: Invoke cli-explore-agent (Subagent)
**For --regenerate**: Backup and preserve existing data
```bash
bash(cp .workflow/project-tech.json .workflow/project-tech.json.backup)
```
**Delegate analysis to subagent**:
```javascript
let exploreAgent = null
try {
exploreAgent = spawn_agent({
agent_type: "cli_explore_agent",
message: `
## TASK ASSIGNMENT
### MANDATORY FIRST STEPS (Agent Execute)
1. Read: .workflow/project-tech.json (if exists, for --regenerate)
---
Analyze project for workflow initialization and generate .workflow/project-tech.json.
## MANDATORY FIRST STEPS
1. Execute: cat ~/.ccw/workflows/cli-templates/schemas/project-tech-schema.json (get schema reference)
2. Execute: ccw tool exec get_modules_by_depth '{}' (get project structure)
## Task
Generate complete project-tech.json following the schema structure:
- project_name: "${projectName}"
- initialized_at: ISO 8601 timestamp
- overview: {
description: "Brief project description",
technology_stack: {
languages: [{name, file_count, primary}],
frameworks: ["string"],
build_tools: ["string"],
test_frameworks: ["string"]
},
architecture: {style, layers: [], patterns: []},
key_components: [{name, path, description, importance}]
}
- features: []
- development_index: ${regenerate ? 'preserve from backup' : '{feature: [], enhancement: [], bugfix: [], refactor: [], docs: []}'}
- statistics: ${regenerate ? 'preserve from backup' : '{total_features: 0, total_sessions: 0, last_updated: ISO timestamp}'}
- _metadata: {initialized_by: "cli-explore-agent", analysis_timestamp: ISO timestamp, analysis_mode: "deep-scan"}
## Analysis Requirements
**Technology Stack**:
- Languages: File counts, mark primary
- Frameworks: From package.json, requirements.txt, go.mod, etc.
- Build tools: npm, cargo, maven, webpack, vite
- Test frameworks: jest, pytest, go test, junit
**Architecture**:
- Style: MVC, microservices, layered (from structure & imports)
- Layers: presentation, business-logic, data-access
- Patterns: singleton, factory, repository
- Key components: 5-10 modules {name, path, description, importance}
## Execution
1. Structural scan: get_modules_by_depth.sh, find, wc -l
2. Semantic analysis: Gemini for patterns/architecture
3. Synthesis: Merge findings
4. ${regenerate ? 'Merge with preserved development_index and statistics from .workflow/project-tech.json.backup' : ''}
5. Write JSON: Write('.workflow/project-tech.json', jsonContent)
6. Report: Return brief completion summary
Project root: ${projectRoot}
`
})
// Wait for completion
const result = wait_agent({ timeout_ms: 1800000 })
if (result.timed_out) {
// Status probe
followup_task({ target: exploreAgent, message: "STATUS_CHECK: Report current progress, findings so far, and estimated remaining work." })
const status = wait_agent({ timeout_ms: 180000 }) // 3 min
if (status.timed_out) {
// Force finalize
followup_task({ target: exploreAgent, message: "FINALIZE: Output all current findings immediately. Time limit reached.", interrupt: true })
const forced = wait_agent({ timeout_ms: 180000 }) // 3 min
if (forced.timed_out) {
close_agent({ target: exploreAgent })
throw new Error('Agent timeout')
}
}
}
} finally {
if (exploreAgent) close_agent({ target: exploreAgent })
}
```
### Step 4: Initialize Spec System (if not --skip-specs)
```javascript
// Skip spec initialization if --skip-specs flag is provided
if (!skipSpecs) {
// Initialize spec system if not already initialized
const specsCheck = Bash('test -f .ccw/specs/coding-conventions.md && echo EXISTS || echo NOT_FOUND')
if (specsCheck.includes('NOT_FOUND')) {
console.log('Initializing spec system...')
Bash('ccw spec init')
Bash('ccw spec rebuild')
}
} else {
console.log('Skipping spec initialization and questionnaire (--skip-specs)')
}
```
If `--skip-specs` is provided, skip directly to Step 7 (Display Summary) with limited output.
### Step 5: Multi-Round Interactive Questionnaire (if not --skip-specs)
#### Step 5.0: Check Existing Guidelines
If guidelines already have content, ask the user how to proceed:
```javascript
// Check if specs already have content via ccw spec list
const specsList = Bash('ccw spec list --json 2>/dev/null || echo "{}"')
const specsData = JSON.parse(specsList)
const isPopulated = (specsData.total || 0) > 5 // More than seed docs
if (isPopulated && !reset) {
const mode = functions.request_user_input({
questions: [{
header: "Guidelines",
id: "mode",
question: "Project guidelines already contain entries. How would you like to proceed?",
options: [
{ label: "Append(Recommended)", description: "Keep existing entries and add new ones from the wizard" },
{ label: "Reset", description: "Clear all existing entries and start fresh" },
{ label: "Cancel", description: "Exit without changes" }
]
}]
}) // BLOCKS (wait for user response)
// If Cancel -> exit
// If Reset -> clear all arrays before proceeding
// If Append -> keep existing, wizard adds to them
}
// If --reset flag was provided, clear existing entries before proceeding
if (reset) {
// Reset specs content
console.log('Resetting existing guidelines...')
}
```
#### Step 5.1: Load Project Context
```javascript
// Load project context via ccw spec load for planning context
const projectContext = Bash('ccw spec load --category planning 2>/dev/null || echo "{}"')
const specData = JSON.parse(projectContext)
// Extract key info from loaded specs for generating smart questions
const languages = specData.overview?.technology_stack?.languages || []
const primaryLang = languages.find(l => l.primary)?.name || languages[0]?.name || 'Unknown'
const frameworks = specData.overview?.technology_stack?.frameworks || []
const testFrameworks = specData.overview?.technology_stack?.test_frameworks || []
const archStyle = specData.overview?.architecture?.style || 'Unknown'
const archPatterns = specData.overview?.architecture?.patterns || []
const buildTools = specData.overview?.technology_stack?.build_tools || []
```
#### Step 5.2: Multi-Round Questionnaire
Each round uses `request_user_input` with project-aware options. The user can always select "Other" to provide custom input.
**CRITICAL**: After each round, collect the user's answers and convert them into guideline entries. Do NOT batch all rounds -- process each round's answers before proceeding to the next.
---
##### Round 1: Coding Conventions
Generate options dynamically based on detected language/framework:
```javascript
// Build language-specific coding style options
const codingStyleOptions = []
if (['TypeScript', 'JavaScript'].includes(primaryLang)) {
codingStyleOptions.push(
{ label: "Strict TypeScript", description: "Use strict mode, no 'any' type, explicit return types for public APIs" },
{ label: "Functional style", description: "Prefer pure functions, immutability, avoid class-based patterns where possible" },
{ label: "Const over let", description: "Always use const; only use let when reassignment is truly needed" }
)
} else if (primaryLang === 'Python') {
codingStyleOptions.push(
{ label: "Type hints", description: "Use type hints for all function signatures and class attributes" },
{ label: "Functional style", description: "Prefer pure functions, list comprehensions, avoid mutable state" },
{ label: "PEP 8 strict", description: "Strict PEP 8 compliance with max line length 88 (Black formatter)" }
)
} else if (primaryLang === 'Go') {
codingStyleOptions.push(
{ label: "Error wrapping", description: "Always wrap errors with context using fmt.Errorf with %w" },
{ label: "Interface first", description: "Define interfaces at the consumer side, not the provider" },
{ label: "Table-driven tests", description: "Use table-driven test pattern for all unit tests" }
)
}
// Add universal options
codingStyleOptions.push(
{ label: "Early returns", description: "Prefer early returns / guard clauses over deep nesting" }
)
// Round 1: Coding Conventions
const round1 = functions.request_user_input({
questions: [
{
header: "Code Style",
id: "coding_style",
question: `Your project uses ${primaryLang}. Which coding style conventions do you follow?`,
options: codingStyleOptions.slice(0, 3) // Max 3 options
},
{
header: "Naming",
id: "naming",
question: `What naming conventions does your ${primaryLang} project use?`,
options: [
{ label: "camelCase variables", description: "Variables and functions use camelCase (e.g., getUserName)" },
Auf GitHub ansehen