Custom Documentation Templates¶
This tutorial covers the FCC Jinja2 template system: how templates work, what variables are available, how to create new templates, and how to integrate them with the DocGenerator.
How the Template System Works¶
FCC uses Jinja2 templates to generate documentation files for each persona. The DocGenerator class loads templates from a templates directory, renders them with persona-specific context, and writes the output as Markdown files.
The built-in templates live at src/fcc/templates/docs/ and produce a comprehensive documentation suite for each persona:
| Template | Output | Purpose |
|---|---|---|
persona/index.md.j2 |
index.md |
Persona landing page |
persona/specification.md.j2 |
specification.md |
Full R.I.S.C.E.A.R. specification |
persona/constitution.md.j2 |
constitution.md |
Constitution rules (hard_stop, mandatory, preferred) |
persona/coordination.md.j2 |
coordination.md |
Collaboration map and handoff details |
persona/prompts/index.md.j2 |
prompts/index.md |
Prompt catalog index |
persona/prompts/prompt.md.j2 |
prompts/{id}.md |
Individual prompt pages |
persona/tutorials/index.md.j2 |
tutorials/index.md |
Tutorial catalog index |
persona/tutorials/tutorial.md.j2 |
tutorials/{id}.md |
Individual tutorial pages |
persona/workflows/index.md.j2 |
workflows/index.md |
Workflow catalog index |
persona/workflows/workflow.md.j2 |
workflows/{id}.md |
Individual workflow pages |
persona/package/index.md.j2 |
package/index.md |
Package summary |
cross-reference/matrix.md.j2 |
Cross-reference matrix | Persona interaction map |
cross-reference/coordination-methods.md.j2 |
Coordination methods | How personas coordinate |
cross-reference/constitution-framework.md.j2 |
Constitution framework | Shared governance rules |
sitemap.md.j2 |
SITEMAP.md | Full documentation sitemap |
Template Variables¶
When rendering a persona template, the DocGenerator provides these context variables:
Core Variables¶
| Variable | Type | Description |
|---|---|---|
persona |
PersonaSpec |
The full persona specification object |
persona.id |
str |
Short ID (e.g., "RC") |
persona.name |
str |
Full name (e.g., "Research Crafter") |
persona.fcc_phase |
str |
FCC phase (Find, Create, Critique, All, Orchestration) |
persona.role_title |
str |
Professional title |
persona.color |
str |
Hex color code |
persona.category |
str |
Category (core, integration, governance, stakeholder, champion) |
persona.riscear |
RISCEARSpec |
Full R.I.S.C.E.A.R. specification |
persona.deliverables |
list |
Named deliverables with descriptions |
persona.collaboration |
list |
Collaboration relationships |
R.I.S.C.E.A.R. Variables¶
Access via persona.riscear:
| Variable | Type |
|---|---|
persona.riscear.role |
str |
persona.riscear.inputs |
list[str] |
persona.riscear.style |
str |
persona.riscear.constraints |
list[str] |
persona.riscear.expected_output |
list[str] |
persona.riscear.archetype |
str |
persona.riscear.responsibilities |
list[str] |
persona.riscear.role_skills |
list[str] |
persona.riscear.role_collaborators |
list[str] |
persona.riscear.role_adoption_checklist |
list[str] |
Documentation Context Variables¶
| Variable | Type | Description |
|---|---|---|
doc_context |
dict |
Documentation generation context |
doc_context.primary_action |
str |
Primary action verb |
doc_context.primary_output |
str |
Primary output type |
doc_context.constitution |
dict |
Constitution rules |
default_constitution |
dict |
Shared default constitution |
tutorial_count |
int |
Number of tutorials generated |
prompt_count |
int |
Number of prompts generated |
Creating a New Template¶
Step 1: Create the Template File¶
Create a Jinja2 template with .j2 extension:
Example template content:
---
title: "Security Review - {{ persona.name }}"
---
# Security Review: {{ persona.name }}
## Overview
This document provides security review guidelines for the **{{ persona.name }}** ({{ persona.id }}) persona.
**Phase:** {{ persona.fcc_phase }}
**Archetype:** {{ persona.riscear.archetype }}
## Constraints
{% for constraint in persona.riscear.constraints %}
- {{ constraint }}
{% endfor %}
## Constitution Rules
### Hard Stops
{% if doc_context and doc_context.constitution %}
{% for rule in doc_context.constitution.hard_stop %}
- {{ rule }}
{% endfor %}
{% endif %}
### Mandatory
{% if doc_context and doc_context.constitution %}
{% for rule in doc_context.constitution.mandatory %}
- {{ rule }}
{% endfor %}
{% endif %}
## Deliverables
| Deliverable | Description |
|---|---|
{% for d in persona.deliverables %}
| {{ d.name }} | {{ d.description }} |
{% endfor %}
## Collaboration
{% for c in persona.collaboration %}
- **{{ c.target }}** ({{ c.direction }}): {{ c.interaction }}
{% endfor %}
Step 2: Use Jinja2 Features¶
FCC templates support standard Jinja2 features:
{# Comments #}
{# Conditionals #}
{% if persona.champion_of %}
This persona is a champion of {{ persona.champion_of }}.
{% endif %}
{# Loops with index #}
{% for skill in persona.riscear.role_skills %}
{{ loop.index }}. {{ skill }}
{% endfor %}
{# Filters #}
{{ persona.name | upper }}
{{ persona.riscear.role | truncate(100) }}
{# Default values #}
{{ doc_context.get('primary_action', 'documentation') }}
Integrating with DocGenerator¶
Option 1: Override the Templates Directory¶
Point the DocGenerator to your custom templates directory:
from pathlib import Path
from fcc.personas.registry import PersonaRegistry
from fcc.scaffold.doc_generator import DocGenerator
registry = PersonaRegistry.from_yaml_directory("data/personas/")
generator = DocGenerator(
registry=registry,
templates_dir=Path("my_project/templates/"),
)
# Generate docs using your custom templates
count = generator.generate_all_docs(Path("output/docs"))
print(f"Generated {count} files")
Your custom templates directory should mirror the structure of the built-in templates:
my_project/templates/
docs/
persona/
index.md.j2
specification.md.j2
security-review.md.j2 # Your custom template
cross-reference/
matrix.md.j2
sitemap.md.j2
Option 2: Extend the DocGenerator¶
For more control, subclass DocGenerator and add custom rendering:
from fcc.scaffold.doc_generator import DocGenerator
class CustomDocGenerator(DocGenerator):
def generate_persona_docs(self, persona_id, output_dir):
# Call parent to generate standard docs
count = super().generate_persona_docs(persona_id, output_dir)
# Add custom security review
persona = self.registry.get(persona_id)
slug = persona.id.lower()
base = output_dir / "fcc" / "personas" / persona.category / slug
doc_ctx = persona.doc_context or {}
self._write(
"docs/persona/security-review.md.j2",
base / "security-review.md",
{"persona": persona, "doc_context": doc_ctx},
)
count += 1
return count
Template Data Sources¶
The DocGenerator loads additional data from YAML files in the data/docs/ directory:
| File | Purpose | Used By |
|---|---|---|
tutorial_topics.yaml |
Tutorial titles and outcomes per difficulty level | Tutorial templates |
prompt_topics.yaml |
Prompt titles and descriptions per difficulty level | Prompt templates |
constitution_template.yaml |
Default constitution rules and workflow definitions | Constitution and workflow templates |
You can provide custom versions of these files via the data_dir parameter:
generator = DocGenerator(
registry=registry,
templates_dir=Path("my_project/templates/"),
data_dir=Path("my_project/data/"),
)
Output Structure¶
The DocGenerator produces a structured output directory:
output/docs/fcc/personas/
core/
rc/
index.md
specification.md
constitution.md
coordination.md
prompts/
index.md
prompt-001.md
...
tutorials/
index.md
tutorial-001.md
...
workflows/
index.md
...
package/
index.md
integration/
cia/
...
governance/
...
stakeholder/
...
champion/
...
cross-reference-matrix.md
coordination-methods.md
constitution-framework.md
SITEMAP.md
Each persona gets approximately 56 files. With 24 personas plus cross-reference and sitemap files, the full generation produces approximately 1,348 documentation files.
Next Steps¶
- Custom Quality Gates -- Add quality validation for your custom templates
- Custom Personas -- Create personas to use with your templates
- Custom Scenarios -- Validate your templates through simulation scenarios