# Playbooks

Write a playbook when a team must build the same kind of thing more than once,
and the hard part is the decisions, not the typing. A playbook is an
actionable blueprint for one pattern. It records the build order, the
constraints, and the traps. It isn't a tutorial, and it isn't a reference.

This playbook is the source standard for every playbook on this site. The one
rule: give the reader the decisions and the traps, and prove each one with
evidence.

## Core model

A playbook answers eight questions for one pattern:

- What does the reader have when they finish?
- Which concepts and invariants does every step depend on?
- When is this pattern the right tool, and when is it the wrong one?
- What are the parts?
- In what order does the reader build them?
- Which mistakes look correct but fail later?
- How does the reader prove that it works?
- Which evidence supports each claim?

The reader is a capable developer or an agent. The reader can write the code.
The reader doesn't know the non-obvious decisions. The playbook supplies those
decisions.

## When to use it

Write a playbook when two or more of these conditions are true:

- The team built this pattern at least once, and will build it again.
- The first build found traps that a second build will hit again.
- The correct build order isn't obvious.
- An agent must follow the pattern without a human in the loop.
- A technology has security, release, or platform rules that a team must
  apply on every project.

Don't write a playbook for these cases:

- A pattern with no evidence. Build it once, or find the primary
  documentation, then write it down. A playbook from memory or theory has the
  wrong traps.
- A step-by-step tutorial for one product. Put it under `guide/`.
- A list of flags, fields, or endpoints. Put it under `reference/`.
- A rule that a script can check. Write the script instead.

## Parts

Write the parts in this order.

| Part | Required | Purpose |
|---|---|---|
| Frontmatter | Yes | The title, the description, and the last updated date |
| Opening | Yes | What the reader builds, when, the scope, and the one rule |
| Core model | Yes | The concepts and the invariants that every step depends on |
| When to use it | Yes | The conditions for use, and the conditions against use |
| Baseline | No | The prerequisites, the default stack, and what to commit |
| Parts | No | A table of every component and its purpose |
| Build order | Yes | Numbered steps, in dependency order |
| Minimum viable version | No | The first release, and what waits for later |
| Change workflow | No | The sequence for each later change |
| Design rules | No | The principles that apply across all steps |
| Anti-patterns | Yes | Each mistake, its failure mode, and the accepted pattern |
| Verification | Yes | The pass signals and the checklists |
| Sources | No | The primary documents behind the claims |

The required parts are the minimum viable playbook. Add an optional part when
its trigger applies:

- Baseline: the reader needs tools, accounts, or a default stack before
  step 1.
- Parts: the reader builds distinct components separately.
- Minimum viable version: the parts can ship in stages.
- Change workflow: the team extends the result again and again, for example
  one feature at a time.
- Design rules: a principle applies to more than one step.
- Sources: the claims come from external documentation.

Also add an optional part when a reader asks the same question twice.

## Build order

### 1. Collect the evidence

Base every playbook on evidence. Use one or both of these sources:

- A real implementation: a repository, a project, or a pull request that
  proves the pattern.
- Primary documentation: the official documentation for the technology.

Read the evidence before you write. Each step in the playbook must trace to
it. If you have no evidence, stop. Build the pattern once, or find the
primary documentation.

### 2. Write the frontmatter

Every playbook starts with this frontmatter:

```yaml
---
title: Feature Flags
description: How to add feature flags to a web application
lastUpdated: 2026-09-25
---
```

Follow these rules:

- `title`: the short name of the pattern or the technology. Not "How to" and
  not "Playbook".
- `description`: one sentence that starts with "How to".
- `lastUpdated`: an ISO date, `YYYY-MM-DD`. Starlight shows it in the page
  footer.

Change `lastUpdated` on every change to the content. Don't change it for a
typo or a formatting fix. The date tells the reader how much to trust the
content.

Keep one date only. Don't write a second date in the body. Two dates can
disagree, and the reader can't tell which one is correct.

Don't add a `#` heading. Starlight shows the `title` as the page heading.

### 3. Write the opening

Write one paragraph that starts with "Build a X when...", "Write a X
when...", or "Use this playbook to...". State what the thing is in one or two
sentences.

Then write the scope:

- The basis: the reference implementation, or the documentation.
- The target version, when the version changes the guidance.
- The recheck trigger, when the playbook depends on external documentation.
  For example: "Recheck the linked documentation before each major release."

If one rule matters more than the rest, state it in the opening. Don't put it
at the end. A reader who stops early must still see it.

### 4. Write the core model

Under `## Core model`, state the concepts that every step depends on. Use one
or both of these forms:

- The questions that the pattern answers, as a list.
- The components, the boundaries between them, and the invariant for each.
  For example: two trust zones, and the zone that enforces security.

Keep it short. The detail goes in the steps.

### 5. State when to use it

Under `## When to use it`, list the conditions for use as bullets. State how
the conditions combine: all, any, or a threshold such as "three or more". A
threshold stops the reader from using the pattern for a weak match.

Then list the conditions against use, and name the better alternative. This
is often the most useful line in the playbook.

### 6. Write the baseline and the parts

Write these sections only when their triggers apply.

Under `## Baseline`, list the prerequisites and the default stack. When the
pattern has secrets or generated files, add two lists: the files to commit,
and the items to never commit.

Under `## Parts`, write a two-column table: the part, and its purpose. Put the
required parts in the table. Put the optional parts in a list below the
table, and say which problem makes each one necessary.

### 7. Write the build order

Under `## Build order`, write numbered `### 1. Imperative title` steps in
dependency order. Each step does one thing. Each step opens with an
instruction, not with background.

Use unnumbered `####` headings for the topics inside one step. Don't number
any other heading. A number tells the reader that the order matters.

Put the decisions in the steps:

- The ordering that matters, and why.
- The constraint that isn't obvious.
- The default value, for example a port offset or a timeout.
- The thing to never do in this step.

Use a code block, a table, or a schema only when prose can't state the detail
exactly. A config file, an interface contract, a directory tree, or one line
that fixes an ordering is acceptable. A full implementation isn't.

Write each placeholder in capital letters. Explain it below the step:

```md
Replace the following:

- `PRODUCT`: the short name of the product family.
```

When a claim comes from external documentation, add a source line at the end
of the section:

```md
Source: [Content Security Policy](https://example.com/docs/csp/).
```

### 8. Add the minimum viable version and the change workflow

Write these sections only when their triggers apply.

Under `## Minimum viable version`, list the three to five items to ship
first, as a numbered list. Then state which parts wait for a second release,
and which real problem makes them necessary.

Under `## Change workflow`, write the numbered sequence for one repeated
change, for example a new feature. Start at the user outcome. End at the
verification of the released result.

### 9. Write the design rules

Under `## Design rules`, write the principles that apply to more than one
step. Start each rule with a bold sentence. Follow it with one or two
sentences of reason.

If a rule applies to only one step, move it into that step.

### 10. Write the anti-patterns

Under `## Anti-patterns`, write a table with three columns:

```md
| Anti-pattern | Failure mode | Accepted pattern |
|---|---|---|
| Hold a lock during I/O | Requests stall or deadlock | Copy the state, release the lock, then do the I/O |
```

The failure mode is mandatory. A mistake with no failure mode is only an
opinion. The accepted pattern tells the reader what to do instead.

Take the anti-patterns from real failures and from warnings in the primary
documentation. A good anti-pattern looks correct to a new reader. "Don't
write bad code" isn't an anti-pattern.

A row can repeat a "never" statement from a step. The table is the index that
a reviewer scans.

### 11. Write the verification

Under `## Verification`, give the pass signal for the result. A pass signal
is concrete: a command and its expected output, a log line, or a check that
must pass. Never write only "test it".

Write the checks as `- [ ]` checklists. Group a long checklist under
`####` headings by concern, for example security and reliability.

Add a separate checklist for each recurring event:

- A review checklist, when the team changes the result through pull
  requests.
- A release checklist, when the result ships releases.

### 12. List the sources

Under `## Sources`, list the primary documents, one link per line. The reader
uses this list to recheck the playbook at the recheck trigger in the opening.

### 13. Add the playbook to the site

Save the file as `src/content/docs/playbooks/SLUG.md`. The sidebar generates
the entry from the folder.

Replace the following:

- `SLUG`: the kebab-case form of the title, for example `feature-flags`.

Link each companion playbook in the opening.

## Design rules

- **One pattern per playbook.** Split a frontend concern and a backend concern
  into two linked playbooks. Each reader finds only their part.
- **Decisions, not boilerplate.** The reader can write the code. Give them the
  choices that they would otherwise learn from a failure.
- **Name the tool, not the version.** A pinned version is wrong within months,
  and the reader trusts it. Pin a version only when the pattern requires it,
  and state why. A security fix is a valid reason.
- **State the prohibitions.** Write "never" lists for the most expensive
  mistakes, for example the items to never commit or never log. A reader
  follows an explicit prohibition more reliably than an implied one.
- **Cite the source next to the claim.** A source line at the end of the
  section lets the reader recheck that one claim after a release.
- **Write in simplified technical English.** Use active voice, short
  sentences, and one word for one meaning. Don't use em dashes.
- **Write timelessly.** Describe how the pattern works, not how it changed.
  The `lastUpdated` date records when.
- **Link, don't copy.** When another document owns a subject, link to it.
  Duplicated prose drifts.

## Anti-patterns

| Anti-pattern | Failure mode | Accepted pattern |
|---|---|---|
| No `lastUpdated` date | The reader can't tell a current playbook from a stale one, so they trust neither | Set `lastUpdated` in the frontmatter |
| A `lastUpdated` change with no content change | The date stops meaning anything | Change the date only when the content changes |
| A second date in the body | The two dates disagree, and the reader can't tell which one is correct | Keep one date, in the frontmatter |
| A `#` heading in the body | The page shows two titles | Let Starlight show the `title` |
| A playbook from memory or theory | It documents imagined traps and misses the real ones | Trace every step to a real build or to primary documentation |
| Full implementations in the steps | They go stale, they cost attention, and the reader copies them instead of reading the decision | Show only the contract or the config, and name the decision |
| No "when not to use it" | Readers apply the pattern to every problem that looks similar | Name the conditions against use, and the better alternative |
| Generic anti-patterns such as "handle errors" | They teach nothing and hide the specific anti-patterns | Take the anti-patterns from real failures and documentation warnings |
| An anti-pattern with no failure mode | The reader can't weigh it against the cost of the fix | Write the failure mode and the accepted pattern in the table |
| One playbook for several patterns | The reader can't find their part, and each update touches unrelated content | Write one playbook per pattern, and link them |
| The most important rule at the end | A reader who stops early never sees it | State the one rule in the opening |
| Rationale and history at the top | The reader who must act now has to scroll past it | Put the steps first and the sources last |
| A number on every heading | The reader can't tell an ordered step from a topic | Number only the build order steps |
| A claim with no source | The reader can't recheck it after a release | Add a source line after the section |
| A pinned version with no reason | It becomes wrong, and nothing tells the reader | Name the tool, or state why the version matters |
| No pass signal | The reader can't prove that the result works | Give a command, an expected output, or a checklist |
| A tutorial or a reference page filed as a playbook | It has no decisions and no traps, so it fails the purpose of the folder | Put it under `guide/` or `reference/` |

## Verification

A playbook is ready when every item passes:

- [ ] The frontmatter has `title`, `description`, and `lastUpdated`.
- [ ] The `description` starts with "How to".
- [ ] The body has no `#` heading and no second date.
- [ ] The opening names the basis. It names the target version and the
      recheck trigger when they apply.
- [ ] Every required part is present, in the order of the parts table.
- [ ] "When to use it" states how the conditions combine, and names an
      alternative.
- [ ] Only the build order steps have numbers.
- [ ] Each anti-pattern row has a failure mode and an accepted pattern.
- [ ] The verification section gives a concrete pass signal.
- [ ] `perl -CSD -ne 'print "$.: $_" if /[\x{2013}\x{2014}]/' FILE` prints
      nothing. This finds en dashes and em dashes.
- [ ] `npm run build` completes, and the page footer shows the last updated
      date.
- [ ] An implementer can follow the playbook in their own codebase and ask no
      questions.