Files
Claude-Code-Workflow/.claude/commands/workflow/init-guidelines.md
catlog22 6d225948d1 feat(workflow): add interactive init-guidelines wizard for project guidelines configuration
Add /workflow:init-guidelines command that interactively fills project-guidelines.json
based on project analysis from project-tech.json. Features:
- 5-round questionnaire covering coding style, naming, file structure, documentation,
  architecture, tech stack, performance, security, and quality rules
- Dynamic question generation based on detected language/framework/architecture
- Append/reset mode for existing guidelines
- Multi-select options with "Other" for custom input

Modify /workflow:init to ask user whether to run init-guidelines after initialization
when guidelines are empty (scaffold only).
2026-01-31 20:58:29 +08:00

16 KiB

name, description, argument-hint, examples
name description argument-hint examples
init-guidelines Interactive wizard to fill project-guidelines.json based on project analysis [--reset]
/workflow:init-guidelines
/workflow:init-guidelines --reset

Workflow Init Guidelines Command (/workflow:init-guidelines)

Overview

Interactive multi-round wizard that analyzes the current project (via project-tech.json) and asks targeted questions to populate .workflow/project-guidelines.json with coding conventions, constraints, and quality rules.

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 /workflow:init after initialization. Upon completion, return to the calling workflow if applicable.

Usage

/workflow:init-guidelines          # Fill guidelines interactively (skip if already populated)
/workflow:init-guidelines --reset  # Reset and re-fill guidelines from scratch

Execution Process

Input Parsing:
   └─ Parse --reset flag → reset = true | false

Step 1: Check Prerequisites
   ├─ project-tech.json must exist (run /workflow:init first)
   ├─ project-guidelines.json: check if populated or scaffold-only
   └─ If populated + no --reset → Ask: "Guidelines already exist. Overwrite or append?"

Step 2: Load Project Context
   └─ Read project-tech.json → extract tech stack, architecture, patterns

Step 3: Multi-Round Interactive Questionnaire
   ├─ 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 4: Write project-guidelines.json

Step 5: Display Summary

Implementation

Step 1: Check Prerequisites

bash(test -f .workflow/project-tech.json && echo "TECH_EXISTS" || echo "TECH_NOT_FOUND")
bash(test -f .workflow/project-guidelines.json && echo "GUIDELINES_EXISTS" || echo "GUIDELINES_NOT_FOUND")

If TECH_NOT_FOUND: Exit with message

Project tech analysis not found. Run /workflow:init first.

Parse --reset flag:

const reset = $ARGUMENTS.includes('--reset')

If GUIDELINES_EXISTS and not --reset: Check if guidelines are populated (not just scaffold)

const guidelines = JSON.parse(Read('.workflow/project-guidelines.json'))
const isPopulated =
  guidelines.conventions.coding_style.length > 0 ||
  guidelines.conventions.naming_patterns.length > 0 ||
  guidelines.constraints.architecture.length > 0 ||
  guidelines.constraints.tech_stack.length > 0

if (isPopulated) {
  AskUserQuestion({
    questions: [{
      question: "Project guidelines already contain entries. How would you like to proceed?",
      header: "Mode",
      multiSelect: false,
      options: [
        { label: "Append", 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" }
      ]
    }]
  })
  // If Cancel → exit
  // If Reset → clear all arrays before proceeding
  // If Append → keep existing, wizard adds to them
}

Step 2: Load Project Context

const projectTech = JSON.parse(Read('.workflow/project-tech.json'))

// Extract key info for generating smart questions
const languages = projectTech.technology_analysis?.technology_stack?.languages
  || projectTech.overview?.technology_stack?.languages || []
const primaryLang = languages.find(l => l.primary)?.name || languages[0]?.name || 'Unknown'
const frameworks = projectTech.technology_analysis?.technology_stack?.frameworks
  || projectTech.overview?.technology_stack?.frameworks || []
const testFrameworks = projectTech.technology_analysis?.technology_stack?.test_frameworks
  || projectTech.overview?.technology_stack?.test_frameworks || []
const archStyle = projectTech.technology_analysis?.architecture?.style
  || projectTech.overview?.architecture?.style || 'Unknown'
const archPatterns = projectTech.technology_analysis?.architecture?.patterns
  || projectTech.overview?.architecture?.patterns || []
const buildTools = projectTech.technology_analysis?.technology_stack?.build_tools
  || projectTech.overview?.technology_stack?.build_tools || []

Step 3: Multi-Round Interactive Questionnaire

Each round uses AskUserQuestion 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:

// 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" }
)

AskUserQuestion({
  questions: [
    {
      question: `Your project uses ${primaryLang}. Which coding style conventions do you follow?`,
      header: "Coding Style",
      multiSelect: true,
      options: codingStyleOptions.slice(0, 4) // Max 4 options
    },
    {
      question: `What naming conventions does your ${primaryLang} project use?`,
      header: "Naming",
      multiSelect: true,
      options: [
        { label: "camelCase variables", description: "Variables and functions use camelCase (e.g., getUserName)" },
        { label: "PascalCase types", description: "Classes, interfaces, type aliases use PascalCase (e.g., UserService)" },
        { label: "UPPER_SNAKE constants", description: "Constants use UPPER_SNAKE_CASE (e.g., MAX_RETRIES)" },
        { label: "Prefix interfaces", description: "Prefix interfaces with 'I' (e.g., IUserService)" }
      ]
    }
  ]
})

Process Round 1 answers → add to conventions.coding_style and conventions.naming_patterns arrays.


Round 2: File Structure & Documentation

AskUserQuestion({
  questions: [
    {
      question: `Your project has a ${archStyle} architecture. What file organization rules apply?`,
      header: "File Structure",
      multiSelect: true,
      options: [
        { label: "Co-located tests", description: "Test files live next to source files (e.g., foo.ts + foo.test.ts)" },
        { label: "Separate test dir", description: "Tests in a dedicated __tests__ or tests/ directory" },
        { label: "One export per file", description: "Each file exports a single main component/class/function" },
        { label: "Index barrels", description: "Use index.ts barrel files for clean imports from directories" }
      ]
    },
    {
      question: "What documentation standards does your project follow?",
      header: "Documentation",
      multiSelect: true,
      options: [
        { label: "JSDoc/docstring public APIs", description: "All public functions and classes must have JSDoc/docstrings" },
        { label: "README per module", description: "Each major module/package has its own README" },
        { label: "Inline comments for why", description: "Comments explain 'why', not 'what' — code should be self-documenting" },
        { label: "No comment requirement", description: "Code should be self-explanatory; comments only for non-obvious logic" }
      ]
    }
  ]
})

Process Round 2 answers → add to conventions.file_structure and conventions.documentation.


Round 3: Architecture & Tech Stack Constraints

// Build architecture-specific options
const archOptions = []

if (archStyle.toLowerCase().includes('monolith')) {
  archOptions.push(
    { label: "No circular deps", description: "Modules must not have circular dependencies" },
    { label: "Layer boundaries", description: "Strict layer separation: UI → Service → Data (no skipping layers)" }
  )
} else if (archStyle.toLowerCase().includes('microservice')) {
  archOptions.push(
    { label: "Service isolation", description: "Services must not share databases or internal state" },
    { label: "API contracts", description: "All inter-service communication through versioned API contracts" }
  )
}
archOptions.push(
  { label: "Stateless services", description: "Service/business logic must be stateless (state in DB/cache only)" },
  { label: "Dependency injection", description: "Use dependency injection for testability, no hardcoded dependencies" }
)

AskUserQuestion({
  questions: [
    {
      question: `Your ${archStyle} architecture uses ${archPatterns.join(', ') || 'various'} patterns. What architecture constraints apply?`,
      header: "Architecture",
      multiSelect: true,
      options: archOptions.slice(0, 4)
    },
    {
      question: `Tech stack: ${frameworks.join(', ')}. What technology constraints apply?`,
      header: "Tech Stack",
      multiSelect: true,
      options: [
        { label: "No new deps without review", description: "Adding new dependencies requires explicit justification and review" },
        { label: "Pin dependency versions", description: "All dependencies must use exact versions, not ranges" },
        { label: "Prefer native APIs", description: "Use built-in/native APIs over third-party libraries when possible" },
        { label: "Framework conventions", description: `Follow official ${frameworks[0] || 'framework'} conventions and best practices` }
      ]
    }
  ]
})

Process Round 3 answers → add to constraints.architecture and constraints.tech_stack.


Round 4: Performance & Security Constraints

AskUserQuestion({
  questions: [
    {
      question: "What performance requirements does your project have?",
      header: "Performance",
      multiSelect: true,
      options: [
        { label: "API response time", description: "API endpoints must respond within 200ms (p95)" },
        { label: "Bundle size limit", description: "Frontend bundle size must stay under 500KB gzipped" },
        { label: "Lazy loading", description: "Large modules/routes must use lazy loading / code splitting" },
        { label: "No N+1 queries", description: "Database access must avoid N+1 query patterns" }
      ]
    },
    {
      question: "What security requirements does your project enforce?",
      header: "Security",
      multiSelect: true,
      options: [
        { label: "Input sanitization", description: "All user input must be validated and sanitized before use" },
        { label: "No secrets in code", description: "No API keys, passwords, or tokens in source code — use env vars" },
        { label: "Auth on all endpoints", description: "All API endpoints require authentication unless explicitly public" },
        { label: "Parameterized queries", description: "All database queries must use parameterized/prepared statements" }
      ]
    }
  ]
})

Process Round 4 answers → add to constraints.performance and constraints.security.


Round 5: Quality Rules

AskUserQuestion({
  questions: [
    {
      question: `Testing with ${testFrameworks.join(', ') || 'your test framework'}. What quality rules apply?`,
      header: "Quality",
      multiSelect: true,
      options: [
        { label: "Min test coverage", description: "Minimum 80% code coverage for new code; no merging below threshold" },
        { label: "No skipped tests", description: "Tests must not be skipped (.skip/.only) in committed code" },
        { label: "Lint must pass", description: "All code must pass linter checks before commit (enforced by pre-commit)" },
        { label: "Type check must pass", description: "Full type checking (tsc --noEmit) must pass with zero errors" }
      ]
    }
  ]
})

Process Round 5 answers → add to quality_rules array as { rule, scope, enforced_by } objects.

Step 4: Write project-guidelines.json

// Build the final guidelines object
const finalGuidelines = {
  conventions: {
    coding_style: existingCodingStyle.concat(newCodingStyle),
    naming_patterns: existingNamingPatterns.concat(newNamingPatterns),
    file_structure: existingFileStructure.concat(newFileStructure),
    documentation: existingDocumentation.concat(newDocumentation)
  },
  constraints: {
    architecture: existingArchitecture.concat(newArchitecture),
    tech_stack: existingTechStack.concat(newTechStack),
    performance: existingPerformance.concat(newPerformance),
    security: existingSecurity.concat(newSecurity)
  },
  quality_rules: existingQualityRules.concat(newQualityRules),
  learnings: existingLearnings, // Preserve existing learnings
  _metadata: {
    created_at: existingMetadata?.created_at || new Date().toISOString(),
    version: "1.0.0",
    last_updated: new Date().toISOString(),
    updated_by: "workflow:init-guidelines"
  }
}

Write('.workflow/project-guidelines.json', JSON.stringify(finalGuidelines, null, 2))

Step 5: Display Summary

const countConventions = finalGuidelines.conventions.coding_style.length
  + finalGuidelines.conventions.naming_patterns.length
  + finalGuidelines.conventions.file_structure.length
  + finalGuidelines.conventions.documentation.length

const countConstraints = finalGuidelines.constraints.architecture.length
  + finalGuidelines.constraints.tech_stack.length
  + finalGuidelines.constraints.performance.length
  + finalGuidelines.constraints.security.length

const countQuality = finalGuidelines.quality_rules.length

console.log(`
✓ Project guidelines configured

## Summary
- Conventions: ${countConventions} rules (coding: ${cs}, naming: ${np}, files: ${fs}, docs: ${doc})
- Constraints: ${countConstraints} rules (arch: ${ar}, tech: ${ts}, perf: ${pf}, security: ${sc})
- Quality rules: ${countQuality}

File: .workflow/project-guidelines.json

Next steps:
- Use /workflow:session:solidify to add individual rules later
- Guidelines will be auto-loaded by /workflow:plan for task generation
`)

Answer Processing Rules

When converting user selections to guideline entries:

  1. Selected option → Use the option's description as the guideline string (it's more precise than the label)
  2. "Other" with custom text → Use the user's text directly as the guideline string
  3. Deduplication → Skip entries that already exist in the guidelines (exact string match)
  4. Quality rules → Convert to { rule: description, scope: "all", enforced_by: "code-review" } format

Error Handling

  • No project-tech.json: Exit with instruction to run /workflow:init first
  • User cancels mid-wizard: Save whatever was collected so far (partial is better than nothing)
  • File write failure: Report error, suggest manual edit
  • /workflow:init - Creates scaffold; optionally calls this command
  • /workflow:session:solidify - Add individual rules one at a time