Agent docs

The shape of a release changelog

What a published version tells the person moving a pin.

A changelog is read once, by someone deciding whether to take a version and what it will cost them. Everything here follows from that. A file that restates the commit history serves nobody: the commits are already in the log, and a reader who wanted them would be reading the log.

Audience: an agent or person writing the notes for a published version.

The structure is adapted from slack-automation, whose ci-kit/skills/release-changelog/PROMPT.md and ci-kit/skills/WRITING.md worked out the shape first. Two things differ here, and both come from what this repo ships.

What makes this repo's changelog different#

A version of @versable-git/ui is not only code. The tarball carries src and theme, four CLIs under bin, per-component reference under docs, and method, which is a verbatim copy of the design canon and the app-patterns recipes. Taking a bump therefore delivers three things at once:

what arriveswhat it does to a consumer
components and tokenstheir screens change, or gain capability
the canon under method/the rules their work is judged against change
kit-standard and the other binsthe grader's checks change

A changelog that describes only the first leaves two thirds unsaid. The symptom is specific and has happened: a consumer upgrades, runs kit-standard, sees findings on screens they never touched, and nothing in the notes explains why the bar moved.

The second difference is the audience count. Three apps consume this kit, each on its own pin, and agents read USAGE.md to adopt it without a person present. Write for the one moving the pin, whether that is a person or not.

The five sections, in this order#

The order is the reader's, not the author's. It runs from what this costs them to what it gives them.

1. What changes on screens you already have#

Everything that reaches a caller who did not opt in. A table, because these items share a shape:

| what flipped | what a reader sees | keep the old behaviour with |

This leads because it is the only section that can cost someone an afternoon. A release with nothing in it says so in one line and moves on.

2. Rules that changed#

Which canon sections moved, and what kit-standard grades now that it did not before. Name the check by its id and say what it fires on. A consumer should learn why their score moved from the notes, not from the score.

Omit the section when the canon and the checks are untouched. Most patch releases will omit it.

3. What you can delete#

The Retires line, promoted to a table with the app, the file and what replaces it. This is the section that pays for the upgrade, so it is worth the precision: name the file and line, not the area.

Name only what fully dies. A file that shrinks is not retired, and saying so sends someone to delete something they still need.

4. What you can now do#

Grouped by what a reader would call the area, never by package path. A component, its pattern page, its doc and the CLI check that grades it belong in one bullet when they serve one capability.

Each bullet states what changed, neutrally. No "cleaner", "better", "properly".

5. Known gaps#

What landed narrower than it was specified, what has no test, what the standard still reports. The most valuable line in a release note is usually the one admitting what is missing, and a reader who finds a gap you did not name stops trusting the rest of the document.

The header#

Three lines above the first section, and every number is counted rather than carried over from anywhere:

> <n> commits, <n> files, +A/-D since `v<previous>`.
> Areas: <the areas, from the diff>.
> Grounded in the diff at `<previous>...<head>`, not commit subjects.

What never goes in#

  • A commit list, or anything derived mechanically from commit subjects. Subjects mislead: a revert reads as a regression, "remove gating" may have moved a gate rather than removed one, and a vague subject undersells a real feature.
  • A file inventory. A changed file is not a bullet. Group by what a reader would call the change and let one bullet cover every file that served it.
  • Length as a proxy for effort. A reader judges the size of a release by the length of this document before reading a word, so an inflated one is a false claim about scope.

Length#

There is no target and no cap. A release touching four hundred files for one migration is short. A release with nine unrelated changes is long even when each is small. Judge by how many things happened, never by how many files moved.

The prose rules#

slack-automation's ci-kit/skills/WRITING.md is the house voice and applies here in full. The tells worth repeating, because they are the ones this repo's changelog has actually shown: zero em dashes, bold beyond roughly one phrase per screen, Label: fragments where a sentence belongs, and a closing paragraph summarising what was just read.

Two of its rules matter more here than elsewhere. Every identifier wears backticks, because a consumer will grep for them. And every claim carries its evidence: a file and line, a measured number, a command and what it printed.

These notes are read on a GitHub Release and on the package page, where a path in backticks is a string the reader has to go and find. Name a file and link it.

  • Write a file in this repo as blob/main. The release step rewrites those to the tag as it extracts the section (changelog-section.mjs --at-tag), so notes read a year later open the files as they shipped. A file in a consuming app keeps main, because it describes that app's code rather than this release; all of them sit under github.com/versable-git.
  • A link into another repo is file-level, with no line anchor. That repo's main moves without telling you, so the anchor is wrong shortly after you write it and looks right forever. One call site in walmart-mvp was three different line numbers in one afternoon: 231 in the note that named it, 322 in a local checkout, 275 on the remote. A line anchor is only safe inside this repo, where the release rewrites it to a tag and the tag does not move.
  • A link that must name a location in another repo names what to search for instead: the prop, the symbol, the string.
  • A path holding brackets or parentheses is percent-encoded, or the markdown link breaks on the first bracket. The console's route folders are full of them.
  • Check that each link resolves before shipping. gh api repos/<owner>/<repo>/contents/<path> answers in one call, and a 404 in a release note is worse than the plain string would have been. Note what that check does NOT prove: the file exists, so a link with a wrong line anchor passes it and still lands the reader somewhere arbitrary. That is the second reason cross-repo links carry no anchor.

What is mechanical, and what is not#

Most of this is not automatable, and that is deliberate. A generated changelog is a commit list with better formatting.

What runs on its own:

gatewhat it prevents
sync-method-docs.mjs --check in CIshipping canon copies that drift from the canon, so the rules a consumer installs match the ones grading them
the release step in publish-kit.ymla published version whose notes live only inside a tarball
scripts/changelog-section.mjsthe notes and the release body drifting apart, since both read one source
the notes gate in ship-kit.sh and publish-kit.ymla version reaching the registry with nothing written about it, which cannot be undone

One generator, for the section people forget:

node scripts/rules-changed.mjs <previous-tag>

Before the first tag exists, pass the previous release's commit instead. This repo cut no tags before the release step landed, so the first run after it has no tag to name.

It prints section 2's skeleton: which kit-standard checks a consumer gains or loses between two refs, and which canon docs moved. It leaves capitalised slots where the prose goes, because what a check fires on is a sentence a person writes. On its first run it found a check the author of this document had forgotten, which is the entire argument for it.

What a person or an agent writes: every word of the five sections. The reading that produces them is the work, and the work is what the reader is paying for.

@versable-git/ui · reference, canon, and method, read in place