-
Notifications
You must be signed in to change notification settings - Fork 955
Feat/custom-template #307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/custom-template #307
Conversation
- 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.
WalkthroughAdds optional template generation to init: a CLI Changes
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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.
Example instruction:
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. Comment |
There was a problem hiding this 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 targetedThe 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 inloadTemplate
loadTemplatecurrently treats anyfs.readFilefailure 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
ENOENTfrom 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
maybeGenerateChangeTemplatesmethod has clear logic and good user feedback. However, ifChangeTemplateManager.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
📒 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 solidThe 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
hasCustomTemplatesandwriteDefaultTemplatesdo exactly what’s needed for the init flow (skip when atemplates/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 correctRe-exporting
ChangeTemplateManager,ChangeTemplateType, andTemplateContextfrom this index keeps template APIs centralized and matches the existing pattern in this module.src/cli/index.ts (1)
41-45: Init--templatesflag is correctly threaded intoInitCommandThe new
--templatesboolean option and the extended action signature cleanly passtemplates: options?.templatesintoInitCommand, matching the updatedInitCommandOptionsshape. 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 comprehensiveThe new
change templates generationsuite exercises all key paths: no-op by default, generation whentemplates: 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 themaybeGenerateChangeTemplatesbehavior inInitCommand.src/core/templates/slash-command-templates.ts (1)
33-37: Template variable docs are consistent with the template engineThe
proposalReferencessection 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 withChangeTemplateManagerandTemplateContext. 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
templatesfield is properly added as an optional parameter and stored in the class. This follows the existing pattern fortoolsand 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.
TabishB
left a comment
There was a problem hiding this 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). |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this 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 referenceThe template variable list and generic “check
openspec/templates/<type>.md.templatefirst” 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 inopenspec/AGENTS.mdor the spec-template docs.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 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 correctThe 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 clearReferencing
openspec/changes/<id>/proposal.md(plusdesign.mdandtasks.md) keeps the apply flow aligned with the proposal directory structure and resolves the earlierchanges/<id>/vsopenspec/changes/<id>/inconsistency.
63-64: Archive path now matches the openspec changes treeUpdating the archive step to expect changes under
openspec/changes/archive/keeps the lifecycle (proposal → apply → archive) consistently rooted atopenspec/changes/and avoids confusion about where archived changes live.
| 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.`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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).
|
Duplicate with the scaffold's function |
There was a problem hiding this 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
📒 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complete the spec.md fallback instruction.
Line 30 has two gaps that could lead to validation failures:
- Missing RENAMED: The instruction lists
ADDED|MODIFIED|REMOVEDbut omitsRENAMED, while the test validation (test/core/init.test.ts:1707) expects all four delta types. - 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.
| - 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.
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:
Changes
Core Implementation
src/core/templates/change-templates.ts(192 lines)ChangeTemplateManagerclass for template loading and rendering{{changeId}},{{date}}, and{{capability}}CLI Enhancement
Modified:
src/cli/index.ts--templatesoption toopenspec initcommandModified:
src/core/init.tsDocumentation Updates
Modified:
src/core/templates/agents-template.tsModified:
src/core/templates/slash-command-templates.tsTesting
New:
test/core/templates/change-templates.test.ts(445 lines)loadTemplate()for all scenariosModified:
test/core/init.test.tsTechnical Details
Template System Architecture
The template system follows a layered approach:
openspec/templates/directoryVariable 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:
## ADDED|MODIFIED|REMOVED|RENAMED Requirements### Requirement:#### Scenario:Invalid templates trigger a warning and fall back to the default template to prevent breaking the archive functionality.
Usage
Generating Default Templates
This command creates the following template files in
openspec/templates/:proposal.md.templatetasks.md.templatedesign.md.templatespec.md.templateCustomizing 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:
openspec/templates/Backward Compatibility
This feature is fully backward compatible:
--templatesflag is usedTesting
Files Changed
Summary by CodeRabbit
New Features
Documentation
Tests