template.yaml manifest plus supporting prose (TEMPLATE.md, composition.md, hooks.md, prompt-cookbook.md). Public templates are served from the hosted content library (Supabase); your own author into .ralphy/workspaces/<ws>/templates/<slug>/ (user-local). The old repo-public templates/<category>/<slug>/ folder was retired in #084. This page is the wire-format spec: the manifest Zod schema, the two kinds, the segment categories, the slug discipline, and the version gate.
Full example
A minimalvibe-style template at .ralphy/workspaces/<ws>/templates/brand-story/template.yaml:
vibe-reference template adds a composition.md walkthrough plus a reference/ folder of worked artifacts alongside the manifest. Both kinds use the same schema.
File layout
.ralphy/workspaces/<ws>/templates/ is flat (no category subdir). When a slug exists in both, workspace overrides repo — per AGENTS invariant #10.
Zod schema
cli/lib/schemas/template.ts exports TemplateYamlSchema. Field-by-field:
category — the five segment-persona folders
templates/. The lint walks only these five.
kind — vibe-reference vs vibe-style
Five
vibe-reference templates ship in repo; 38 vibe-style. Both kinds are loadable by ralphy template use <slug>.
requires
diagnoseRequiredInputs() checks the user’s project inputs against this block and returns the first missing requirement. Callers map the result to E_TEMPLATE_INPUT_MISSING. The refs field is a single count for v1.0; the 3-slot {cref, sref, pref} shape lands post-launch (decision D-02).
scenes — optional scaffolding
vibe-reference templates fill this in. vibe-style templates leave it as [].
A worked vibe-reference scenes block:
Scenario conforming to cli/lib/schemas/scene.ts → ScenarioSchema. The full scene shape (with vo_text, camera, lighting, gesture, broll, refs, notes) is the scenarist’s output contract, not the template’s input. See Memory schemas and the scenarist playbook for the downstream shape.
Gesture vocabulary
When the template’sdirection field hints at a body-language beat, the scenarist may attach a gesture to the resulting scene. The vocabulary is the finite enum in cli/lib/schemas/gestures.ts:
Scene.notes (the free-text escape hatch), never in direction. The enum is closed by design (decision D-06) — adapters silently omit unknown values rather than throw, so a forward-compatible PR that adds a new gesture degrades gracefully on older binaries.
Slug discipline
Slugs are kebab-case. The regex:Banned tokens
DENIED_SLUG_TOKENS in cli/lib/schemas/template.ts blocks real-creator and brand tokens from appearing in slugs. The match is whole-token (delimited by start, end, or hyphen) so arogant-pov is fine but joe-rogan-pod is not.
Currently denied:
TEMPLATE.md / composition.md — never in the slug. The rule is decision D-05: archetypal slugs only.
validateSlug(slug) returns {ok: true} or {ok: false, reason, token?}. Callers build E_TEMPLATE_SLUG_INVALID from the rejection payload.
Version gating
template.yaml must declare version: 1. The loader in cli/lib/templater/loader.ts → parseTemplateManifest() reads the version field first; if it is not in SUPPORTED_VERSIONS = [1], the loader calls raiseError("E_TEMPLATE_VERSION_UNSUPPORTED", {version, id}) and exits.
scenes[] eventually gains a required field, the loader keeps a v1 reader alive for at least one major-release cycle (decision D-03). Authors bump version: 2 only when the schema breaks compatibly.
Manifest discovery
locateTemplateManifest(dir) prefers template.yaml, then falls back to template.json for not-yet-migrated templates (02.05.04 migration window). Both shapes parse through the same Zod schema. New templates should land as .yaml only.
Slug resolution
ralphy template use <slug> resolves a slug across both tiers:
- Search
.ralphy/workspaces/<ws>/templates/<slug>/template.yaml. - If not found, look the slug up in the public content library (Supabase).
- If still not found, search aliases (
aliases: [old-slug]).
Validation
The manifest parses through the v1 Zod loader (cli/lib/templater/loader.ts) on every ralphy template show / use. It enforces:
- The category is one of
TEMPLATE_CATEGORIES. - The slug passes
validateSlug()— kebab-case, no banned tokens. template.yaml(or legacytemplate.json) is present and parses without throwing.
lint:templates script was retired with the templates/ folder in #084 — there is no longer a committed repo catalog to walk.)
Authoring checklist
- Pick a category. One of
b2b-saas,dtc-commerce,creator-lifestyle,entertainment-viral,cinematic-narrative. - Pick a slug. Kebab-case, no creator names.
- Decide the kind.
vibe-referenceif you’re shipping a full production with refs;vibe-styleif you’re shipping a prompt cookbook. - Write
template.yamlat.ralphy/workspaces/<ws>/templates/<slug>/. Start withversion: 1, fill required fields, default the rest. - Write
TEMPLATE.md. Human-readable overview. Creator references go here, not in the slug. - For
vibe-reference: addcomposition.md(the narrated walkthrough) andreference/(worked artifacts). - For
vibe-style: addhooks.md(hook library) andprompt-cookbook.md(per-modality fragments). - Run
ralphy template register <slug>thenralphy template suggest "<your test brief>". Verify the new template surfaces with a sensible score. - To publish to the public Library, use the
templater/dev-publish-templatepath.
Related
- CLI:
ralphy template—list,suggest,use,show. - Library — every published template, browsable.
- Concepts: templates — what a template is, narrated.
cli/lib/schemas/template.ts— the Zod source.cli/lib/templater/loader.ts— the loader / validator.