feat(changelog): make releases legible to agents - #81
Open
SPIKESPIGEL404 wants to merge 1 commit into
Open
Conversation
Four gaps, all on the surfaces agents actually read. llms.txt never mentioned the changelog. The index that tells an assistant what exists listed docs, API reference and recipes, and llms-full.txt bundled `source.getPages()` — docs only. So an agent asked "what's new", "is X supported yet", or "what changed between versions" had no route to an answer, on a site that otherwise goes out of its way to welcome them (robots.ts names GPTBot, ClaudeBot, PerplexityBot and the rest by hand). Add a Changelog section, and append the release history to the ingestion bundle. Serve /changelog.md. RSS and Atom are the developer channel; assistants fetch Markdown, and a feed carries only descriptions, never the notes. One file, newest first, an `##` per release with its date, permalink and breaking flag. Formatting lives in lib/changelog.ts next to the other pure presentation logic, so it is unit-tested; the entry bodies come from fumadocs, which needed `includeProcessedMarkdown` on the changelog collection. The sync's provenance comment is stripped — build bookkeeping, invisible on the page, and it would otherwise be the first thing an agent read about a release. Entry pages had title, description and canonical, and nothing else: no openGraph, so a shared release link carried no date and no article type, and no structured data, on a site that emits JSON-LD for the org, the docs and every FAQ. Add both. The release node states only version facts and carries its own @id — the root layout already publishes the canonical BitRouter SoftwareApplication, and without a distinct id the two would merge into one node with contradictory app-level properties. Teach the sync to read the folded release format. From v1.0.0-alpha.28 the source repo folds per-PR change files into the release body (bitrouter/bitrouter#820), so it leads with `### Breaking changes` / `### Added` sections holding `#### <title>` and prose, and the generated bullets move into a collapsed "All commits" block. Left alone the old parser would have regressed on the better input: `firstFeatureLine` took the first `- ` bullet, which now lives inside the collapsed block, so `description` — the index headline, the meta description and the RSS summary — would have become a random commit subject while the curated title was ignored. Tags matched `Fixes`, which does not match `Fixed`. Parsing moves to lib/release-notes.mjs and is tested against both shapes; releases whose PRs were all labelled `no-changelog` still arrive bullets-only and still work. Tags and the breaking flag now read the raw body, so a curated entry is still tagged from the commit groups in its collapsed list and git-cliff's inline `[**breaking**]` marker is not lost with them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four gaps, all on the surfaces agents actually read. The plumbing here is already good —
robots.tsnames GPTBot, ClaudeBot, OAI-SearchBot, PerplexityBot and Google-Extended by hand, there's llms.txt, llms-full.txt, a git-dated sitemap, RSS and Atom. The changelog just wasn't wired into any of it.1. llms.txt never mentioned the changelog
The index that tells an assistant what exists listed docs, API reference and recipes.
llms-full.txtbundledsource.getPages()— docs only. So an agent asked "what's new", "is X supported yet", or "what changed between versions" had no route to an answer.Adds a
## Changelogsection, and appends the release history to the ingestion bundle. The docs say what BitRouter does; only the changelog says what it does now.2.
/changelog.mdRSS and Atom are the developer channel. Assistants fetch Markdown — and a feed carries only the descriptions, never the notes. This serves the whole history as one file, newest first, an
##per release with its date, permalink and breaking flag.Formatting lives in
lib/changelog.tsbeside the other pure presentation logic so it's unit-tested; bodies come from fumadocs, which neededincludeProcessedMarkdownon the changelog collection. The sync's provenance comment ({/* Auto-generated… Edit freely */}) is stripped — build bookkeeping, invisible on the rendered page, and otherwise the first thing an agent would read about a release.3. Structured data and article metadata on entries
Entry pages had title, description and canonical, and nothing else. No
openGraph, so a shared release link carried no date and no article type. No JSON-LD, on a site that emits it for the organization, the docs and every FAQ.Adds both. The release node states only version facts (
softwareVersion,datePublished,releaseNotes) and carries its own@id— the root layout already publishes the canonical BitRouterSoftwareApplication, and without a distinct id the two merge into one node with contradictory app-level properties. "Which version added X" is a question structured data answers deterministically and prose does not.4. Teach the sync the folded release format — the time-sensitive one
From v1.0.0-alpha.28 the source repo folds per-PR change files into the release body (bitrouter/bitrouter#820): it leads with
### Breaking changes/### Addedsections holding#### <title>and prose, and the generated bullets move into a collapsed All commits block.Left alone, the old parser would have regressed on the better input:
firstFeatureLinetook the first-bullet, which now lives inside the collapsed block — sodescription(the index headline, the<meta>description, and the RSS summary) would have become a random commit subject while the curated title was ignored.deriveTagsmatchedFixes, which does not matchFixed. Tags would have gone empty.Parsing moves to
lib/release-notes.mjs, tested against both shapes. Releases whose PRs were all labelledno-changelogstill arrive bullets-only and still work. Tags and the breaking flag now read the raw body, so a curated entry is still tagged from the commit groups in its collapsed list and git-cliff's inline[**breaking**]marker isn't lost with them.Verified against the exact body #820 will publish:
Verification
pnpm buildpasses (/changelog.mdprerenders static, 25 releases, ~22KB), 148 tests pass (21 new),lint:docsandlint:changelogclean. Built HTML confirmed to carryog:type=article,article:published_time, and the release JSON-LD. Pre-existingtscerrors incomponents/ai/search.tsxandcomponents/markdown.tsxare untouched by this branch.Not done
[#anchor]suffixes fumadocs appends to headings in processed Markdown show up in/changelog.md, exactly as they already do throughoutllms-full.txt. Fixing that would change the docs bundle too, so it's left alone here.🤖 Generated with Claude Code