Guidance for AI Agents working with this repository.
A sophisticated collection of infrastructure templates (boilerplates) with a Python CLI for management. Supports Terraform, Docker, Ansible, Kubernetes, etc. Built with Typer (CLI) and Jinja2 (templating).
# Run the CLI application
python3 -m cli
# Debugging and Testing commands
python3 -m cli --log-level DEBUG compose listFor detailed information about testing boilerplates in a production-like environment before release, see WARP-LOCAL.md (local file, not in git). This document covers:
- Test server infrastructure and Docker contexts
- Step-by-step testing procedures for Docker Compose, Swarm, and Kubernetes
- Comprehensive testing checklists
- Production release criteria
Should always happen before pushing anything to the repository.
- Use
yamllintfor YAML files - Use
rufffor Python code:ruff check --fix .- Check and auto-fix linting errors (including unused imports)ruff format .- Format code according to style guidelines- Both commands must be run before committing
The project is stored in a public GitHub Repository, use issues, and branches for features/bugfixes and open PRs for merging.
Naming Conventions and Best-Practices:
- Branches, PRs:
feature/2314-add-feature,problem/1249-fix-bug - Issues should have clear titles and descriptions, link related issues/PRs, and have appropriate labels like (problem, feature, discussion, question).
- Commit messages should be clear and concise, following the format:
type(scope): subject(e.g.,fix(compose): correct variable parsing).
cli/- Python CLI application source codecli/core/- Core Components of the CLI applicationcli/core/schema/- JSON schema definitions for all modulescli/modules/- Modules implementing technology-specific functionscli/__main__.py- CLI entry point, auto-discovers modules and registers commands
library/- Template collections organized by modulelibrary/ansible/- Ansible playbooks and configurationslibrary/compose/- Docker Compose configurationslibrary/docker/- Docker templateslibrary/kubernetes/- Kubernetes deploymentslibrary/packer/- Packer templateslibrary/terraform/- OpenTofu/Terraform templates and examples
archetypes/- Testing tool for template snippets (archetype development)archetypes/__init__.py- Package initializationarchetypes/__main__.py- CLI tool entry pointarchetypes/<module>/- Module-specific archetype snippets (e.g.,archetypes/compose/)
cli/core/collection.py- VariableCollection class (manages sections and variables)- Key Attributes:
_sections(dict of VariableSection objects),_variable_map(flat lookup dict) - Key Methods:
get_satisfied_values()(returns enabled variables),apply_defaults(),sort_sections()
- Key Attributes:
cli/core/config.py- Configuration management (loading, saving, validation)cli/core/display/- Centralized CLI output rendering package (Always use DisplayManager - never print directly)__init__.py- Package exports (DisplayManager, DisplaySettings, IconManager)display_manager.py- Main DisplayManager facadedisplay_settings.py- DisplaySettings configuration classicon_manager.py- IconManager for Nerd Font iconsvariable_display.py- VariableDisplayManager for variable renderingtemplate_display.py- TemplateDisplayManager for template displaystatus_display.py- StatusDisplayManager for status messagestable_display.py- TableDisplayManager for table rendering
cli/core/exceptions.py- Custom exceptions for error handling (Always use this for raising errors)cli/core/library.py- LibraryManager for template discovery from git-synced libraries and static file pathscli/core/module.py- Abstract base class for modules (defines standard commands)cli/core/prompt.py- Interactive CLI prompts using rich librarycli/core/registry.py- Central registry for module classes (auto-discovers modules)cli/core/repo.py- Repository management for syncing git-based template librariescli/core/schema/- Schema management package (JSON-based schema system)loader.py- SchemaLoader class for loading and validating JSON schemas<module>/- Module-specific schema directories (e.g.,compose/,terraform/)<module>/v*.json- Version-specific JSON schema files (e.g.,v1.0.json,v1.2.json)
cli/core/section.py- VariableSection class (stores section metadata and variables)- Key Attributes:
key,title,toggle,needs,variables(dict of Variable objects)
- Key Attributes:
cli/core/template.py- Template Class for parsing, managing and rendering templatescli/core/variable.py- Variable class (stores variable metadata and values)- Key Attributes:
name,type,value(stores default or current value),description,sensitive,needs - Note: Default values are stored in
valueattribute, NOT in a separatedefaultattribute
- Key Attributes:
cli/core/validators.py- Semantic validators for template content (Docker Compose, YAML, etc.)cli/core/version.py- Version comparison utilities for semantic versioning
Module Structure: Modules can be either single files or packages:
- Single file:
cli/modules/modulename.py(for simple modules) - Package:
cli/modules/modulename/with__init__.py(for multi-schema modules)
Creating Modules:
- Subclass
Modulefromcli/core/module.py - Define
name,description, andschema_versionclass attributes - For multi-schema modules: organize specs in separate files (e.g.,
spec_v1_0.py,spec_v1_1.py) - Call
registry.register(YourModule)at module bottom - Auto-discovered and registered at CLI startup
Module Discovery and Registration:
The system automatically discovers and registers modules at startup:
- Discovery: CLI
__main__.pyimports all Python files incli/modules/directory - Registration: Each module file calls
registry.register(ModuleClass)at module level - Storage: Registry stores module classes in a central dictionary by module name
- Command Generation: CLI framework auto-generates subcommands for each registered module
- Instantiation: Modules are instantiated on-demand when commands are invoked
Benefits:
- No manual registration needed - just add a file to
cli/modules/ - Modules are self-contained - can be added/removed without modifying core code
- Type-safe - registry validates module interfaces at registration time
Module Schema System:
JSON Schema Architecture (Refactored from Python specs):
All module schemas are now defined as JSON files in cli/core/schema/<module>/v*.json. This provides:
- Version control: Easy schema comparison and diffs in git
- Language-agnostic: Schemas can be consumed by tools outside Python
- Validation: Built-in JSON schema validation
- Documentation: Self-documenting schema structure
Schema File Location:
cli/core/schema/
compose/
v1.0.json
v1.1.json
v1.2.json
terraform/
v1.0.json
ansible/
v1.0.json
...other modules...
JSON Schema Structure:
Schemas are arrays of section objects, where each section contains:
[
{
"key": "section_key",
"title": "Section Title",
"description": "Optional section description",
"toggle": "optional_toggle_variable_name",
"needs": "optional_dependency",
"required": true,
"vars": [
{
"name": "variable_name",
"type": "str",
"description": "Variable description",
"default": "default_value",
"required": true,
"sensitive": false,
"autogenerated": false,
"options": ["option1", "option2"],
"needs": "other_var=value",
"extra": "Additional help text"
}
]
}
]Schema Loading in Modules:
Modules load JSON schemas on-demand using the SchemaLoader:
from cli.core.schema import load_schema, has_schema, list_versions
class MyModule(Module):
name = "mymodule"
schema_version = "1.2" # Latest version supported
def get_spec(self, template_schema: str) -> OrderedDict:
"""Load JSON schema and convert to dict format."""
json_spec = load_schema(self.name, template_schema)
# Convert JSON array to OrderedDict format
return self._convert_json_to_dict(json_spec)Schema Design Principles:
- Backward compatibility: Newer module versions can load older template schemas
- Auto-created toggle variables: Sections with
toggleautomatically create boolean variables - Conditional visibility: Variables use
needsconstraints to show/hide based on other variable values - Mode-based organization: Related settings grouped by operational mode (e.g., network_mode, volume_mode)
- Incremental evolution: New schemas add features without breaking existing templates
Working with Schemas:
- View available versions: Check
cli/core/schema/<module>/directory or uselist_versions(module) - Add new schema version: Create new JSON file following naming convention (e.g.,
v1.3.json) - Update module: Increment
schema_versionin module class when adding new schema - Validate schemas: SchemaLoader automatically validates JSON structure on load
Migration from Python Specs:
Older Python-based spec_v*.py files have been migrated to JSON. The module __init__.py now:
- Loads JSON schemas using SchemaLoader
- Converts JSON array format to OrderedDict for backward compatibility
- Provides lazy loading via
_SchemaDictclass
Existing Modules:
cli/modules/compose/- Docker Compose (JSON schemas: v1.0, v1.1, v1.2)- Other modules (ansible, terraform, kubernetes, helm, packer) - Work in Progress
(Work in Progress): terraform, docker, ansible, kubernetes, packer modules
- Loads libraries from config file
- Stores Git Libraries under:
~/.config/boilerplates/libraries/{name}/ - Uses sparse-checkout to clone only template directories for git-based libraries (avoiding unnecessary files)
- Supports two library types: git (synced from repos) and static (local directories)
- Priority determined by config order (first = highest)
Library Types:
git: Requiresurl,branch,directoryfieldsstatic: Requirespathfield (absolute or relative to config)
Duplicate Handling:
- Within same library: Raises
DuplicateTemplateError - Across libraries: Uses qualified IDs (e.g.,
alloy.default,alloy.local) - Simple IDs use priority:
compose show alloyloads from first library - Qualified IDs target specific library:
compose show alloy.local
Config Example:
libraries:
- name: default # Highest priority (checked first)
type: git
url: https://github.com/user/templates.git
branch: main
directory: library
- name: local # Lower priority
type: static
path: ~/my-templates
url: '' # Backward compatibility fields
branch: main
directory: .Note: Static libraries include dummy url/branch/directory fields for backward compatibility with older CLI versions.
- User Config stored in
~/.config/boilerplates/config.yaml
CRITICAL RULE - NEVER violate this:
- NEVER use
console.print()outside of display manager classes (cli/core/display/directory) - NEVER import
Consolefromrich.consoleexcept in display manager classes orcli/__main__.py - ALWAYS use
module_instance.display.display_*()ordisplay.display_*()methods for ALL output - Display managers (
cli/core/display/*.py) are the ONLY exception - they implement console output
Rationale:
DisplayManagerprovides a centralized interface for ALL CLI output rendering- Direct console usage bypasses formatting standards, icon management, and output consistency
IconManagerprovides Nerd Font icons internally for DisplayManager - never use emojis or direct icons
DisplayManager Architecture (Refactored for Single Responsibility Principle):
DisplayManager acts as a facade that delegates to specialized manager classes:
-
VariableDisplayManager - Handles all variable-related rendering
render_variable_value()- Variable value formatting with context awarenessrender_section()- Section header displayrender_variables_table()- Complete variables table with dependencies
-
TemplateDisplayManager - Handles all template-related rendering
render_template()- Main template display coordinatorrender_template_header()- Template metadata displayrender_file_tree()- Template file structure visualizationrender_file_generation_confirmation()- Files preview before generation
-
StatusDisplayManager - Handles status messages and error display
display_message()- Core message formatting with level-based routingdisplay_error(),display_warning(),display_success(),display_info()- Convenience methodsdisplay_template_render_error()- Detailed render error displaydisplay_warning_with_confirmation()- Interactive warning prompts
-
TableDisplayManager - Handles table rendering
render_templates_table()- Templates list with library indicatorsrender_status_table()- Status tables with success/error indicatorsrender_config_tree()- Configuration tree visualization
Usage Pattern:
# External code uses DisplayManager methods (backward compatible)
display = DisplayManager()
display.display_template(template, template_id)
# Internally, DisplayManager delegates to specialized managers
# display.templates.render_template(template, template_id)Design Principles:
- External code calls
DisplayManagermethods only DisplayManagerdelegates to specialized managers internally- Each specialized manager has a single, focused responsibility
- Backward compatibility maintained through delegation methods
- All managers can access parent DisplayManager via
self.parent
Templates are directory-based. Each template is a directory containing all the necessary files and subdirectories for the boilerplate.
How templates are loaded and rendered:
- Discovery: LibraryManager finds template directories containing
template.yaml/template.yml - Parsing: Template class loads and parses the template metadata and spec
- Schema Resolution: Module's
get_spec()loads appropriate spec based on template'sschemafield - Variable Inheritance: Template inherits ALL variables from module schema
- Variable Merging: Template spec overrides are merged with module spec (precedence: module < template < user config < CLI)
- Collection Building: VariableCollection is constructed with merged variables and sections
- Dependency Resolution: Sections are topologically sorted based on
needsconstraints - Variable Resolution: Variables with
needsconstraints are evaluated for visibility - Jinja2 Rendering: Template files (
.j2) are rendered with final variable values - Sanitization: Rendered output is cleaned (whitespace, blank lines, trailing newline)
- Validation: Optional semantic validation (YAML structure, Docker Compose schema, etc.)
Key Architecture Points:
- Templates don't "call" module specs - they declare a schema version and inherit from it
- Variable visibility is dynamic based on
needsconstraints (evaluated at prompt/render time) - Jinja2 templates support
{% include %}and{% import %}for composition
Requires template.yaml or template.yml with metadata and variables:
---
kind: compose
schema: "X.Y" # Optional: Defaults to "1.0" if not specified (e.g., "1.0", "1.2")
metadata:
name: My Service Template
description: A template for a service.
version: 1.0.0
author: Your Name
date: '2024-01-01'
spec:
general:
vars:
service_name:
type: str
description: Service nameTemplate Version Field:
The metadata.version field in template.yaml should reflect the version of the underlying application or resource:
- Compose templates: Match the Docker image version (e.g.,
nginx:1.25.3→version: 1.25.3) - Terraform templates: Match the provider version (e.g., AWS provider 5.23.0 →
version: 5.23.0) - Other templates: Match the primary application/tool version being deployed
- Use
latestor increment template-specific version (e.g.,0.1.0,0.2.0) only when no specific application version applies
Rationale: This helps users identify which version of the application/provider the template is designed for and ensures template versions track upstream changes.
Application Version Variables:
- IMPORTANT: Application/image versions should be hardcoded in template files (e.g.,
image: nginx:1.25.3) - Do NOT create template variables for application versions (e.g., no
nginx_versionvariable) - Users should update the template file directly when they need a different version
- This prevents version mismatches and ensures templates are tested with specific, known versions
- Exception: Only create version variables if there's a strong technical reason (e.g., multi-component version pinning)
Version Format: Schemas use 2-level versioning in MAJOR.MINOR format (e.g., "1.0", "1.2", "2.0").
Templates and modules use schema versioning to ensure compatibility. Each module defines a supported schema version, and templates declare which schema version they use.
---
kind: compose
schema: "X.Y" # Optional: Defaults to "1.0" if not specified (e.g., "1.0", "1.2")
metadata:
name: My Template
version: 1.0.0
# ... other metadata fields
spec:
# ... variable specificationsHow It Works:
- Module Schema Version: Each module defines
schema_version(e.g., "1.0", "1.2", "2.0") - Module Spec Loading: Modules load appropriate spec based on template's schema version
- Template Schema Version: Each template declares
schemaat the top level (defaults to "1.0") - Compatibility Check: Template schema ≤ Module schema → Compatible
- Incompatibility: Template schema > Module schema →
IncompatibleSchemaVersionError
Behavior:
- Templates without
schemafield default to "1.0" (backward compatible) - Older templates work with newer module versions (backward compatibility)
- Templates with newer schema versions fail on older modules with
IncompatibleSchemaVersionError - Version comparison uses MAJOR.MINOR format (e.g., "1.0" < "1.2" < "2.0")
When to Use:
- Increment module schema version when adding new features (new variable types, sections, etc.)
- Set template schema when using features from a specific schema version
- Templates using features from newer schemas must declare the appropriate schema version
Single-File Module Example:
class SimpleModule(Module):
name = "simple"
description = "Simple module"
schema_version = "X.Y" # e.g., "1.0", "1.2"
spec = VariableCollection.from_dict({...}) # Single specMulti-Schema Module Example:
# cli/modules/modulename/__init__.py
class ExampleModule(Module):
name = "modulename"
description = "Module description"
schema_version = "X.Y" # Highest schema version supported (e.g., "1.2", "2.0")
def get_spec(self, template_schema: str) -> VariableCollection:
"""Load spec based on template schema version."""
# Dynamically load the appropriate spec version
# template_schema will be like "1.0", "1.2", etc.
version_file = f"spec_v{template_schema.replace('.', '_')}"
spec_module = importlib.import_module(f".{version_file}", package=__package__)
return spec_module.get_spec()Version Management:
- CLI version is defined in
cli/__init__.pyas__version__ - pyproject.toml version must match
__version__for releases - GitHub release workflow validates version consistency
- Jinja2 Templates (
.j2): Rendered by Jinja2,.j2extension removed in output. Support{% include %}and{% import %}. - Static Files: Non-
.j2files copied as-is. - Sanitization: Auto-sanitized (single blank lines, no leading blanks, trimmed whitespace, single trailing newline).
- Shortcodes: Template descriptions support emoji-style shortcodes (e.g.,
:warning:,:info:,:docker:) which are automatically replaced with Nerd Font icons during display. Add new shortcodes toIconManager.SHORTCODESdict.
Traefik Integration:
When using Traefik with Docker Compose, the traefik.docker.network label is CRITICAL for stacks with multiple networks. When containers are connected to multiple networks, Traefik must know which network to use for routing.
Implementation:
- Review
archetypes/compose/directory for reference implementations of Traefik integration patterns - The
traefik.docker.network={{ traefik_network }}label must be present in both standardlabels:anddeploy.labels:sections - Standard mode and Swarm mode require different label configurations - check archetypes for examples
How Templates Inherit Variables:
Templates automatically inherit ALL variables from the module schema version they declare. The template's schema: "X.Y" field determines which module spec is loaded, and all variables from that schema are available.
When to Define Template Variables:
You only need to define variables in your template's spec section when:
- Overriding defaults: Change default values for module variables (e.g., hardcode
service_namefor your specific app) - Adding custom variables: Define template-specific variables not present in the module schema
- Upgrading to newer schema: To use new features, update
schema: "X.Y"to a higher version - no template spec changes needed
Variable Precedence (lowest to highest):
- Module
spec(defaults for all templates of that kind) - Template
spec(overrides module defaults) - User
config.yaml(overrides template and module defaults) - CLI
--var(highest priority)
Template Variable Override Rules:
- Override module defaults: Only specify properties that differ from module spec (e.g., change
defaultvalue) - Create new variables: Define template-specific variables not in module spec
- Minimize duplication: Do NOT re-specify
type,description, or other properties if they remain unchanged from module spec
Example:
# Template declares schema: "1.2" → inherits ALL variables from compose schema 1.2
# Template spec ONLY needs to override specific defaults:
spec:
general:
vars:
service_name:
default: whoami # Only override the default, type already defined in module
# All other schema 1.2 variables (network_mode, volume_mode, etc.) are automatically availableVariable Types:
str(default),int,float,boolemail- Email validation with regexurl- URL validation (requires scheme and host)hostname- Hostname/domain validationenum- Choice fromoptionslist
Variable Properties:
sensitive: true- Masked in prompts/display (e.g., passwords)autogenerated: true- Auto-generates value if empty (shows*autoplaceholder)default- Default valuedescription- Variable descriptionprompt- Custom prompt text (overrides description)extra- Additional help textoptions- List of valid values (for enum type)
Section Features:
- Toggle Settings: Conditional sections via
toggle: "bool_var_name". If false, section is skipped.- IMPORTANT: When a section has
toggle: "var_name", that boolean variable is AUTO-CREATED by the system - Toggle variable behavior may vary by schema version - check current schema documentation
- Example:
portssection withtoggle: "ports_enabled"automatically providesports_enabledboolean
- IMPORTANT: When a section has
- Dependencies: Use
needs: "section_name"orneeds: ["sec1", "sec2"]. Dependent sections only shown when dependencies are enabled.
Dependency Resolution Architecture:
Sections and variables support needs constraints to control visibility based on other variables.
Section-Level Dependencies:
- Format:
needs: "section_name"orneeds: ["sec1", "sec2"] - Section only appears when all required sections are enabled (their toggle variables are true)
- Automatically validated: detects circular, missing, and self-dependencies
- Topologically sorted: ensures dependencies are prompted/processed before dependents
Variable-Level Dependencies:
- Format:
needs: "var_name=value"orneeds: "var1=val1;var2=val2"(semicolon-separated) - Variable only visible when constraint is satisfied (e.g.,
needs: "network_mode=bridge") - Supports multiple values:
needs: "network_mode=bridge,macvlan"(comma = OR) - Evaluated dynamically at prompt and render time
Validation:
- Circular dependencies: Raises error if A needs B and B needs A
- Missing dependencies: Raises error if referencing non-existent sections/variables
- Self-dependencies: Raises error if section depends on itself
Example Section with Dependencies:
spec:
traefik:
title: Traefik
required: false
toggle: traefik_enabled
vars:
traefik_enabled:
type: bool
default: false
traefik_host:
type: hostname
traefik_tls:
title: Traefik TLS/SSL
needs: traefik
toggle: traefik_tls_enabled
vars:
traefik_tls_enabled:
type: bool
default: true
traefik_tls_certresolver:
type: str
sensitive: false
default: myresolverJinja2 Validation:
- Templates validated for Jinja2 syntax errors during load
- Checks for undefined variables (variables used but not declared in spec)
- Built into Template class
Semantic Validation:
- Validator registry system in
cli/core/validators.py - Extensible:
ContentValidatorabstract base class - Built-in validators:
DockerComposeValidator,YAMLValidator - Validates rendered output (YAML structure, Docker Compose schema, etc.)
- Triggered via
compose validatecommand with--semanticflag (enabled by default)
Uses rich library for interactive prompts. Supports:
- Text input
- Password input (masked, for
sensitive: truevariables) - Selection from list (single/multiple)
- Confirmation (yes/no)
- Default values
- Autogenerated variables (show
*autoplaceholder, generate on render)
To skip the prompt use the --no-interactive flag, which will use defaults or empty values.
Standard Module Commands (auto-registered for all modules):
list- List all templatessearch <query>- Search templates by IDshow <id>- Show template detailsgenerate <id> -o <directory>- Generate from template (supports--dry-run,--var,--no-interactive)validate [template_id]- Validate template(s) (Jinja2 + semantic). Omit template_id to validate all templatesdefaults- Manage config defaults (get,set,rm,clear,list)
Core Commands:
repo sync- Sync git-based librariesrepo list- List configured libraries
The archetypes package provides reusable, standardized template building blocks for creating boilerplates. Archetypes are modular Jinja2 snippets that represent specific configuration sections.
- Template Development: Provide standardized, tested building blocks for creating new templates
- Testing & Validation: Enable testing of specific configuration sections in isolation with different variable combinations
# List available archetypes for a module
python3 -m archetypes compose list
# Preview an archetype component
python3 -m archetypes compose generate <archetype-name>
# Test with variable overrides
python3 -m archetypes compose generate <archetype-name> \
--var traefik_enabled=true \
--var swarm_enabled=true
# Validate templates against archetypes
python3 -m archetypes compose validate # All templates
python3 -m archetypes compose validate <template> # Single templateThe validate command compares templates against archetypes to measure coverage and identify which archetype patterns are being used.
What it does:
- Compares each template file against all available archetypes using structural pattern matching
- Abstracts away specific values to focus on:
- Jinja2 control flow:
{% if %},{% elif %},{% else %},{% for %}structures - YAML structure: Key names, indentation, and nesting patterns
- Variable usage patterns: Presence of
{{ }}placeholders (not specific names) - Wildcard placeholders:
__ANY__,__ANYSTR__,__ANYINT__,__ANYBOOL__ - Repeat markers:
{# @repeat-start #}/{# @repeat-end #} - Optional markers:
{# @optional-start #}/{# @optional-end #}
- Jinja2 control flow:
- This allows detection of archetypes even when specific values differ (e.g.,
grafana_datavsalloy_data) - Calculates containment ratio: what percentage of each archetype structure is found within the template
- Reports usage status: exact (≥95%), high (≥70%), partial (≥30%), or none (<30%)
- Provides coverage metrics: (exact + high matches) / total archetypes
Archetypes support special annotations for flexible pattern matching:
Wildcard Placeholders (match any value):
__ANY__- Matches anything__ANYSTR__- Matches any string__ANYINT__- Matches any integer__ANYBOOL__- Matches any boolean
Repeat Markers (pattern can appear 1+ times):
{# @repeat-start #}
pattern
{# @repeat-end #}Optional Markers (section may or may not exist):
{# @optional-start #}
pattern
{# @optional-end #}Example:
volumes:
{# @repeat-start #}
__ANY__:
driver: local
{# @repeat-end #}Matches any number of volumes with driver: local
Usage:
# Validate all templates in library - shows summary table
python3 -m archetypes compose validate
# Validate specific template - shows detailed archetype breakdown
python3 -m archetypes compose validate whoami
# Validate templates in custom location
python3 -m archetypes compose validate --library /path/to/templatesOutput:
- Summary mode (all templates): Table showing exact/high/partial/none counts and coverage % per template
- Detail mode (single template): Table showing each archetype's status, similarity %, and matching file
Use cases:
- Quality assurance: Ensure templates follow established patterns
- Refactoring: Identify templates that could benefit from archetype alignment
- Documentation: Track which archetypes are most/least used across templates
- Discover: Use
listcommand to see available archetype components for your module - Review: Preview archetypes to understand implementation patterns
- Copy: Copy relevant archetype components to your template directory
- Customize: Modify as needed (hardcode image, add custom labels, etc.)
- Validate: Use
compose validateto check Jinja2 syntax and semantic correctness
Key Concepts:
- Each module can have its own
archetypes/<module>/directory with reusable components archetypes.yamlconfigures schema version and variable overrides for testing- Components are modular Jinja2 files that can be tested in isolation or composition
- Testing only: The
generatecommand NEVER writes files - always shows preview output
How it works:
- Loads module spec based on schema version from
archetypes.yaml - Merges variable sources: module spec → archetypes.yaml → CLI --var
- Renders using Jinja2 with support for
{% include %}directives