Template Customization
SpecifyX uses Jinja2 templates to generate consistent project artifacts. This guide covers how to customize existing templates and create your own templates for specifications, plans, tasks, and scripts.
Template System Overview
SpecifyX uses a structured template system with multiple categories:
Template Categories
- Runtime Templates - Core specification and planning templates
- Command Templates - AI assistant-specific commands
- Script Templates - Python utility scripts
- Memory Templates - Project constitution and context
Template Structure
.specify/
├── templates/ # Project runtime templates
│ ├── spec-template.md.j2
│ ├── plan-template.md.j2
│ └── task-template.md.j2
├── commands/ # AI assistant commands
│ ├── claude/
│ ├── gemini/
│ └── copilot/
└── scripts/ # Utility scripts
├── deploy-feature.py.j2
└── review-code.py.j2
Template Variables
Templates have access to built-in and custom variables:
Built-in Variables
project_name
- Current project namefeature_name
- Current feature namebranch_name
- Current branch namedate
- Current dateai_assistant
- Selected AI assistantis_windows
- Platform detectionbranch_patterns
- Available branch naming patternsvalidation_rules
- Branch validation rulestemplate_variables
- Custom template variables from config
Context Variables
feature_description
- User-provided feature descriptionspec_id
- Specification IDauthor_name
- Author name from configcompany_name
- Company name from config
Customizing Runtime Templates
Runtime templates define the structure of specifications, plans, and tasks.
Specification Template
Edit .specify/templates/spec-template.md.j2
to customize your specification format:
# Feature Specification: {{ feature_name | default('[FEATURE NAME]') }}
**Feature Branch**: `{{ branch_name | default('[###-feature-name]') }}`
**Created**: {{ date | default('[DATE]') }}
**Author**: {{ template_variables.author_name | default('[AUTHOR]') }}
## Overview
{{ feature_description | default('[Describe what this feature does and why it\'s needed]') }}
## User Stories
{% if ai_assistant == 'claude' %}
*Use Claude to help refine these user stories*
{% endif %}
### Primary User Story
As a [user type], I want [goal] so that [benefit].
## Requirements
- **FR-001**: System MUST [capability]
- **FR-002**: Users MUST be able to [action]
{% if template_variables.include_security_section %}
## Security Considerations
- Authentication requirements
- Authorization rules
- Data protection needs
{% endif %}
## Success Criteria
- [ ] [Measurable outcome]
- [ ] [User feedback metric]
## Implementation Plan
### Phase 1: Foundation
- [ ] Setup development environment
- [ ] Create project structure
### Phase 2: Core Development
- [ ] Implement core functionality
- [ ] Add unit tests
### Phase 3: Integration
- [ ] API endpoints
- [ ] Frontend integration
- [ ] End-to-end testing
{% if template_variables.database != 'none' %}
## Database Design
### Entities
- **{{ feature_name | title }}**: [Primary entity description]
### Relationships
- [Entity] → [Related Entity]: [Relationship type]
{% endif %}
## API Design
```http
POST /api/{{ feature_name | lower }}
GET /api/{{ feature_name | lower }}/:id
PUT /api/{{ feature_name | lower }}/:id
DELETE /api/{{ feature_name | lower }}/:id
Testing Strategy
- Unit Tests: [Coverage targets]
- Integration Tests: [Key scenarios]
- Performance Tests: [Benchmarks]
{% if ai_assistant == 'claude' %}
## Claude Code Integration
- Use subagents for complex implementations
- Leverage code review workflow
- Use `/tasks` to break down implementation
{% endif %}
Plan Template
Edit .specify/templates/plan-template.md.j2
for implementation planning:
# Implementation Plan: {{ feature_name | default('[FEATURE NAME]') }}
**Specification**: [Link to spec file]
**Branch**: `{{ branch_name }}`
**Created**: {{ date }}
**Tech Stack**: {{ template_variables.tech_stack | default('[SPECIFY TECH STACK]') }}
## Architecture Overview
- **Framework**: {{ template_variables.framework | default('[FRAMEWORK]') }}
- **Database**: {{ template_variables.database | default('[DATABASE]') }}
- **API Style**: {{ template_variables.api_style | default('[REST/GraphQL/etc]') }}
## Development Tasks
### Backend Tasks
{% if template_variables.has_backend %}
- [ ] **BE-001**: Implement data models
- [ ] **BE-002**: Create API endpoints
{% endif %}
### Frontend Tasks
{% if template_variables.has_frontend %}
- [ ] **FE-001**: Create UI components
- [ ] **FE-002**: Implement user interactions
{% endif %}
### Testing Tasks
- [ ] **TEST-001**: Write unit tests
- [ ] **TEST-002**: Integration testing
## Definition of Done
- [ ] Code reviewed and approved
- [ ] Unit tests pass (90%+ coverage)
- [ ] Integration tests pass
- [ ] Documentation updated
- [ ] Performance benchmarks met
- [ ] Security review completed
{% if ai_assistant == 'claude' %}
## Claude Code Workflow
1. Create feature branch: `{{ branch_name }}`
2. Use `/tasks` command to track progress
3. Request code review when ready
4. Use subagents for complex implementations
{% endif %}
Jinja2 Template Features
Conditionals
Create AI-specific content:
{% if ai_assistant == 'claude' %}
Use the `/specify` command to create specifications.
{% elif ai_assistant == 'gemini' %}
Use Gemini Code to create specifications.
{% elif ai_assistant == 'copilot' %}
Use GitHub Copilot to create specifications.
{% endif %}
Loops
Iterate over collections:
{% for pattern in branch_patterns %}
- {{ pattern }}
{% endfor %}
Filters
Transform data:
# {{ feature_name | title }}
# {{ feature_name | lower }}
# {{ feature_name | upper }}
# {{ date | default('[DATE]') }}
Macros for Reusable Content
Define reusable template snippets:
{% macro requirement(id, description, priority='medium') %}
- **{{ id }}**: {{ description }} *(Priority: {{ priority }})*
{% endmacro %}
## Requirements
{{ requirement('FR-001', 'User authentication', 'high') }}
{{ requirement('FR-002', 'Data validation', 'medium') }}
{{ requirement('FR-003', 'Error handling', 'low') }}
Template Inheritance
Create base templates and extend them:
{# base-spec.j2 #}
# {{ feature_name | default('[FEATURE NAME]') }}
**Branch**: {{ branch_name }}
**Created**: {{ date }}
{% block overview %}
## Overview
[Feature overview]
{% endblock %}
{% block requirements %}
## Requirements
[Feature requirements]
{% endblock %}
{% block acceptance %}
## Acceptance Criteria
[Acceptance criteria]
{% endblock %}
Extend base templates:
{# api-spec.j2 #}
{% extends "base-spec.j2" %}
{% block overview %}
## API Feature Overview
This feature adds new API endpoints to {{ project_name }}.
{% endblock %}
{% block requirements %}
{{ super() }}
### API Requirements
- RESTful endpoints
- OpenAPI documentation
- Rate limiting
{% endblock %}
Custom Script Templates
Create custom utility scripts:
#!/usr/bin/env python3
"""
Deploy feature script for {{ project_name }}
This script handles the deployment of the current feature branch.
Generated by SpecifyX for {{ ai_assistant }} workflow.
"""
import sys
from pathlib import Path
def deploy_feature():
"""Deploy the current feature branch"""
print(f"Deploying feature branch: {get_current_branch()}")
# Run deployment steps
steps = [
{% if template_variables.has_tests %}
("Running tests", "{{ template_variables.test_command | default('npm test') }}"),
{% endif %}
{% if template_variables.has_build %}
("Building project", "{{ template_variables.build_command | default('npm run build') }}"),
{% endif %}
("Deploying to {{ template_variables.deployment_platform | default('production') }}",
"{{ template_variables.deploy_command | default('npm run deploy') }}")
]
for step_name, command in steps:
print(f"Step: {step_name}")
# Execute command logic here
print(f"Deployment URL: {{ template_variables.deployment_url | default('[URL]') }}")
return True
if __name__ == "__main__":
deploy_feature()
Template Testing
Validation
Test your templates with the specifyx check
command:
specifyx check templates
Common Issues
-
Missing endif tags
{# ❌ Wrong: Missing endif #}
{% if condition %}
Content here
{# ✅ Correct: Matched tags #}
{% if condition %}
Content here
{% endif %} -
Undefined variables
{# ❌ Wrong: Undefined variable #}
{{ missing_variable }}
{# ✅ Correct: Use default filter #}
{{ missing_variable | default('[DEFAULT VALUE]') }} -
Performance issues
{# ❌ Slow: Complex loops #}
{% for i in range(1000) %}
{{ complex_operation(i) }}
{% endfor %}
{# ✅ Better: Precompute values #}
{% set computed_values = precompute_values() %}
{% for value in computed_values %}
{{ value }}
{% endfor %}
Best Practices
Template Design
- Keep templates focused - One template per purpose
- Use meaningful defaults - Provide helpful placeholder text
- Include validation - Add checks for required variables
- Document variables - Comment template variables and their purpose
Variable Naming
- Use descriptive names -
feature_description
notdesc
- Follow conventions -
snake_case
for variables - Group related variables - Use
template_variables
namespace - Provide defaults - Always use
| default()
for optional variables
Conditional Logic
- Keep conditions simple - Avoid deeply nested conditionals
- Use meaningful conditions -
has_backend
notflag1
- Provide fallbacks - Always have an
else
clause when appropriate - Test edge cases - Verify templates work with all variable combinations
Next Steps
- Configuration Management - Configure template variables
- Best Practices Guide - Template design best practices