release-notes — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited release-notes (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Translate one version's CHANGELOG entries into adopter-facing release notes. The CHANGELOG is written for contributors (terse, internal mechanics, issue numbers); adopters read the website and care what GAIA now does for _their_ project.
Contents: Pre-flight: Worktree check; Inputs; Output (a): the release data file; Output (b): the editorial-decisions report; The translation contract; Worked exemplars; Workflow; See.
It pairs with /gaia-release but runs independently: point it at the [Unreleased] block while cutting a release, or at any historical ## [x.y.z] block to backfill the website.
It never edits `CHANGELOG.md`; it only reads it.
This skill writes into the sibling website checkout, resolved relative to the main checkout. If invoked from a linked worktree, reject hard: gaia_refuse_if_worktree (.gaia/scripts/main-only-lib.sh) asks the shared resolver which tree this is and refuses out loud, naming the main checkout, when the answer is a worktree.
Detection (run this first, before anything else):
. .gaia/scripts/main-only-lib.sh
gaia_refuse_if_worktree "/release-notes" || exit 1Invocation carries a target version, e.g. release-notes 1.4.0 (no leading v). Resolve which CHANGELOG block to translate, and where the date comes from, by that version:
CHANGELOG.md contains ## [<version>] - <YYYY-MM-DD>. Translate that block. Take version and date verbatim from the header. The release already happened on that date; the shell clock is irrelevant.## [Unreleased]. Translate that block. version is the argument (the maintainer is cutting it now). date is today from the shell clock (date +%F).If no version was supplied and an [Unreleased] block exists, ask the maintainer which version is being cut, the version label has to come from a human, not a guess.
Whether historical or live, the date comes from the CHANGELOG header or the shell, never from your own notion of "today." Models routinely misdate by months; a wrong date silently ships a wrong timeline to every visitor. For a live cut, run date +%F and use exactly that.
Write to ../website/src/pages/changelog/releases/<version>.ts (version with no leading v; mkdir -p the directory if it's missing). The changelog page auto-discovers every file via import.meta.glob('../releases/*.ts') and sorts by version, so dropping the file in is all that's needed, there's no index or import list to update.
The schema lives in `../website/src/pages/changelog/types.ts` (the `Release` type), read it as the source of truth before writing.
Match the file form of the existing release files, don't trust this skill's literal shape. The website's convention drifts (export style and key order have both changed). Before writing, open the newest releases/*.ts and mirror it exactly: types.ts gives you the _fields_, a live sibling file gives you the _serialization_. Today that form is a bare default export with keys in alphabetical order (the formatter sorts them). Omit any optional key with no content:
export default {
added: ['...'],
date: '2026-06-02',
fixed: ['...'],
headline: 'A short title or one plain sentence.',
improved: ['...'],
version: '1.4.0',
};added → "New" (capabilities that didn't exist before). improved → "Improved" (changed/enhanced behavior). fixed → "Fixed".headline, required for any bucketed release (one or more added/improved/fixed items). A short title or one plain sentence, leading with the release's reason to exist. The buckets render with no title of their own, so a bucketed card with no headline ships titleless. A grab-bag with no single story still gets a headline: use a descriptive umbrella line naming the two or three biggest items ("Built-in a11y testing, dead-code detection, and stories as tests"), never nothing. The only way to omit headline is to let a summary carry the lead instead (see below). For a newly-shipped capability, carry the rule 1 now into the headline too, "GAIA apps now ship with a CSP", not "ship with".summary vs buckets, mutually exclusive. The renderer shows summary as a single paragraph _instead of_ the added/improved/fixed lists. The choice is driven by how many distinct adopter-facing items survive the cut, not by the release's age or whether it's a backfill. Use buckets whenever one or more itemizable adopter-facing changes remain; each lands as its own bullet under New/Improved/Fixed. Reserve summary for: (1) an internal-only release where every change was dropped as maintainer plumbing, a one-line "no adopter-facing changes" note (e.g. "Internal release-tooling fixes. No change to how GAIA apps behave."); (2) a genuine one-sentence story; or (3) a broad inaugural / overview release where a narrative reads better than a long list (the 1.0.0 entry). Never set both.preamble, only when the version's block carries the 1.6.1 routing line (a line equal to the output of bash .gaia/scripts/compose-release-body.sh --routing-line). Copy the preamble of the newest releases/*.ts that has one, verbatim: the routing line, the Proceed line, and the sha256 line of the bundle the routing line downloads. The renderer emits it before the headline, so the GitHub release body still leads with the routing line after /gaia-release overwrites it. The routing line itself is never a bullet.[text](url) (rendered as a new-tab link). Entry-reference links are _optional_ and are built from the trailing (#N) the entry carries: https://github.com/gaia-harness/gaia/issues/N for the issue an entry closes, https://github.com/gaia-harness/gaia/pull/N for an entry carrying a pull-request number. Include one only when a reader would genuinely follow it for detail, never as decoration. The exemplars below omit them.After writing the file, print a report to the terminal (don't write a file, this is a human gate the maintainer reads before accepting the notes). It makes your editorial judgment auditable. Use this structure:
## Release notes, v<version> (<date>)
Wrote ../website/src/pages/changelog/releases/<version>.ts
**Dropped** (with reason)
- <changelog line>, <why: pure-internal / housekeeping / docs-only>
**Consolidated**
- <N changelog lines about X> → one <bucket> item
**Needs a human ruling** (ambiguous actor, see rule 6)
- <line>, feature or housekeeping? <why it's ambiguous>Omit a section if it's empty. Never drop something silently: if it didn't make the notes, it appears under Dropped or Needs a human ruling.
This is the substance of the skill, the rules that turn a contributor's changelog into an adopter's release notes.
/update-gaia, the quality gate. "what changed and what it means for me," not "which function moved." The scaffolded React app is GAIA apps (apps built from the template); effects on the developer's own code or files are your … (your utility classes, your package.json). So "the app ships with a CSP" becomes "GAIA apps now ship with a CSP."git -C captures so a quoted sibling-repo push is recognized as foreign" ships inside an adopter hook, yet only fires when _you_ push across GAIA's own sibling repos during a release, drop it. (Contrast: a change to the Code Review Audit an adopter runs before every merge _is_ adopter-facing, residence aside, an adopter who runs it sees the benefit, so keep it.)/gaia-cleanse on GAIA's own wiki, housekeeping, drop it. When a line could mean "GAIA now does X" (keep) or "I did X to the repo" (drop) and the voice won't tell you which, put it under Needs a human ruling rather than picking. Guessing wrong either invents a feature or buries a real one.### Added → added ("New"). ### Changed → improved ("Improved"). ### Fixed → fixed ("Fixed"). ### Removed → improved ("Improved"): the website has no "Removed" bucket, and a removal that survives the cut reads to an adopter as a cleanup or simplification, but see rule 11, most convention-anchored removals are reframed or dropped, not bucketed verbatim. A **BREAKING:** or Migration sub-bullet stays in whatever bucket its parent lives in (usually improved).### Removed / ### Changed entry carries the adopter-action convention anchor (an Action required: line and/or a literal pnpm command, see CHANGELOG.md) and the action reduces to a single mechanical command /update-gaia surfaces for the adopter (a pnpm remove/pnpm install-style cleanup), do not present it as a chore the reader must perform. Either reframe at impact altitude, naming the cleanup as a benefit and noting the tooling handles it ("GAIA dropped the vestigial react-router-dom shim; /update-gaia cleans it up for you"), or drop it as no adopter-behavior-change. Log the decision in Output (b): a drop goes under Dropped with the reason "agent-automated by /update-gaia"; a reframe is visible in the notes themselves. Never a silent cut. Guardrail (does not erode rule 8): a genuine breaking change or hand-migration, anything the agent cannot do for the adopter (editing their code, resolving a conflict patch, a real API break), is still kept, plainly framed, with a pointer to the exact steps. The anchor is the discriminator: a one-command cleanup is automatable (reframe/drop); an Action required: that demands human code changes is a migration (keep). When you cannot tell which from the entry, route it to Needs a human ruling, never guess.These are the calibration. Study how dense, internal-sounding changelog blocks collapse into a few adopter-meaningful bullets, and what gets cut. They show the _editorial result_ and house style.
1.3.5, seven Added, five Changed, four Fixed → two / three / oneexport default {
added: [
'Dependency supply-chain hardening: new package versions are quarantined for 7 days before GAIA installs them, and downgrades are blocked, defending against a compromised fresh release.',
'GAIA apps now ship with a Content-Security-Policy that restricts which scripts can run, hardening them against script injection.',
],
date: '2026-06-02',
fixed: [
"`Form/Chain` merges class names with `twMerge`, so your utility classes override the component's defaults instead of conflicting with them.",
],
headline: 'Faster, cheaper CI and a hardened dependency supply chain.',
improved: [
'Code Review Audit on CI is now opt-in and installs on demand. When it runs, it only audits changes since the last green run instead of the whole codebase, so CI is faster and cheaper.',
'React Router v8 future flags are enabled so your app is ready for the v8 upgrade early. One flag (`v8_passThroughRequests`) changes how loaders and actions receive the request: if you have customized `app/root.tsx`, a small migration is needed. See the full changelog for exact steps.',
'Kickoff prompts print to the terminal instead of silently copying to your clipboard.',
],
version: '1.3.5',
};Report for 1.3.5:
**Dropped** (with reason)
- stamp GAIA-Audit status on out-of-scope skips, internal status stamping, no adopter effect
- clarify the gate owns formatting; make PR merge marker-first, internal workflow mechanics
- document useDebounce return semantics, docs-only
- detect orphaned wiki drift in preflight via suggested_base, internal release tooling
- recover the un-evaluated window on sync re-anchor, internal wiki-sync mechanics
- gaia-release updates softwareVersion, maintainer-only release tooling
**Consolidated**
- four Code Review Audit / CI lines (install on demand, honor both tokens, gate on since-last-green delta, incremental scope, opt-in) → one "Improved" item
- two pnpm supply-chain lines (minimumReleaseAge quarantine, no-downgrade trustPolicy) → one "New" item1.4.0, note the housekeeping drop (rules 5/6)export default {
date: '2026-06-02',
fixed: [
'`/update-gaia` no longer re-adds files you intentionally deleted.',
'`/update-gaia` only raises conflicts for files that actually changed in the release, instead of flooding you with spurious patches.',
'Wiki entries take their dates from your system clock instead of the model, so timestamps are always correct.',
],
headline: '`/update-gaia` stops fighting you over your own files.',
version: '1.4.0',
};Report for 1.4.0:
**Dropped** (with reason)
- promote machine-local feedback memories into shared wiki, reads like a feature but was the maintainer running /gaia-cleanse, a content action on GAIA's own wiki, not adopter-visible behavior (rule 5/6)summary fits, internal-only or one-line releasesA release with no distinct adopter-facing items left after the cut, an internal-only patch where everything was dropped as maintainer plumbing, or a genuinely one-sentence story, collapses to a single summary paragraph. This is about item count, not age: a backfilled old release with two real adopter changes still earns buckets. The shape, for an internal-only patch like 1.1.1:
export default {
date: '2026-05-11',
headline: 'GAIA release fixes',
summary:
'Fix to the gaia-release maintainer reference, plus follow-ups from live init runs.',
version: '1.1.1',
};date +%F now.../website/src/pages/changelog/types.ts for the current Release fields and the newest releases/*.ts for the current file form (export style + key order). Then read the version's block from CHANGELOG.md. Classify every line: keep, drop (rule 4/5), consolidate-with-siblings (rule 7), reframe-or-drop a /update-gaia-automated cleanup (rule 11), or ambiguous (rule 6).headline per Output (a), or a summary in place of buckets when one of Output (a)'s three summary cases applies..ts in the exact form of the file you read in step 2 (today: bare default export, keys alphabetical), with a preamble when the block carries the routing line (Output (a)). Omit empty optional keys. Sweep for em-dashes and for bullets with no observable result before writing (rule 3/9).mkdir -p ../website/src/pages/changelog/releases and write <version>.ts. No index to update, the page globs the directory..claude/commands/gaia-release.md, the release process this feeds: Step 14 invokes this skill for the changelog page entry and locksteps the other website version sites.CHANGELOG.md, the source.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.