Prompt template schema
Every prompt in Prompt & Profit ships in two forms. Once in the Playbook — in Section 6 of the chapter that uses it, with a worked example, declared variables, and stated failure modes. Once as a downloadable YAML working file inside the Premium bundle, runnable from a notebook or the command line. Both forms carry the same body; the YAML is the source of truth.
The page below is the schema both forms follow. If a prompt template in the Playbook deviates from it, the errata channel is the right place to flag it.
Why a schema
Prompts are not pseudocode. A template in this Playbook is a copy-pasteable artefact you can run against a current GPT-4-class or Claude-class model and get a predictable, useful output. Vague prompts, undeclared variables, and missing worked examples are the single most common reason prompt libraries fail when a second person tries to use them. The schema below is what stops that.
It also doubles as the Playbook’s bibliography of patterns. Appendix A — The Prompt Library — is built directly from the YAML files. Change a template, and the appendix and the runnable file move together.
The schema in one block
id: ch03-long-form-blog-brief # required — chNN-kebab-case-slug, unique
title: Long-Form Blog Post Brief Generator # required — human-readable name
chapter: 3 # required — numeric chapter
job_to_be_done: > # required — 1–2 sentences on what the template produces
Turn a topic + target-keyword pair into a structured blog post brief
with H2 outline, target audience note, and primary angle.
inputs: # required — every variable used in `prompt`
topic: string
primary_keyword: string
audience: string
brand_voice: string
word_count_target: integer
prompt: | # required — the runnable prompt body, using {variables}
You are a senior B2B content strategist at a SaaS company.
Your task is to produce a blog post brief for a writer who will
draft a {word_count_target}-word post on "{topic}", targeting the
keyword "{primary_keyword}" for the audience "{audience}".
Write in the voice: {brand_voice}.
Output: H1, five-H2 outline, primary angle in one sentence,
two competing angles rejected with one-sentence rationale each,
and three internal link suggestions.
worked_example: # required — one complete input set + described output
inputs:
topic: Zero-party data strategy
primary_keyword: zero-party data
audience: B2B marketing leaders at Series B–D SaaS firms
brand_voice: practical, direct, peer-to-peer
word_count_target: 1500
expected_output_summary: >
H1 centred on practitioner framing; five H2s covering definition,
why now, collection mechanics, measurement, and governance;
primary angle rejecting the "death of cookies" framing in favour
of "trust-first data strategy"; two rejected angles; three
internal link candidates.
pro_tip: > # optional — one field-tested refinement
Run this prompt twice with two different brand_voice strings and
compare the outlines — you will learn where your voice is actually
shaping the output versus where it is cosmetic.
failure_modes: # optional — how the prompt breaks in practice
- "Missing audience specificity produces generic outlines."
- "Asking for too many H2s (>7) collapses the outline into a table of contents."
- "Leaving brand_voice vague ('professional') defaults the model to vendor-voice."
model_notes: # optional — any model-specific behaviour
claude_opus: "Holds the structure best on drafts over 1,200 words."
gpt_4o: "Sometimes merges two H2s; run twice if the outline compresses."
tags: # optional — discovery tags for cross-index
- content-brief
- seo
- voice-calibration
Field-by-field
| Field | Purpose |
|---|---|
id | chNN-kebab-case-slug. Unique across the entire library. The handle Section 6 prose uses to point at the YAML |
title | Human-readable name. Used in the appendix table of contents |
chapter | Numeric chapter the template belongs to |
job_to_be_done | One or two sentences describing what the template produces |
inputs | Every variable used in prompt declared with a type. One of string, integer, list, boolean |
prompt | The full runnable body. No placeholders like [insert topic here] — every variable uses {snake_case} and matches an inputs entry |
worked_example | One complete input set with real values plus a described expected output. Not optional — templates without worked examples fail reader comprehension |
pro_tip | Optional. One field-tested refinement — speculative tips do not qualify |
failure_modes | Optional. How the prompt breaks in practice |
model_notes | Optional. Specific behaviour observed on a named model |
tags | Optional. Cross-index tags for the appendix |
The variable convention
Variables are {snake_case}, always. Not {camelCase}, not {TitleCase}. Every variable that appears in the prompt body is declared in inputs — undeclared variables are a bug. Names are marketing-domain, not engineering-domain: {audience} not {target_user_profile}, {primary_goal} not {conversion_objective}.
When a single concept needs multiple values — three voice samples, four reject criteria — use numbered variants: {sample_1}, {sample_2}, {sample_3}.
The worked-example contract
Every prompt ships with a worked example. Real input values, a described expected output. No template that requires you to imagine what the output would look like.
The contract has two parts. The example inputs are concrete enough that you could run them today. The expected output summary describes the structure and substance of what the model returns — three H2s on these topics, an H1 framed this way, a closing paragraph rejecting that angle. Not the verbatim output (which varies run to run), but the recognisable shape.
The quality bar
Every template clears all of the rows below before it ships.
| Dimension | Standard |
|---|---|
| Runnability | Copy-paste the prompt, substitute the worked-example inputs, execute on a current GPT-4-class or Claude-class model. The output matches the expected_output_summary within reasonable tolerance |
| Completeness | id, title, chapter, job_to_be_done, inputs, prompt, worked_example all present and non-empty |
| Determinism | Running twice with identical inputs produces similar structure (exact wording will differ). Wildly divergent outputs mean the prompt is under-specified |
| Model-agnostic by default | Prompts work across models. Anything that requires a specific feature — function calling, extended thinking, long context — is called out in model_notes |
| Density | The prompt body is typically 80 to 400 words. Shorter is under-specified; longer is usually over-constrained and brittle |
| Tested | The prompt has been run end-to-end at least once by the author against at least one model, and the actual output has been compared to expected_output_summary |
How the Playbook references a template
In Section 6 of every chapter, each pattern subsection follows the same shape. The body of the prompt is mirrored verbatim from the YAML; the prose form lets you read the pattern in flow, the YAML lets you run it.
### Pattern 1: Voice-Calibrated Draft
**What it does.** [1–2 sentences]
**When to use it.** [1–2 sentences]
**The prompt.** See **Appendix A — Prompt Library** for the full runnable
template (`prompts/ch03/voice-calibrated-draft.yaml`).
```text
[the prompt body, copied verbatim from the YAML]
Worked example.
Inputs:
{topic}— Zero-party data strategy{audience}— B2B marketing leaders at Series B SaaS firms{word_count_target}— 1,500
Expected output:
- H1 centred on practitioner framing
- Five H2s covering definition, why now, collection mechanics, measurement, and governance
- A primary angle that rejects the “death of cookies” framing
The prose body and the YAML body match. Where they diverge, the YAML wins — and the prose is the bug.
## What the reader holds the Playbook to
The standard, in three lines:
1. Every prompt template in the Playbook has a worked example with real inputs and a described expected output.
2. Every variable in the prompt body is declared in `inputs` with a type.
3. Every template runs on a current GPT-4-class or Claude-class model and produces output recognisable as the described expected output.
If a prompt does not run, [the errata channel](/errata) is the right place to flag it.