Scaffold API¶
The fcc.scaffold package provides the documentation generator, the Jinja2
template engine, and CLI commands for project scaffolding and doc generation.
All CLI operations have programmatic equivalents.
flowchart TD
CLI[fcc CLI] --> init[fcc init]
CLI --> add[fcc add-persona]
CLI --> sim[fcc simulate]
CLI --> gen[fcc generate-docs]
CLI --> val[fcc validate-docs]
CLI --> dash[fcc dashboard]
gen --> DG[DocGenerator]
DG --> J2[Jinja2 Templates]
DG --> PR[PersonaRegistry]
J2 --> OUT[Generated Markdown Files]
PR --> OUT
DocGenerator¶
DocGenerator is the core engine behind the fcc generate-docs CLI command.
It accepts a PersonaRegistry, resolves template topics from YAML data, and
writes documentation files via Jinja2 templates.
Generating All Documentation¶
from pathlib import Path
from fcc._resources import get_data_dir, get_personas_dir
from fcc.personas.registry import PersonaRegistry
from fcc.scaffold.doc_generator import DocGenerator
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
gen = DocGenerator(registry, data_dir=get_data_dir())
output_dir = Path("docs")
total = gen.generate_all_docs(output_dir)
print(f"Generated {total} files")
generate_all_docs produces:
- Per-persona documentation (index, specification, constitution, coordination, prompts, tutorials, workflows, package) -- approximately 56 files per persona
- Cross-reference documentation (matrix, coordination methods, constitution framework) -- 3 files
- SITEMAP.md -- 1 file
Generating for a Subset of Personas¶
Pass a list of persona IDs to restrict output.
total = gen.generate_all_docs(
output_dir=Path("docs"),
persona_ids=["RC", "BC", "DE"],
)
print(f"Generated {total} files for 3 personas")
Generating Individual Components¶
from pathlib import Path
from fcc._resources import get_data_dir, get_personas_dir
from fcc.personas.registry import PersonaRegistry
from fcc.personas.cross_reference import CrossReferenceMatrix
from fcc.scaffold.doc_generator import DocGenerator
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
gen = DocGenerator(registry, data_dir=get_data_dir())
output_dir = Path("docs")
# Single persona documentation
file_count = gen.generate_persona_docs("RC", output_dir)
print(f"RC docs: {file_count} files")
# Cross-reference documentation (requires a matrix)
matrix = CrossReferenceMatrix.from_yaml(
get_personas_dir() / "cross_reference.yaml"
)
file_count = gen.generate_cross_reference(matrix, output_dir)
print(f"Cross-reference: {file_count} files")
# Sitemap only
file_count = gen.generate_sitemap(output_dir)
print(f"Sitemap: {file_count} file")
Constructor Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
registry |
PersonaRegistry |
(required) | The personas to generate docs for |
templates_dir |
Path or None |
Bundled templates | Override the Jinja2 templates directory |
data_dir |
Path or None |
Bundled data | Override the data directory for topics and constitution |
Custom Templates Directory¶
You can override the template directory to use your own Jinja2 templates while keeping the same generation logic.
from pathlib import Path
from fcc.personas.registry import PersonaRegistry
from fcc.scaffold.doc_generator import DocGenerator
registry = PersonaRegistry.from_yaml_directory("my_project/personas/")
gen = DocGenerator(
registry,
templates_dir=Path("my_project/templates"),
data_dir=Path("my_project/data"),
)
total = gen.generate_all_docs(Path("my_project/docs"))
Template Engine¶
The fcc.scaffold.engine module provides lower-level Jinja2 template
rendering functions.
get_jinja_env¶
Creates a configured Jinja2 Environment pointing at the specified
templates directory. The environment uses trim_blocks and lstrip_blocks
for clean output.
from fcc._resources import get_templates_dir
from fcc.scaffold.engine import get_jinja_env
env = get_jinja_env(get_templates_dir())
# List available template names
print(env.list_templates())
render_template¶
Renders a single template file with a context dictionary.
from fcc._resources import get_templates_dir, get_personas_dir
from fcc.personas.registry import PersonaRegistry
from fcc.scaffold.engine import render_template
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
persona = registry.get("RC")
content = render_template(
template_path="docs/persona/specification.md.j2",
context={
"persona": persona,
"doc_context": persona.doc_context or {},
"default_constitution": {},
"tutorial_count": 21,
"prompt_count": 21,
},
templates_dir=get_templates_dir(),
)
print(content[:200])
render_to_file¶
Renders a template and writes the result to a file, creating parent directories as needed.
from pathlib import Path
from fcc.scaffold.engine import render_to_file
render_to_file(
template_path="docs/persona/index.md.j2",
output_path=Path("output/rc/index.md"),
context={"persona": persona, "doc_context": {}, "default_constitution": {},
"tutorial_count": 21, "prompt_count": 21},
)
CLI Programmatic Equivalents¶
Every fcc CLI command has a direct programmatic equivalent. Here is
a mapping of CLI commands to Python API calls.
fcc init¶
from pathlib import Path
from fcc.scaffold.project import init_project
config = init_project(Path("./my-project"), "My Project")
print(f"Personas: {len(config.personas)}")
fcc add-persona¶
from pathlib import Path
from fcc.scaffold.project import add_persona
persona = add_persona(Path("./my-project"), "CA", "Custom Analyst", "Find")
print(f"Added: {persona.name} ({persona.id})")
fcc simulate¶
from pathlib import Path
from fcc.simulation.ai_client import AIClient, AIProvider
from fcc.simulation.ai_engine import AISimulationEngine, write_ai_traces
from fcc.workflow.graph import WorkflowGraph
graph = WorkflowGraph.from_json(Path("data/workflows/base_sequence.json"))
client = AIClient(provider=AIProvider.MOCK)
engine = AISimulationEngine(graph, ai_client=client, max_steps=20)
result = engine.run(start_node="RC", scenario_id="GEN-001")
write_ai_traces([result], "traces_ai.json")
print(f"Steps: {result.total_steps}, AI calls: {result.total_ai_calls}")
fcc generate-docs¶
from pathlib import Path
from fcc._resources import get_data_dir, get_personas_dir
from fcc.personas.registry import PersonaRegistry
from fcc.scaffold.doc_generator import DocGenerator
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
gen = DocGenerator(registry, data_dir=get_data_dir())
total = gen.generate_all_docs(Path("docs"))
print(f"Generated {total} files")
fcc generate-docs --personas core¶
from pathlib import Path
from fcc._resources import get_data_dir, get_personas_dir
from fcc.personas.registry import PersonaRegistry
from fcc.scaffold.doc_generator import DocGenerator
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
core_ids = [p.id for p in registry.by_category("core")]
gen = DocGenerator(registry, data_dir=get_data_dir())
total = gen.generate_all_docs(Path("docs"), persona_ids=core_ids)
print(f"Generated {total} files for core personas")
fcc validate-docs¶
from pathlib import Path
doc_dir = Path("docs")
persona_dir = doc_dir / "fcc" / "personas"
md_files = list(persona_dir.rglob("*.md"))
print(f"Found {len(md_files)} documentation files")
issues = [f for f in md_files if not f.read_text().strip()]
if issues:
print(f"Empty files: {len(issues)}")
else:
print("Validation passed")
fcc sitemap¶
from pathlib import Path
from fcc._resources import get_data_dir, get_personas_dir
from fcc.personas.registry import PersonaRegistry
from fcc.scaffold.doc_generator import DocGenerator
registry = PersonaRegistry.from_yaml_directory(get_personas_dir())
gen = DocGenerator(registry, data_dir=get_data_dir())
gen.generate_sitemap(Path("docs"))