# The issue body

> The schema rd-plan writes, rd-issues files, rd-build treats as done-or-not, and rd-retro scores against.

One schema, used by four skills. `rd-plan` writes it, `rd-issues` files it,
`rd-build` reads the acceptance lines as the definition of done, and `rd-retro`
scores a run against it. It is markdown, so it renders in the app, in `radial
show`, and in a diff.

Use the smallest version that carries the contract. A body padded with empty
headings teaches readers to skim, and the acceptance lines are the part nobody
can afford to skim.

## A parent

Three header lines first, nothing above them:

```markdown
**Type:** feature
**Agent:** Claude Code
**Session ID:** 9f2c1a44-0c3e-4a5d-8b21-6f0d7e2b1c88

**Goal:** One sentence a stakeholder would recognise, describing the world
after this ships.

**Scope:**
- In: everything this tree covers.
- Out: what a reasonable reader would expect and will not get, and why.

**Plan:** How the children fit, the decisions already made, and the reason for
each. This is where a reader learns why it is three children and not one.

**Acceptance:**
- [boot] The repo's gate is green.
- [behavioral] A named person can do a named thing.

**Tags:** [ui, api]
```

`Type` is `feature`, `fix`, `chore`, `refactor` or `docs`. `Session ID` makes
the planning conversation findable a month later, which is its only job;
`unknown` is an acceptable value and a missing line is not.

## A child

```markdown
**Goal:** One sentence. What exists after this child merges.

**Scope:**
- In: …
- Out: …

**Plan:** The approach, the key decision, the trap to avoid. Two to six
sentences. Name the pattern the repo already uses, so the builder follows it
instead of inventing a second one.

**Files:**
create: src/lib/skills/manifest.ts, src/lib/skills/manifest.test.ts
modify: src/app/developers/page.tsx

**UX:** The journey a person takes, including empty, loading and error states.
No human-visible surface? Write `n/a (no UI surface)` rather than deleting the
line, so a reader knows it was considered.

**Acceptance:**
- [integration] With the manifest unreachable, the page renders the degraded
  hook table and no 500.
- [integration] A page whose frontmatter omits `section` fails the content
  build, naming the file.

**Browse checks:**
1. Open `/docs/skills` → the sidebar shows the skills in two groups → click
   "Install and update" → a Claude Code section and a Codex section appear,
   each with a copy button.
2. At 390px wide → the sidebar is a disclosure above the article and nothing
   overflows horizontally.

**Tags:** [ui]
```

## The rules that actually matter

**An acceptance criterion is observable.** It names an input and a result
someone can see: a rendered string, a status code, a row in the database, an
exit code. Never a function you intend to call. The test is whether a reviewer
who has not read your diff could check the line. If not, rewrite it.

**A bracket tag says how it is checked.** `[boot]` the process starts and the
gate passes. `[integration]` two real parts meet. `[behavioral]` a person does
something and sees something. `[perf]` a number with a bound.

**Browse checks are walkthroughs, not intentions.** Each starts where the
reader starts, lists the clicks, and ends on a condition that is either on
screen or not. `rd-build` runs them verbatim before a child may move to in
review, so vagueness here becomes a false "done" later, which is the specific
failure the format exists to prevent.

**The Out list is load-bearing.** It records what you decided not to do, so
nobody re-litigates it in review and `rd-retro` can tell a deliberate omission
from a dropped ball. A plan that excludes nothing has not been thought about.

**Write it for the reader who arrives late.** The body is read by a teammate in
six months and by an agent with no memory of the conversation you are having
now. Neither has your context.

<callout kind="note">

`rd-plan` writes every body of one plan into a single file,
`.radial/plans/<slug>.md`, and `rd-issues` files each with
`radial create --description-file`. `-d` is inline text: passing it a path
stores the literal path as the description, which nobody notices until review.

</callout>
