Templates & Authoring
repospec init seeds a repository's .repospec/ from the bundled templates in @repospec/templates. Templates are shipped in the package (not fetched at runtime) so init is deterministic and offline (ADR-0006). This page explains what they produce and how to author or customize them.
What templates produce
Templates render only the human-owned source under .repospec/ — the constitution, architecture, workflow, and the starter agents and rules. They do not render tool entrypoints like CLAUDE.md or AGENTS.md; those are generated from .repospec/ by adapters in the engine and carry a managed header (ADR-0004). Keep the line clear: templates seed what a human then owns and edits; adapters generate what the tool regenerates.
getSeedDocuments(project) returns the seed files for a validated project:
import { getSeedDocuments } from '@repospec/templates';
for (const { path, contents } of getSeedDocuments(project)) {
// path is relative to .repospec/, e.g. "constitution.md", "agents/reviewer.md"
}project.yaml itself is not a template — the engine serializes it from the validated configuration.
Interpolation
Seed content is filled from the init answers with a small substitution engine. interpolate replaces {{ dotted.path }} placeholders from a variable tree and throws on a missing variable — a loud failure beats a silent blank in a generated document.
import { interpolate, partials } from '@repospec/templates';
const TEMPLATE = `# Architecture — {{ project.name }}
${partials.seededNote}
This is a **{{ project.type }}**.
`;
const md = interpolate(TEMPLATE, { project: project.project });- Whitespace inside the braces is ignored:
{{project.name}}and{{ project.name }}are equivalent. - Paths resolve into nested objects (
{{ project.name }}readsvars.project.name). - A referenced variable that is missing or
null/undefinedthrows.
Partials
partials holds reusable snippets shared across documents, so common prose lives in one place. Today it exports seededNote (the notice at the top of every seeded document). Compose partials into templates with a normal template literal, as shown above.
Customizing the seed content
The seed content lives in @repospec/templates/src/content/. To change what new repositories start with, edit those modules — each is a small function returning Markdown, using interpolate + partials for anything derived from the project. Keep two rules in mind:
- Deterministic and offline. No network, no clock, no randomness — the same project must always produce the same seed (ADR-0006).
- Human-owned output only. Never emit a managed header or anything a human shouldn't own; generated entrypoints are the adapters' job.
Adapters vs. templates
Templates (@repospec/templates) | Adapters (@repospec/engine) | |
|---|---|---|
| Produce | human-owned .repospec/ source | generated tool entrypoints |
| When | once, at init | every generate / sync |
| Ownership | human edits freely afterward | managed header; regenerated |
| Add one by | editing content/ | implementing the Adapter interface |
To target a new assistant, add an adapter (see packages/engine/src/adapters/), not a template. Templates are for what the human authors; adapters are for what the tool keeps in sync.