Skip to content

Conversation

@jax-max
Copy link
Contributor

@jax-max jax-max commented Nov 14, 2025

Add Custom Template Support for Change Files

Summary

This PR introduces custom template support for OpenSpec change files, enabling projects to customize the structure and content of generated change proposal files (proposal.md, tasks.md, design.md, spec.md). The feature is fully backward compatible and opt-in, ensuring no impact on existing projects.

Problem Statement

Currently, OpenSpec generates change files using hardcoded default structures. While these defaults work well for most cases, they present challenges for different project needs: large-scale projects find the default templates too simplistic and require more detailed sections, while some teams find alternative tools like spec-kit overly complex. Additionally, organizations need to adapt templates to match their specific documentation standards, compliance requirements, and review processes. The current hardcoded structure prevents teams from customizing document sections to fit their project scale and organizational needs.

Solution

This implementation adds a flexible template system that:

  1. Allows projects to define custom templates for each change file type
  2. Supports variable substitution for dynamic content
  3. Validates templates to ensure compatibility with OpenSpec's archive functionality
  4. Falls back gracefully to default templates when custom templates are not available

Changes

Core Implementation

  • New Module: src/core/templates/change-templates.ts (192 lines)
    • ChangeTemplateManager class for template loading and rendering
    • Variable substitution engine for {{changeId}}, {{date}}, and {{capability}}
    • Spec template validation to ensure required tags are present
    • Default template definitions for all change file types

CLI Enhancement

  • Modified: src/cli/index.ts

    • Added --templates option to openspec init command
    • Optional flag to generate default templates during project initialization
  • Modified: src/core/init.ts

    • Integrated template generation into initialization workflow
    • Added logic to skip generation if templates directory already exists
    • Non-intrusive implementation that does not affect default behavior

Documentation Updates

  • Modified: src/core/templates/agents-template.ts

    • Added "Custom Templates" section explaining template usage
    • Documented variable replacement syntax
    • Clarified fallback behavior and validation requirements
  • Modified: src/core/templates/slash-command-templates.ts

    • Updated proposal steps to include template checking instructions
    • Added detailed template processing guidelines for AI assistants
    • Enhanced reference section with template variable documentation

Testing

  • New: test/core/templates/change-templates.test.ts (445 lines)

    • Comprehensive test coverage for all template operations
    • Tests for variable substitution, validation, and fallback behavior
    • Edge case handling and error scenarios
    • Optimized test structure using loadTemplate() for all scenarios
  • Modified: test/core/init.test.ts

    • Added tests for template generation during initialization
    • Verified skip behavior when templates already exist

Technical Details

Template System Architecture

The template system follows a layered approach:

  1. Template Discovery: Checks for custom templates in openspec/templates/ directory
  2. Template Loading: Loads custom template or falls back to default
  3. Validation: Validates spec templates to ensure archive compatibility
  4. Rendering: Replaces variables with actual values
  5. Output: Returns rendered template content

Variable Substitution

Supported variables:

  • {{changeId}}: The change identifier (e.g., add-user-auth)
  • {{date}}: Current date in ISO format (YYYY-MM-DD)
  • {{capability}}: Capability name (only used in spec.md templates)

Spec Template Validation

Custom spec templates must include:

  • At least one delta section header: ## ADDED|MODIFIED|REMOVED|RENAMED Requirements
  • Requirement header: ### Requirement:
  • Scenario header: #### Scenario:

Invalid templates trigger a warning and fall back to the default template to prevent breaking the archive functionality.

Usage

Generating Default Templates

openspec init --templates

This command creates the following template files in openspec/templates/:

  • proposal.md.template
  • tasks.md.template
  • design.md.template
  • spec.md.template

Customizing Templates

Users can edit the generated templates to match their project's documentation standards. The templates support variable substitution and will be automatically used when creating new change files.

Template Processing

When AI assistants create change files, they:

  1. Check for custom templates in openspec/templates/
  2. Use custom template if available, otherwise use default structure
  3. Replace variables with actual values
  4. Validate spec templates before use

Backward Compatibility

This feature is fully backward compatible:

  • Default behavior unchanged: existing projects continue to work without modification
  • Opt-in feature: templates are only generated when --templates flag is used
  • Graceful fallback: if templates don't exist, system uses default structures
  • No breaking changes: all existing APIs and workflows remain functional

Testing

  • All existing tests pass (33 tests in change-templates.test.ts)
  • 445 lines of new test coverage
  • No linter errors
  • Comprehensive edge case coverage

Files Changed

Added:
- src/core/templates/change-templates.ts (192 lines)
- test/core/templates/change-templates.test.ts (445 lines)

Modified:
- src/cli/index.ts (+3/-1 lines)
- src/core/init.ts (+29/-0 lines)
- src/core/templates/agents-template.ts (+32/-0 lines)
- src/core/templates/index.ts (+1/-0 lines)
- src/core/templates/slash-command-templates.ts (+30/-6 lines)
- test/core/init.test.ts (+100/-0 lines)

Total: +822/-11 lines across 8 files

Summary by CodeRabbit

  • New Features

    • Added an init option (--templates) to optionally generate default change templates; generation is skipped when custom templates exist. Templates support proposal, tasks, design and spec with variable substitution (changeId, date, capability) and spec-template validation with fallback to defaults.
  • Documentation

    • Updated workflow docs with examples and template-driven file-creation guidance.
  • Tests

    • Added tests for generation, loading, validation, substitution, skipping, and overwrite behavior.

- Added instructions to avoid writing code during the proposal stage and focus on creating design documents.
- Emphasized the design phase by including a reminder not to implement code until the apply stage.
- Updated validation steps to clarify the importance of confirming project conventions before proceeding with tasks.
…hat no implementation code should be written during the design phase.
…g project initialization

- Introduced a new command-line option `--templates` to the `init` command, allowing users to generate default change templates in the `openspec/templates/` directory.
- Implemented logic to check for existing templates and skip generation if they are already present.
- Updated documentation to reflect the new template generation feature and its usage.
- Added comprehensive tests to ensure correct behavior of the template generation functionality.
…delines

- Revised the steps for creating proposals to include critical checks for template existence and variable replacement.
- Enhanced clarity on the creation of `proposal.md`, `tasks.md`, and `design.md` files, specifying fallback structures when templates are not available.
- Added detailed instructions for mapping changes into capabilities and creating spec deltas, ensuring consistency in proposal documentation.
- Updated reference section to emphasize the importance of template processing for various file types.
… update tests to use loadTemplate

- Removed the synchronous `render` method from `ChangeTemplateManager` to streamline template processing.
- Updated tests to replace calls to `render` with `loadTemplate`, ensuring asynchronous handling of template rendering.
- Adjusted test cases to maintain functionality and validate the use of default templates.
@jax-max jax-max requested a review from TabishB as a code owner November 14, 2025 11:40
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

Walkthrough

Adds optional template generation to init: a CLI --templates flag, wiring into InitCommand, a new ChangeTemplateManager for default/custom templates (load/validate/write/variable substitution), updates to template-driven docs/workflows, and tests covering generation and validation.

Changes

Cohort / File(s) Summary
CLI flag integration
src/cli/index.ts
Adds --templates boolean flag to the init command and forwards it into InitCommand options.
Init command enhancement
src/core/init.ts
InitCommand options now include templates?: boolean; stores generateTemplates and calls maybeGenerateChangeTemplates(openspecPath) to optionally generate default templates or skip when custom templates exist.
Template manager implementation
src/core/templates/change-templates.ts
New ChangeTemplateManager plus ChangeTemplateType and TemplateContext; in-code default templates, load custom templates with validation and variable substitution, hasCustomTemplates and writeDefaultTemplates.
Template exports
src/core/templates/index.ts
Re-exports ChangeTemplateManager, ChangeTemplateType, and TemplateContext.
Documentation / workflow templates
src/core/templates/agents-template.ts, src/core/templates/slash-command-templates.ts
Convert workflows to template-driven instructions, document openspec/templates/, variable placeholders ({{changeId}}, {{date}}, {{capability}}), and update file paths to openspec/....
Tests
test/core/init.test.ts, test/core/templates/change-templates.test.ts
New tests for init template generation/skipping, template validation and fallback, variable substitution, hasCustomTemplates and writeDefaultTemplates, and related edge cases.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI
    participant InitCommand
    participant ChangeTemplateManager
    Note right of ChangeTemplateManager `#f2f7ff`: manages default & custom templates

    User->>CLI: openspec init [--templates]
    CLI->>InitCommand: run init(options{ templates?: boolean, ... })
    InitCommand->>InitCommand: perform init steps
    alt options.templates == true
        InitCommand->>ChangeTemplateManager: hasCustomTemplates(openspecDir)
        alt custom templates exist
            ChangeTemplateManager-->>InitCommand: true
            InitCommand-->>User: Skipping template generation (custom present)
        else no custom templates
            ChangeTemplateManager-->>InitCommand: false
            InitCommand->>ChangeTemplateManager: writeDefaultTemplates(openspecDir)
            ChangeTemplateManager-->>InitCommand: written
            InitCommand-->>User: Default templates generated
        end
    else options.templates != true
        InitCommand-->>User: Init completed (no templates)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to:
    • ChangeTemplateManager.validateSpecTemplate() correctness and edge-case detection
    • Variable substitution robustness (multiple occurrences, empty/special values)
    • File write/overwrite semantics in writeDefaultTemplates
    • Integration ordering of maybeGenerateChangeTemplates() in InitCommand

Possibly related PRs

Suggested reviewers

  • TabishB
  • Israel-Laguan

Poem

🐇 I hopped through code at break of day,

templates tucked in nests of .md,
{{date}} and {{changeId}} ready to play,
Defaults sprout where customs may not be,
A tiny rabbit cheers: "Init, templates—wee!"

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Feat/custom-template' is vague and uses a conventional prefix pattern without clearly describing the main feature or its scope. Consider using a more descriptive title like 'Add custom template support for change files' that clearly communicates the primary feature being introduced.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/core/templates/change-templates.ts (2)

56-81: Spec template validation is clear and targeted

The regex-based checks for a delta section plus ### Requirement: and #### Scenario: headers are straightforward and match the default spec template. If you ever need to keep tests/docs in tighter sync, consider extracting these patterns or error messages as shared constants, but it’s not required for correctness.


86-102: Consider narrowing the read error handling in loadTemplate

loadTemplate currently treats any fs.readFile failure as “no custom template” and silently falls back to the default template. That’s great for missing files, but it will also hide permission or I/O errors that users might want surfaced.

You could optionally distinguish ENOENT from other errors, for example:

try {
  content = await fs.readFile(templatePath, 'utf-8');
  isCustom = true;
} catch (error: any) {
  if (error?.code === 'ENOENT') {
    content = defaultTemplates[type];
  } else {
    throw error; // or log a warning before falling back
  }
}

The variable replacement behavior (defaulting missing values to '' and using an ISO date) is otherwise consistent with the documented {{changeId}}, {{date}}, and {{capability}} semantics.

Also applies to: 115-153

src/core/init.ts (1)

727-746: Consider adding error handling for template generation.

The maybeGenerateChangeTemplates method has clear logic and good user feedback. However, if ChangeTemplateManager.writeDefaultTemplates() throws an error (e.g., permission issues), the initialization will fail without a clear error message specific to template generation.

Consider wrapping the template generation in a try-catch block to provide better error context:

   private async maybeGenerateChangeTemplates(openspecPath: string): Promise<void> {
     // Only generate if explicitly requested via --templates flag
     if (!this.generateTemplates) {
       return;
     }
 
     // Skip if templates already exist
     const hasTemplates = await ChangeTemplateManager.hasCustomTemplates(openspecPath);
     if (hasTemplates) {
       ora({ stream: process.stdout }).info(
         PALETTE.midGray('ℹ Templates directory already exists, skipping template generation.')
       );
       return;
     }
 
-    await ChangeTemplateManager.writeDefaultTemplates(openspecPath);
-    ora({ stream: process.stdout }).succeed(
-      PALETTE.white('Change templates generated in openspec/templates/')
-    );
+    try {
+      await ChangeTemplateManager.writeDefaultTemplates(openspecPath);
+      ora({ stream: process.stdout }).succeed(
+        PALETTE.white('Change templates generated in openspec/templates/')
+      );
+    } catch (error) {
+      throw new Error(
+        `Failed to generate change templates: ${error instanceof Error ? error.message : String(error)}`
+      );
+    }
   }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 17d7e59 and 4edeb36.

📒 Files selected for processing (8)
  • src/cli/index.ts (2 hunks)
  • src/core/init.ts (4 hunks)
  • src/core/templates/agents-template.ts (2 hunks)
  • src/core/templates/change-templates.ts (1 hunks)
  • src/core/templates/index.ts (1 hunks)
  • src/core/templates/slash-command-templates.ts (1 hunks)
  • test/core/init.test.ts (1 hunks)
  • test/core/templates/change-templates.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
test/core/init.test.ts (2)
src/utils/file-system.ts (2)
  • directoryExists (107-117)
  • fileExists (76-86)
src/core/init.ts (1)
  • InitCommand (377-997)
test/core/templates/change-templates.test.ts (1)
src/core/templates/change-templates.ts (2)
  • ChangeTemplateManager (107-192)
  • ChangeTemplateType (4-4)
src/core/templates/change-templates.ts (1)
src/core/templates/index.ts (3)
  • ChangeTemplateType (51-51)
  • TemplateContext (51-51)
  • ChangeTemplateManager (51-51)
src/core/init.ts (3)
src/core/templates/change-templates.ts (1)
  • ChangeTemplateManager (107-192)
src/core/templates/index.ts (1)
  • ChangeTemplateManager (51-51)
src/core/styles/palette.ts (1)
  • PALETTE (3-8)
🔇 Additional comments (14)
src/core/templates/change-templates.ts (2)

15-51: Default templates and spec structure look solid

The built-in templates cover all four change types and the spec default includes the required delta, ### Requirement: and #### Scenario: sections, which aligns with your validation rules and archive expectations. No changes needed here.


169-191: Template directory detection and writing are straightforward

hasCustomTemplates and writeDefaultTemplates do exactly what’s needed for the init flow (skip when a templates/ dir already exists; otherwise write all four defaults). This matches the tests and the “opt-in, non-destructive” behavior described in the PR.

src/core/templates/index.ts (1)

49-51: Re-export wiring for change templates looks correct

Re-exporting ChangeTemplateManager, ChangeTemplateType, and TemplateContext from this index keeps template APIs centralized and matches the existing pattern in this module.

src/cli/index.ts (1)

41-45: Init --templates flag is correctly threaded into InitCommand

The new --templates boolean option and the extended action signature cleanly pass templates: options?.templates into InitCommand, matching the updated InitCommandOptions shape. This keeps template generation strictly opt-in without affecting existing init behavior.

Also applies to: 66-69

test/core/init.test.ts (1)

1562-1660: Template generation integration tests are comprehensive

The new change templates generation suite exercises all key paths: no-op by default, generation when templates: true, skipping when a templates directory already exists, negative case when the flag isn’t provided, and verification that the generated spec template includes the required headings. This aligns well with the maybeGenerateChangeTemplates behavior in InitCommand.

src/core/templates/slash-command-templates.ts (1)

33-37: Template variable docs are consistent with the template engine

The proposalReferences section correctly documents the template lookup path (openspec/templates/<type>.md.template) and the supported variables ({{changeId}}, {{date}} in YYYY-MM-DD, and {{capability}} for spec templates), which aligns with ChangeTemplateManager and TemplateContext. This should make it easy for users (and AI tools) to author compatible custom templates.

src/core/templates/agents-template.ts (2)

158-182: LGTM! Comprehensive custom templates documentation.

The Custom Templates section is clear and well-structured. It effectively explains:

  • How to generate templates with openspec init --templates
  • Variable substitution mechanics
  • Fallback behavior
  • Spec template validation requirements

The documentation aligns with the implementation in ChangeTemplateManager and provides good user guidance.


45-49: Step numbering updated correctly.

The workflow steps have been renumbered properly to accommodate the new custom template check in Step 2. The sequence (Steps 2-5) is logical and maintains clarity.

test/core/templates/change-templates.test.ts (3)

1-20: LGTM! Proper test setup with isolated temporary directories.

The test setup correctly creates isolated temporary directories for each test and cleans up afterward. The use of randomUUID() ensures no conflicts between parallel test runs.


122-141: Good validation fallback test with proper console.warn spy.

The test correctly verifies that invalid custom spec templates fall back to the default template and that a warning is logged. The spy is properly cleaned up.


414-451: Excellent edge case coverage.

The edge cases test suite comprehensively covers:

  • Multiple variable occurrences
  • Empty variables
  • Special characters in variables

This helps ensure robust variable substitution.

src/core/init.ts (3)

16-16: LGTM! ChangeTemplateManager import added.

The import is correctly placed and follows the existing import structure.


371-386: LGTM! Clean opt-in flag for template generation.

The templates field is properly added as an optional parameter and stored in the class. This follows the existing pattern for tools and maintains backward compatibility.


441-443: LGTM! Proper placement in initialization flow.

The template generation is correctly positioned after directory structure creation (ensuring openspec/ exists) and before tool configuration. The comment clearly identifies this as "Step 1.5".

…istency

- Modified paths in the `slash-command-templates.ts` file to ensure all references to change files are prefixed with `openspec/`, enhancing clarity and consistency.
- Updated test case description in `change-templates.test.ts` to reflect the behavior of writing templates, ensuring accurate documentation of expected functionality.
Copy link
Contributor

@TabishB TabishB left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I'm fine with the general idea behind it. I think the approach needs to be more programatic though. Rather than relying on the agent to decide whether to use templates or not. We should introduce a scaffold command and allow users to modify the result of the scaffold command itself.

I'm a little anxious about allowing users to customize the spec file itself since it can be a bit dangerous for how we do the merging/archiving of spec deltas at the moment.

Also i'm not sure if you know. But if you're interested we're working on a seperate project to make an extremely customizable version of openspec. Join the discord and give me a ping and i can show you some of the work. Or just email me at tabish@fissionai.io haha.

2. Choose a unique verb-led \`change-id\` and scaffold \`proposal.md\`, \`tasks.md\`, optional \`design.md\`, and spec deltas under \`openspec/changes/<id>/\`.
3. Draft spec deltas using \`## ADDED|MODIFIED|REMOVED Requirements\` with at least one \`#### Scenario:\` per requirement.
4. Run \`openspec validate <id> --strict\` and resolve any issues before sharing the proposal.
2. Check for custom templates: If \`openspec/templates/\` directory exists, use those templates when creating files (see Custom Templates section below).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @jax-max I try and reduce the amount of decisions an LLM has to make and try and make decisions here programatic if possible.

I have something in mind on how to acccomplish this by creating an openspec scaffold command that sets up default templates for an Agent to fill out.

Check it out here: https://github.com/Fission-AI/OpenSpec/tree/main/openspec/changes/add-scaffold-command

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @TabishB I've seen the changes related to the scaffold – the last update was two months ago, so I'm not sure if the plan is still moving forward.
Personally, I think the scaffold should be project-scoped rather than change-scoped. Therefore, it would be better to handle template initialization during the openspec init phase: first generate the spec, task, design, and proposal templates, then modify these templates to meet the project's specific requirements. After that, all subsequent changes should adhere to these pre-configured templates.
I’ve also thought about making decisions programmatic if possible, but I don’t want to introduce additional commands (like bash or PowerShell) the way spec-kit does.
Do you have any better suggestions? Feel free to share them – I’m open to discussing this further!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve also considered the spec file customization risk – We need to restrict users from modifying tags in spec deltas.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TabishB By the way, I’ve already dropped you a message on Discord, PTAL , hh

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @jax-max, I think we're on the same page here. The scaffold should ideally be project-scoped not change scoped, I agree!

The openspec scaffold should generate whatever the project defined template is (Should default to the standard OpenSpec template structure if it has not been modified.)

We can store this somewhere in openspec/tempalate/*

The job of the scaffold command will be to just make a copy of the template into whatever change directory. (So should take as input).

We then need to update the instructions to ask the agent to "fill in the documents" after creation.

I'll try and see if I can create a sequence diagram for this. We just need to be a bit careful with this change and we could possibly degrade the performance/quality of spec generation for current users.

If there's another way to test this out without affecting the core flow, I'd be keen to integrate that first.

I'll work on the scaffold tomorrow and you can let me know if it works the way you expect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @TabishB , That's awesome! I'm really looking forward to the scaffold feature. Regarding "asking the agent to 'fill in the documents' after creation", we actually prefer to handle this step manually. For large-scale backend projects, the agent’s analysis hasn’t been as effective as expected. Anyway, I’m still super excited for the scaffold to go live! Should I close the current PR?

- Removed redundant instruction in proposal steps to streamline the process.
- Clarified the initial reading order for apply steps by omitting the project conventions document, focusing on the proposal and design documents instead.
…pec into feat/ImproveGenCodeQuality

# Conflicts:
#	src/core/templates/slash-command-templates.ts
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/core/templates/slash-command-templates.ts (1)

36-39: Clarify spec-template validation expectations in the template reference

The template variable list and generic “check openspec/templates/<type>.md.template first” rule are clear. To reduce confusion, you might add a short note here that spec templates (and spec fallbacks) must satisfy the same structural validation rules as normal specs (delta sections + requirement and scenario headers), and point to the authoritative section in openspec/AGENTS.md or the spec-template docs.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 085ea1d and 1717e3c.

📒 Files selected for processing (1)
  • src/core/templates/slash-command-templates.ts (2 hunks)
🔇 Additional comments (3)
src/core/templates/slash-command-templates.ts (3)

8-9: Proposal guardrails change looks correct

The added guardrails clearly separate proposal (design-only) work from implementation and should prevent premature coding during the proposal stage.


46-50: Apply steps path update is consistent and clear

Referencing openspec/changes/<id>/proposal.md (plus design.md and tasks.md) keeps the apply flow aligned with the proposal directory structure and resolves the earlier changes/<id>/ vs openspec/changes/<id>/ inconsistency.


63-64: Archive path now matches the openspec changes tree

Updating the archive step to expect changes under openspec/changes/archive/ keeps the lifecycle (proposal → apply → archive) consistently rooted at openspec/changes/ and avoids confusion about where archived changes live.

Comment on lines +13 to +32
2. Choose a unique verb-led \`change-id\` and create the change directory \`openspec/changes/<id>/\`.
3. Create \`proposal.md\` in \`openspec/changes/<id>/\`:
- **CRITICAL**: Check if \`openspec/templates/proposal.md.template\` exists
- If exists: Read the template file and replace variables (\`{{changeId}}\` → actual change-id, \`{{date}}\` → current date in YYYY-MM-DD format)
- If not exists: Use the default structure from \`openspec/AGENTS.md\` (see "Proposal Structure" section)
4. Create \`tasks.md\` in \`openspec/changes/<id>/\`:
- **CRITICAL**: Check if \`openspec/templates/tasks.md.template\` exists
- If exists: Read the template file and replace variables (\`{{changeId}}\` → actual change-id, \`{{date}}\` → current date in YYYY-MM-DD format)
- If not exists: Use the default structure from \`openspec/AGENTS.md\` (see "Proposal Structure" section)
5. Create \`design.md\` in \`openspec/changes/<id>/\` (only when needed—see criteria in \`openspec/AGENTS.md\`):
- **CRITICAL**: Check if \`openspec/templates/design.md.template\` exists
- If exists: Read the template file and replace variables (\`{{changeId}}\` → actual change-id, \`{{date}}\` → current date in YYYY-MM-DD format)
- If not exists: Use the default structure from \`openspec/AGENTS.md\` (see "Proposal Structure" section)
6. Map the change into concrete capabilities or requirements, breaking multi-scope efforts into distinct spec deltas with clear relationships and sequencing.
7. Create spec deltas in \`openspec/changes/<id>/specs/<capability>/spec.md\` (one folder per capability):
- **CRITICAL**: Check if \`openspec/templates/spec.md.template\` exists
- If exists: Read the template file and replace variables (\`{{changeId}}\` → actual change-id, \`{{date}}\` → current date in YYYY-MM-DD format, \`{{capability}}\` → capability name)
- If not exists: Use \`## ADDED|MODIFIED|REMOVED Requirements\` format with at least one \`#### Scenario:\` per requirement
- Cross-reference related capabilities when relevant
8. Validate with \`openspec validate <id> --strict\` and resolve every issue before sharing the proposal.`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Align spec.md fallback instructions with spec-template validation rules

The proposal steps for templates and paths under openspec/changes/<id>/ look solid and consistent, but Line 30’s spec fallback (Use \## ADDED|MODIFIED|REMOVED Requirements` format with at least one `#### Scenario:` per requirement`) doesn’t mention requirement headers, while the PR summary notes that spec-template validation requires both requirement and scenario headers.

Following these instructions as written could produce spec deltas that still fail validation. Consider updating the spec.md bullet(s) to explicitly include whatever “Requirement” heading pattern the validator and AGENTS.md expect (e.g., a Requirement: heading per requirement), and ideally reference the relevant section in openspec/AGENTS.md so authors can mirror the exact structure.

🤖 Prompt for AI Agents
In src/core/templates/slash-command-templates.ts around lines 13 to 32, the
fallback instruction for spec.md omits explicit requirement header guidance
required by the spec-template validator; update the spec.md fallback bullet to
state that each requirement must include the required "Requirement" heading
pattern (e.g., a "Requirement:" or "#### Requirement:" header as used by
AGENTS.md and the validator), and include a short parenthetical mapping to the
exact AGENTS.md section or header pattern to follow (so authors produce a
Requirements header plus at least one "#### Scenario:" per requirement).

@jax-max
Copy link
Contributor Author

jax-max commented Nov 19, 2025

Duplicate with the scaffold's function

@jax-max jax-max closed this Nov 19, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/core/init.test.ts (1)

1613-1613: Move test suite to improve organization.

The "change templates generation" test suite is nested inside the "error handling" describe block but doesn't test error scenarios—it validates feature functionality (default behavior, flag-driven generation, idempotency, etc.). This placement is confusing.

Move this describe block to be a sibling of "error handling" (after line 1611, before line 1613) so the test structure reflects that it's a separate feature area:

     });
+  });
+
+  describe('change templates generation', () => {
+    it('should not generate templates by default', async () => {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1717e3c and 0dad4c8.

📒 Files selected for processing (2)
  • src/core/templates/slash-command-templates.ts (2 hunks)
  • test/core/init.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
test/core/init.test.ts (2)
src/utils/file-system.ts (2)
  • directoryExists (107-117)
  • fileExists (76-86)
src/core/init.ts (1)
  • InitCommand (377-997)
🔇 Additional comments (2)
test/core/init.test.ts (1)

1689-1710: LGTM!

The spec template validation correctly verifies that the generated template includes the required structural elements for archive compatibility: at least one delta section header (ADDED/MODIFIED/REMOVED/RENAMED), requirement headers, and scenario headers.

src/core/templates/slash-command-templates.ts (1)

13-29: LGTM!

The template-driven workflow instructions are well-structured:

  • Clear precedence: check for custom templates first, fall back to AGENTS.md defaults
  • Explicit variable substitution guidance (changeId, date, capability)
  • Consistent pattern across all file types (proposal, tasks, design, spec)
  • Proper integration with the filesystem structure under openspec/changes/<id>/

Also applies to: 37-40

7. Create spec deltas in \`openspec/changes/<id>/specs/<capability>/spec.md\` (one folder per capability):
- **CRITICAL**: Check if \`openspec/templates/spec.md.template\` exists
- If exists: Read the template file and replace variables (\`{{changeId}}\` → actual change-id, \`{{date}}\` → current date in YYYY-MM-DD format, \`{{capability}}\` → capability name)
- If not exists: Use \`## ADDED|MODIFIED|REMOVED Requirements\` format with at least one \`#### Scenario:\` per requirement
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Complete the spec.md fallback instruction.

Line 30 has two gaps that could lead to validation failures:

  1. Missing RENAMED: The instruction lists ADDED|MODIFIED|REMOVED but omits RENAMED, while the test validation (test/core/init.test.ts:1707) expects all four delta types.
  2. Missing requirement header guidance: The instruction only mentions #### Scenario: headers but doesn't specify the requirement header format (e.g., ### Requirement:), while the test (line 1708) expects both.

This issue was flagged in a previous review but remains unresolved.

Apply this diff to add the missing guidance:

-   - If not exists: Use `## ADDED|MODIFIED|REMOVED Requirements` format with at least one `#### Scenario:` per requirement
+   - If not exists: Use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements` format with `### Requirement:` headers and at least one `#### Scenario:` per requirement
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- If not exists: Use \`## ADDED|MODIFIED|REMOVED Requirements\` format with at least one \`#### Scenario:\` per requirement
- If not exists: Use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements` format with `### Requirement:` headers and at least one `#### Scenario:` per requirement
🤖 Prompt for AI Agents
In src/core/templates/slash-command-templates.ts around line 30, the spec.md
fallback instruction is missing guidance for the RENAMED delta type and does not
specify the requirement header format; update the sentence to include all four
delta types (ADDED|MODIFIED|REMOVED|RENAMED) and add explicit requirement header
guidance (e.g., require a `### Requirement:` header for each requirement) while
preserving the existing note that each requirement must include at least one
`#### Scenario:`; ensure the text matches the validation expectations in
test/core/init.test.ts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants