This file provides guidance to AI Agents when working with code in this repository.
This repository contains a sophisticated collection of templates (called boilerplates) for managing infrastructure across multiple technologies including Terraform, Docker, Ansible, Kubernetes, etc. The project also includes a Python CLI application that allows an easy management, creation, and deployment of boilerplates.
The CLI is a Python application built with Typer for the command-line interface and Jinja2 for templating.
cli/ - Python CLI application source code
cli/core/ - Core functionality (app, config, commands, logging)cli/modules/ - Technology-specific modules (terraform, docker, compose, config, etc.)library/ - Template collections organized by module
library/ansible/ - Ansible playbooks and configurationslibrary/compose/ - Docker Compose configurationslibrary/docker/ - Docker templateslibrary/kubernetes/ - Kubernetes deploymentslibrary/packer/ - Packer templateslibrary/terraform/ - OpenTofu/Terraform templates and examples# List available commands
python3 -m cli
# List templates for a module
python3 -m cli compose list
# Debugging commands
python3 -m cli --log-level DEBUG compose list
# Generate template to directory named after template (default)
python3 -m cli compose generate nginx
# Generate template to custom directory
python3 -m cli compose generate nginx my-nginx-server
# Generate template interactively (default - prompts for variables)
python3 -m cli compose generate authentik
# Generate template non-interactively (skips prompts, uses defaults and CLI variables)
python3 -m cli compose generate authentik my-auth --no-interactive
# Generate with variable overrides (non-interactive)
python3 -m cli compose generate authentik my-auth \
--var service_name=auth \
--var ports_enabled=false \
--var database_type=postgres \
--no-interactive
# Show template details
python3 -m cli compose show authentik
# Managing default values
python3 -m cli compose defaults set service_name my-app
python3 -m cli compose defaults get
python3 -m cli compose defaults list
The CLI application is built with a modular and extensible architecture.
cli/__main__.py: The main entry point using Typer. It dynamically discovers and imports modules from the cli/modules directory, registering their commands with the main application.
cli/core/registry.py: Provides a ModuleRegistry which acts as a central store for all discovered module classes. This avoids magic and keeps module registration explicit.
cli/core/module.py: Defines the abstract Module base class. Each technology (e.g., compose, terraform) is a subclass of Module. It standardizes the list, search, show, and generate commands and handles their registration.
cli/core/library.py: Implements the LibraryManager and Library classes, which are responsible for finding template files within the library/ directory. It supports a priority system, allowing different template sources to override each other.
cli/core/template.py: Contains the Template class, which is the heart of the engine. It parses a template file, separating the YAML frontmatter (metadata, variable specifications) from the Jinja2 content. It intelligently merges variable definitions from both the module and the template file.
cli/core/variables.py: Defines the data structures for managing variables:
Variable: Represents a single variable, including its type, validation rules, and default value.VariableSection: Groups variables into logical sections for better presentation and conditional logic.VariableCollection: Manages the entire set of sections and variables for a template.cli/core/prompt.py: The PromptHandler provides the interactive CLI experience. It uses the rich library to prompt the user for variable values, organized by the sections defined in the VariableCollection.
cli/core/display.py: The DisplayManager handles all output rendering using rich. It provides consistent and visually appealing displays for lists, search results, variable summaries, and error messages.
Templates are directory-based. Each template is a directory containing all the necessary files and subdirectories for the boilerplate.
Every template directory must contain a main template file named either template.yaml or template.yml. This file serves as the entry point and contains the template's metadata and variable specifications in YAML frontmatter format.
Example template.yaml:
---
kind: compose
metadata:
name: My Nginx Template
description: >
A template for a simple Nginx service.
Project: https://...
Source: https://
Documentation: https://
version: 0.1.0
author: Christian Lempa
date: '2024-10-01'
spec:
general:
vars:
nginx_version:
type: string
description: The Nginx version to use.
default: latest
Jinja2 Templates (.j2): Any file within the template directory that has a .j2 extension will be rendered by the Jinja2 engine. The .j2 extension is removed from the final output file name (e.g., config.json.j2 becomes config.json). These files can use {% include %} and {% import %} statements to share code with other files in the template directory.
Static Files: Any file without a .j2 extension is treated as a static file and will be copied to the output directory as-is, preserving its relative path and filename.
Content Sanitization: All rendered Jinja2 templates are automatically sanitized to improve output quality:
library/compose/my-nginx-template/
├── template.yaml
├── compose.yaml.j2
├── config/
│ └── nginx.conf.j2
└── static/
└── README.md
Variables are a cornerstone of the CLI, allowing for dynamic and customizable template generation. They are defined and processed with a clear precedence and logic.
1. Definition and Precedence:
Variables are sourced and merged from multiple locations, with later sources overriding earlier ones:
spec (Lowest Precedence): Each module (e.g., cli/modules/compose.py) can define a base spec dictionary. This provides default variables and sections for all templates of that kind.spec: The spec block within the template.yaml or template.yml file can override or extend the module's spec. This is the single source of truth for defaults within the template.--var) (Highest Precedence): Providing a variable via the command line (--var KEY=VALUE) has the highest priority and will override any default or previously set value.The Variable.origin attribute is updated to reflect this chain (e.g., module -> template -> cli).
2. Required Sections:
spec can be marked as required: true.general section is implicitly required by default.3. Toggle Settings (Conditional Sections):
toggle property to the name of a boolean variable within that same section.toggle: "advanced_enabled"bool. This is validated at load-time by VariableCollection._validate_section_toggle().false), all other variables within that section are skipped, and the section is visually dimmed in the summary table. This provides a clean way to manage optional or advanced configurations.4. Section Dependencies:
needs property.needs: "traefik" or needs: ["database", "redis"] for multiple dependencies.⊘ Section Name (skipped - requires dependency_name to be enabled).traefik (basic) and traefik_tls (needs traefik) sections.database_backup (needs database) or monitoring_alerts (needs monitoring).email (basic) and email_advanced (needs email) sections.Example Section with Dependencies:
spec:
traefik:
title: "Traefik"
toggle: "traefik_enabled"
vars:
traefik_enabled:
type: "bool"
default: false
traefik_host:
type: "hostname"
traefik_tls:
title: "Traefik TLS/SSL"
needs: "traefik" # Only shown if traefik is enabled
toggle: "traefik_tls_enabled"
vars:
traefik_tls_enabled:
type: "bool"
default: true
traefik_tls_certresolver:
type: "str"
template.yaml or template.yml fileconfig/)config module instead of using complex directory structuresdescription, default, or extra properties in the template spec rather than creating a new variable.external_url, smtp_port)type and provide sensible default valuessensitive: true and autogenerated: true for auto-generated secretspwgen filter for password generation: {{ secret_key if secret_key else (none | pwgen(50)) }}Example: For the Traefik template, use the existing authentik section from the module spec instead of creating custom authentik_middleware_* variables. Override the section's description and extra to provide Traefik-specific guidance.
.j2 extension and always use | default() filter for safe fallbacksservice_name, container_name, container_timezone, restart_policyauthentik_secret_key, gitea_root_url)database_type, database_enabled, database_external, database_host, database_port, database_name, database_user, database_passwordnetwork_enabled, network_name, network_externaltraefik_enabled, traefik_host, traefik_tls_enabled, traefik_tls_entrypoint, traefik_tls_certresolverports_enabled, ports_http, ports_https, ports_sshemail_enabled, email_host, email_port, email_username, email_password, email_fromUse separate .env.{service}.j2 files for different services (e.g., .env.authentik.j2, .env.postgres.j2):
env_file directive in compose.yaml.j2# Database Connection)database_enabled, email_enabled, traefik_enabled, ports_enabled, network_enableddepends_on for startup ordering and use named volumes for persistence{% if not database_external %} for conditional service creationrestart: {{ restart_policy | default('unless-stopped') }}