Async Test And Doc Sync
discord-php/DiscordPHP
Maintain test and documentation alignment — PHPUnit tests, async testing patterns, PHPDoc contracts, guide pages, and documentation workflow.
Cut a GAIA release end-to-end: draft notes, open release PR, run pre-tag verification, push the tag, monitor the publish pipeline, and produce the Discord announcement.
$ npx skills add amd/gaia --skill gaia-release -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install amd/gaia gaia-release --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/amd/gaia.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/gaia-release .claude/skills/gaia-release && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "gaia-release" agent skill from https://github.com/amd/gaia/tree/main/.claude/skills/gaia-release into .claude/skills/gaia-release/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gaia-release", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/amd/gaia/tree/main/.claude/skills/gaia-releaseType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add amd/gaia --skill gaia-release -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install amd/gaia gaia-release --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/amd/gaia.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/gaia-release .agents/skills/gaia-release && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "gaia-release" agent skill from https://github.com/amd/gaia/tree/main/.claude/skills/gaia-release into .agents/skills/gaia-release/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gaia-release", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add amd/gaia --skill gaia-release -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install amd/gaia gaia-release --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/amd/gaia.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/gaia-release .cursor/skills/gaia-release && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "gaia-release" agent skill from https://github.com/amd/gaia/tree/main/.claude/skills/gaia-release into .cursor/skills/gaia-release/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gaia-release", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/amd/gaia.git --path .claude/skills/gaia-release--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add amd/gaia --skill gaia-release -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install amd/gaia gaia-release --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/amd/gaia.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/gaia-release .gemini/skills/gaia-release && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "gaia-release" agent skill from https://github.com/amd/gaia/tree/main/.claude/skills/gaia-release into .gemini/skills/gaia-release/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gaia-release", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install amd/gaia gaia-releaseInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add amd/gaia --skill gaia-release -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/amd/gaia.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/gaia-release .github/skills/gaia-release && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "gaia-release" agent skill from https://github.com/amd/gaia/tree/main/.claude/skills/gaia-release into .github/skills/gaia-release/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gaia-release", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add amd/gaia --skill gaia-release -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install amd/gaia gaia-release --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/amd/gaia.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/gaia-release .opencode/skills/gaia-release && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "gaia-release" agent skill from https://github.com/amd/gaia/tree/main/.claude/skills/gaia-release into .opencode/skills/gaia-release/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gaia-release", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
gaia-releaseCut a GAIA release end-to-end: draft notes, open release PR, run pre-tag verification, push the tag, monitor the publish pipeline, and produce the Discord announcement.
Gaia Release is an agent skill from amd/gaia. Cut a GAIA release end-to-end: draft notes, open release PR, run pre-tag verification, push the tag, monitor the publish pipeline, and produce the Discord announcement. Also cuts release candidates (vX.Y.Z-rcN) for testing before the final. Use when the user asks to 'cut a release', 'cut a release candidate', 'release vX.Y.Z', 'tag a release', or 'publish v...'. Pauses at every irreversible step for user approval.
Its SKILL.md is about 8.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files (for example `reference/discord-announcement.md`).
It sits in Testing & QA. It works with Discord. The repository describes itself as: Build AI agents for your PC. The licence is MIT.
7 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 6c3bb5c. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitghpippythoncurlnodenpxjqnpmFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
github.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Gaia Release loads about 8.8k tokens when it runs. Until then it costs about 108 tokens; SKILL.md has 3,756 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from amd/gaia at commit 6c3bb5c, republished under its MIT licence (© amd). 3,756 words, ~8,812 tokens.
.claude/skills/gaia-release/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Run a GAIA release end-to-end against the amd/gaia repo. The skill is a phased checklist with hard gates — each phase produces a concrete artifact, then stops and asks for confirmation before doing anything irreversible (opening a PR, pushing a tag, rerunning a CI job, posting an announcement).
The pre-tag verification phase exists because the v0.17.4 release uncovered two release-blocking bugs that merged-PR CI did not catch (squash-merge silently reverting version.py, and the AppImage smoke test's circular pip install amd-gaia==<unpublished> dependency). Do not skip it.
Accept one argument in any of these shapes:
0.17.5 — bare semverv0.17.5 — with the v prefix (the actual tag form)0.17.5.1 — hotfix-style four-part version (rare; e.g. v0.15.4.1)__version__ from src/gaia/version.py, then suggest the next-patch bump (e.g. 0.17.4 → propose 0.17.5) and ask the user to confirm or override before continuing.Normalise to the bare form internally (0.17.5) and the tag form externally (v0.17.5). If the user gives a version that is older than or equal to the current __version__, stop and ask — never silently roll backwards.
The skill is reinvocation-safe — releases span days, and the user will return mid-flow. Before doing anything else, detect where in the flow we are and skip phases that already landed:
git fetch origin --tags
git checkout main && git pull
NOTES_ON_MAIN=$(git ls-tree -r origin/main --name-only | grep -c "^docs/releases/v<version>\.mdx$" || true)
PR_OPEN=$(gh pr list --repo amd/gaia --search "Release v<version> in:title" --state open --json number --jq '.[0].number' || true)
PR_MERGED=$(gh pr list --repo amd/gaia --search "Release v<version> in:title" --state merged --json number --jq '.[0].number' || true)
TAG_EXISTS=$(git tag --list "v<version>")
RELEASE_EXISTS=$(gh release view "v<version>" --repo amd/gaia --json tagName --jq '.tagName' 2>/dev/null || true)Resume table:
| State | Action |
|---|---|
RELEASE_EXISTS matches | Release already shipped. Skip to Phase 6 (smoke test + announcement) only. |
TAG_EXISTS, no release | Tag pushed, publish workflow in progress or failed. Resume at Phase 5 (monitor). |
v<version>-rcN tags exist, no final tag | A release candidate is out. Resume at Phase 3.5 step 4 (test pass) for the highest N. List them with git tag --list "v<version>-rc*". |
PR_MERGED, no tag | Notes on main. Resume at Phase 3 (pre-tag verification). Do not re-run Phase 1 — never overwrite merged notes. |
PR_OPEN | PR still open. Tell user "PR #N already open at <url> — waiting for merge." Exit. |
NOTES_ON_MAIN ≥ 1 but no PR | Half-finished prior attempt landed notes without a PR (rare). Stop and ask the user before continuing. |
| Nothing matches | Fresh release. Start at Phase 1. |
Always announce the resume decision before continuing: "Detected v<version> state: PR #831 merged, no tag yet. Resuming at Phase 3 (pre-tag verification)."
A PR_OPEN or PR_MERGED state may have been produced by the nightly automation
rather than a person: .github/workflows/nightly-patch-release.yml
drafts Phase 1-2 on its own when a patch release is due, and stops before merge and
tag. Treat that PR exactly like a human-drafted one — review the notes, then resume
at the phase the table gives.
These map to CLAUDE.md. Re-read them whenever this skill runs.
Co-Authored-By: Claude ... trailer), release notes, code comments, or the Discord announcement.## Breaking Changes (only if any), ## What's New, ## Bug Fixes, ## Known Issues (only if any), ## Contributors, ## Full Changelog. Patch releases do not include a pip install block.Release vX.Y.Z PR (e.g. gh pr list --repo amd/gaia --state merged --search "Release v in:title" --limit 3). Open with # GAIA vX.Y.Z Release Notes (no MDX frontmatter in the PR body), end with a Release checklist section. Style drift here costs review cycles.version.py bump and its notes land in the same commit. docs.yml and tests/unit/test_docs_json_release.py both resolve docs/releases/v<version>.mdx and the docs.json navbar label from the declared __version__, so bumping ahead of the notes (the old 0.17.3 → "bump to 0.17.4 for development" pattern) turns every later docs and unit run red, not just the release PR. Never bump on its own.git push origin v<version>.Goal: produce docs/releases/v<version>.mdx matching house style; update navigation and the UI package.json.
Survey commits since previous tag, then sanity-check the version request against scope.
PREV=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' | head -1)
echo "Previous tag: $PREV"
git log "$PREV..HEAD" --pretty=format:'%h %s'
echo
echo "Total: $(git log $PREV..HEAD --oneline | wc -l) commits"
echo "Feat: $(git log $PREV..HEAD --oneline | grep -cE '^[a-f0-9]+ feat') feat commits"
echo "Fix: $(git log $PREV..HEAD --oneline | grep -cE '^[a-f0-9]+ fix') fix commits"Group commits by theme (features, fixes, infra, docs). Extract the PR number from each subject ((#NNN)). For each non-trivial entry, open the linked PR or commit body to get the why — release notes need motivation, not just titles.
Scope-vs-version sanity check (do not skip): apply this rubric against the requested target version:
| Commit shape | Suggested release shape |
|---|---|
Only fix/docs/chore/ci, no feat | Patch (vX.Y.Z+1) ✓ |
1–2 feat commits, small scope | Patch acceptable, mention them as "What's New" |
3+ feat commits, or any commit titled ... vX.Y.Z milestone, default-model swap, breaking change, package layout change | Minor (vX.Y+1.0) — push back |
| Removal of a public API, CLI flag deletion, config schema break, version-pin floor raised in a non-additive way | Major (vX+1.0.0) — push back |
If the requested version doesn't match the rubric, stop and surface the mismatch: "You asked for v<requested> (patch). I see N feat commits since <prev> including <one or two examples> — this looks minor-shaped. Continue as patch, or bump to v<suggested>?" Do not silently proceed.
Read recent release notes for structure only — frontmatter shape, section headings, PR-link format. Take length and tone from Notes format below, not from the files: v0.21.1 is the model at 267 narrative words, while v0.22.0 (1705) and v0.23.0 (1119) were flagged in review as too much text in too-blocky a form — they are the regression this section exists to prevent.
Patch releases are short. Minor/major releases carry more bullets and a pip install block — the per-bullet shape is identical, only the count grows.
Create docs/releases/v<version>.mdx with this skeleton (adapt to whether it's patch / minor / major):
---
title: "v<version>"
description: "<one plain line: what shipped. Not a pitch.>"
---
# GAIA v<version> Release Notes
<Optional single sentence naming what this release is about. Drop it entirely if
the bullets already say it — that is the common case. Never a paragraph.>
## Breaking Changes
- **<what changed>** — <what to do instead>. (PR [#NNN](https://github.com/amd/gaia/pull/NNN))
## What's New
- **<what the user can now do>** — `<gaia command>`. <At most one more sentence, only
if the title genuinely needs it.> (PRs [#NNN](https://github.com/amd/gaia/pull/NNN), [#NNN](https://github.com/amd/gaia/pull/NNN))
## Bug Fixes
- **<what was broken>** — <what now happens>. (PR [#NNN](https://github.com/amd/gaia/pull/NNN))
## Known Issues
- **<what still does not work>** — <workaround, or "tracked in [#NNN](https://github.com/amd/gaia/issues/NNN)">.
## Contributors
- [@handle](https://github.com/handle) — <what they contributed>. (PR [#NNN](https://github.com/amd/gaia/pull/NNN))
## Full Changelog
**N commits** since v<previous>:
- `<sha>` — <subject>
- ...
Full Changelog: [v<previous>...v<version>](https://github.com/amd/gaia/compare/v<previous>...v<version>)Omit ## Breaking Changes and ## Known Issues when empty — no "None" placeholder. Drop
the --- rules between sections; the headings already separate them.
Generate the changelog by introspecting git, and escape it for MDX. Do not
hand-transcribe subjects, and do not pipe git log output in raw — a subject
containing < or { is valid git and invalid MDX, which fails CI's mintlify validate. v0.22.0 hit this on #1791's subject ("fix Mintlify MDX validation
(unescaped '<' breaks the docs check)") — the one commit whose subject describes
the bug it causes.
# Generate the `- `<sha>` — <subject>` lines, escaping the two characters MDX
# treats as syntax. `\<` and `\{` render as literal `<` / `{` (verified against
# `mintlify validate`), and shas never contain them, so escaping the whole line
# is safe. Subjects like "AMD <> SpecificAI" survive correctly.
git log v<previous>..HEAD --pretty=format:'- `%h` — %s' \
| sed -e 's/</\\</g' -e 's/{/\\{/g' > /tmp/changelog.txt
# Guard: nothing hazardous may survive.
grep -nE '(^|[^\\])[<{]' /tmp/changelog.txt && echo "MDX HAZARD — fix before continuing" || echo "changelog MDX-safe"Sanity-check the count against git log --oneline | wc -l after writing the file
(wc -l under-counts by one when the last line has no trailing newline — v0.22.0
claimed 197 when the real count was 198). The claimed count, the listed lines, and
git log must all agree.
Notes format (apply to every entry — this is the point of the skill). Tone is already governed by CLAUDE.md → How You Communicate — plain language, outcome first, each point made exactly once. Do not restate or soften it here. What is release-notes-specific is the shape:
### prose blocks
inside What's New.description is not a third copy.gaia hub, gaia email, …);
SDK, CI, and refactor work last, or omitted when it has no user-visible effect.## Bug Fixes / ## Known Issues / ## Contributors / ## Full Changelog. Those four are reference lists —
their length is set by how many fixes actually shipped, and squeezing them hides work.
The cap is on the narrative part, which is what bloats. Over budget means cut entries,
not reflow them. Step 8 checks it. (Calibration, same measure: v0.21.1 shipped at 267,
v0.22.0 at 1705, v0.23.0 at 1119.)Example — one highlight:
Bad (prose block, promotional, three sentences where one works):
Triage your inbox from the terminal —
gaia emailPoint GAIA at your inbox and it sorts the noise from what needs you: drafts replies to routine mail, flags what's urgent, leaves the rest. Runs locally, so your mail never leaves your machine. Try it:
gaia email.
Good (one bullet, plain, factual):
- Triage your inbox from the terminal —
gaia emailsorts mail, drafts replies to routine messages, and flags what needs you. Runs locally. (PR #1234)
Update docs/docs.json:
releases/v<version> to the Releases tab.v<previous-version> · Lemonade <previous-lemonade> → v<version> · Lemonade <current-lemonade>). Read src/gaia/version.py for the LEMONADE_VERSION constant — it is the source of truth, and the navbar may be drifted from it (Lemonade bumps land outside release PRs).Sync the UI package version.
node installer/version/bump-ui-version.mjsConfirm src/gaia/apps/webui/package.json now reads the new version.
Bump the hub component manifests. The terminal hub and Agent UI publish to
the Agent Hub R2 catalog on a version tag, and release_components.yml gates
the tag against each manifest — R2 paths are immutable, so publishing under a
stale version cannot be undone. A mismatch fails the release, by design.
sed -i '' "s/^version: .*/version: <version>/" \
hub/components/terminal-hub/gaia-agent.yaml \
hub/components/agent-ui/gaia-agent.yaml # GNU sed: drop the ''
grep -H '^version:' hub/components/*/gaia-agent.yaml # both must read <version>Then bump the terminal hub's min_gaia_version to <version> too. It needs
daemon host API v1.1, which no release before this one ships — so the release it
publishes alongside is its minimum, and release_components.yml refuses to
publish it under an older core. Leave agent-ui's alone: it talks to
gaia.ui.server, not the daemon control plane.
sed -i '' "s/^min_gaia_version: .*/min_gaia_version: \"<version>\"/" \
hub/components/terminal-hub/gaia-agent.yaml # GNU sed: drop the ''
python util/check_component_core_api.py --release-version <version>Finally, record what the previous release shipped in RELEASED_DAEMON_API
in util/check_component_core_api.py — the
guard resolves an already-published version from that table, and a missing row
makes it fall back to trusting this tree, which is the drift it exists to catch.
Confirm __version__ is correct.
grep -E '^__version__' src/gaia/version.pyThe post-prior-release bump usually handles this, but a squash-merge can revert it silently. If it's wrong, edit it. If it's right but reverted later (see Phase 3), the validator will catch it.
Validate — both checks. Run from the repo's activated venv (source .venv/bin/activate on Linux/macOS, .venv\Scripts\activate on Windows; the bare-python Microsoft Store stub will fail). If you're working from a git worktree without its own venv, run from the parent checkout's venv.
python util/validate_release_notes.py docs/releases/v<version>.mdx --tag v<version>
(cd docs && npx -y mintlify@latest validate) # the docs.yml `validate` job — MUST also pass
# Word budget from *Notes format* — the narrative part only, not the reference lists.
# Cap: 350 words for a patch, 600 for a minor/major. Over budget means cut entries.
awk '/^## (Bug Fixes|Known Issues|Contributors|Full Changelog)/{exit} {print}' \
docs/releases/v<version>.mdx | wc -wBoth must exit 0. Fix any errors before continuing. If either fails for reasons unrelated to your changes (missing dep, broken import), stop and surface that — do not silently bypass. validate_release_notes.py prints the first failing check (missing/renamed section, absent compare/ link, tag mismatch) — read that line to localise the fix; it has no --verbose flag.
validate_release_notes.py passing is not sufficient — it is not an MDX parser. CI's
validate job additionally runs mintlify validate from docs/, and v0.22.0 failed it
after the notes passed the Python validator (see the escaping rule in step 3). Its error is
misleading: an unparseable .mdx surfaces as "releases/v<version>" is referenced in the docs.json navigation but the file does not exist — the file exists, it just never parsed.
Pre-existing parse errors under docs/plans/ and docs/superpowers/ are reported but
non-fatal; leave them alone.
Show the diff (git diff --stat plus the new .mdx file inline). Ask: "Approve these release notes and continue to Phase 2 (open PR)?" Wait for explicit yes. Iterate on tone/wording before continuing — much cheaper than fixing on main.
Goal: branch, commit, push, open PR, request review.
Branch and commit.
git checkout -b v<version>-release
git add docs/releases/v<version>.mdx docs/docs.json src/gaia/version.py \
src/gaia/apps/webui/package.json src/gaia/apps/webui/package-lock.json \
hub/components/terminal-hub/gaia-agent.yaml \
hub/components/agent-ui/gaia-agent.yaml
git status # confirm scope-clean — no drive-by edits
git diff --cached --stat
git commit -m "Release v<version>"
git push -u origin v<version>-releaseIf git status shows anything outside those five files, stop and ask (bump-ui-version.mjs rewrites package-lock.json too — the prior release commit carries all five). The release PR must be scope-clean.
Read the most recent release PR body to match shape.
gh pr list --repo amd/gaia --state merged --search "Release v in:title" --limit 3 \
--json number,title,body | jq -r '.[0]'Use that as the structural template for this PR body — same opening, same checklist, same section order. Do not invent a new shape.
Prepare the PR body file. Build it by stripping the MDX frontmatter from the release notes and appending the Release checklist section copied from the previous release PR.
# Strip the YAML frontmatter (everything between the first two '---' lines)
awk '/^---$/{c++; next} c>=2' docs/releases/v<version>.mdx > /tmp/release-body.md
# Append the Release checklist section from the previous release PR
PREV_PR=$(gh pr list --repo amd/gaia --state merged --search "Release v in:title" --limit 1 --json number --jq '.[0].number')
gh pr view "$PREV_PR" --repo amd/gaia --json body --jq '.body' \
| awk '/^## Release checklist/{found=1} found' \
>> /tmp/release-body.md
# Sanity-check the body before opening the PR
head -3 /tmp/release-body.md # should start with "# GAIA v<version> Release Notes"
tail -10 /tmp/release-body.md # should end with the checklistIf the awk pipeline produces an empty file, the previous PR didn't have a ## Release checklist heading — fall back to copying the entire body and editing it manually before continuing.
Open the PR. Title: Release v<version>. Body: the file you just built.
gh pr create --repo amd/gaia \
--title "Release v<version>" \
--body-file /tmp/release-body.md \
--reviewer kovtcharov-amdSurface the resulting PR URL.
Stop. Tell the user: "PR opened at <url>. Waiting for review/merge before pre-tag verification. Re-invoke this skill (or /loop) to continue once merged."
Do not poll, do not auto-merge. Do not push the tag from the un-merged branch.
Goal: prove the merged commit on main actually builds clean before the tag locks it in. Do not skip this. Two release-blocking bugs in v0.17.4 would have shipped without this step.
Sync local main to the merged commit, and capture the SHA from the release PR (not just the local HEAD).
git checkout main && git pull
# Re-derive from the release PR — survives gate pauses across sessions/shells.
RELEASE_PR=$(gh pr list --repo amd/gaia --state merged --search "Release v<version> in:title" --json number --jq '.[0].number')
MERGED_SHA=$(gh pr view "$RELEASE_PR" --repo amd/gaia --json mergeCommit --jq '.mergeCommit.oid')
echo "Will tag: $MERGED_SHA (from PR #$RELEASE_PR)"
test "$(git rev-parse HEAD)" = "$MERGED_SHA" || { echo "Local main ($( git rev-parse HEAD)) does not match merged release PR SHA ($MERGED_SHA) — pull, or main has moved past the release commit"; exit 1; }When you reach Gate 3 below, carry both $RELEASE_PR and $MERGED_SHA into the gate question text so Phase 4 can re-derive them from the answer rather than depending on shell variables that don't survive the pause.
Re-verify __version__ post-merge. Squash-merges have silently reverted this. If it doesn't match the target version, stop — open a follow-up PR to fix it before tagging. Never tag a wrong version.
grep -E '^__version__' src/gaia/version.pyRe-run the release notes validator on the merged tree.
python util/validate_release_notes.py docs/releases/v<version>.mdx --tag v<version>Trigger Build Installers via workflow_dispatch against the merged SHA. This builds the same artifacts the tag push will build, on the same code, before the tag exists.
gh workflow run "Build Installers" --repo amd/gaia --ref main
sleep 5
RUN_ID=$(gh run list --repo amd/gaia --workflow "Build Installers" --limit 1 --json databaseId -q '.[0].databaseId')
echo "Watching run $RUN_ID"
gh run watch "$RUN_ID" --repo amd/gaiaAppImage smoke jobs (appimage-distro-matrix, appimage-userns-restricted) are the most flaky — appimage-userns-restricted has a 300s state: ready poll (raised from 90s to cover a first-run model download). On real failure, stop and fix root cause; on transient flake (timeout-only, no logic error), gh run rerun $RUN_ID --failed is acceptable.
Required before continuing:
__version__ matches the target.validate_release_notes.py passes.Show the user the run URL, the release PR number (#$RELEASE_PR), and the merged SHA ($MERGED_SHA). Ask: "Pre-tag verification green on <sha> (release PR #N). Push tag v<version>?" — the SHA and PR number being in the question text means Phase 4 can re-derive them even if the user resumes in a fresh shell.
Goal: put the exact build users will get in front of a tester before it becomes the default. An RC tag runs the same publish.yml, behind the same approval gate, but stays off every stable channel:
Final v<version> | RC v<version>-rcN | |
|---|---|---|
| GitHub Release | normal, becomes latest | pre-release, never latest |
| PyPI | <version> | <version>rcN — pip install amd-gaia ignores it without --pre |
npm @amd-gaia/agent-ui | dist-tag latest | <version>-rc.N under dist-tag next |
Agent Hub R2 (release_components.yml) | publishes | does not run — the catalog has no pre-release channel |
| Website | stable downloads | a collapsed "Try the release candidate" entry, hidden once the final ships |
Context7 refresh, release branch, release-notes bot | run | skipped |
| Release notes | docs/releases/v<version>.mdx | the same file — no RC-specific notes |
version.py stays <version>; the pipeline stamps the RC suffix from the tag (util/release_tag.py), so the final can be tagged on the RC's commit with no further version bump. The one-step Windows setup and the terminal's .pkg/.deb/.rpm packages are not built for an RC (they come from release_components.yml and need a numeric-only version); the RC carries the desktop app installers, the raw terminal binaries, and the wheel/sdist.
Dry-run the classification — a malformed tag fails validate before anything builds, but catching it locally is cheaper:
python util/release_tag.py classify v<version>-rc1
python util/validate_release_notes.py docs/releases/v<version>.mdx --tag v<version>-rc1IS_RC=true, PEP440_VERSION=<version>rc1, NPM_VERSION=<version>-rc.1. Anything else (-rc.1, rc1 without the dash, -rc0, -beta1) is rejected.
Tag the verified SHA from Gate 3 and push — same confirmation rule as Phase 4: the SHA and the green pre-tag run go in the question.
git tag -a v<version>-rc1 <merged-sha> -m "Release candidate v<version>-rc1"
git rev-list -n1 v<version>-rc1 # MUST equal <merged-sha>
git push origin v<version>-rc1Monitor and approve exactly as in Phase 5. The approval gate is the same publish environment. There is no refresh-context7 job to wait for; redeploy-website-rc asks the website to rebuild so the RC entry appears.
Personal test pass on a machine that does not already have the release installed (CLAUDE.md: test from the user's real initial state):
pip install amd-gaia==<version>rc1 && gaia -v # must print <version>rc1
npm view @amd-gaia/agent-ui dist-tags # latest unchanged, next = <version>-rc.1
gh release view v<version>-rc1 --repo amd/gaia # Pre-release, installers attachedThen install the desktop app from the pre-release and walk the golden paths the release notes advertise.
Problems → fix forward, then -rc2. Land the fix on main through a normal PR, re-run Phase 3 on the new merged SHA, and tag v<version>-rc2 from step 2. Never move or delete an RC tag — each one is a published version on PyPI and npm.
Ask: "v<version>-rcN passed testing on <sha>. Tag the final v<version> on that same SHA?" Phase 4 then tags that SHA (re-derive it with git rev-list -n1 v<version>-rcN), not necessarily the release PR's merge commit.
Goal: push the annotated tag; do nothing else.
Confirm you are on main at the verified SHA. Re-derive $MERGED_SHA from the release PR (the SHA from Gate 3) — do not trust shell state across the gate pause.
git checkout main
git pull
# Re-derive from the release PR — the PR number was in the Gate 3 question.
MERGED_SHA=$(gh pr view <release-pr-number> --repo amd/gaia --json mergeCommit --jq '.mergeCommit.oid')
test "$(git rev-parse HEAD)" = "$MERGED_SHA" || { echo "main moved past verified SHA $MERGED_SHA — re-verify (Phase 3) before tagging"; exit 1; }Tag and push.
# Annotated, on the verified SHA — every prior release tag is annotated ("Release vX.Y.Z").
# A bare `git tag v<version>` creates a lightweight tag and breaks convention.
git tag -a v<version> <merged-sha> -m "Release v<version>"
git rev-list -n1 v<version> # MUST equal <merged-sha> before pushing
git push origin v<version>Confirm the publish workflow picked it up.
sleep 10
gh run list --repo amd/gaia --workflow publish.yml --limit 3The flow is: validate → build (build-pypi + build-npm + build-desktop-installers) → approve-publish (manual gate) → publish (publish-pypi + publish-npm) → post-publish-smoke → github-release → refresh-context7. Surface the run URL.
Goal: watch the run, distinguish flake from real failure, surface the manual approval gate to the human.
Watch the run.
gh run watch <run-id> --repo amd/gaiaOn flake (timeout-only, no logic error in the failing step's logs): gh run rerun <run-id> --failed is non-destructive — re-runs only failed jobs and their downstream. Do not rerun the whole workflow; that wastes the publish budget.
On real failure (logic error, missing artifact, validator failure that wasn't there before): stop. Do not push past a red build. Do not delete and re-tag — that path is messy. Surface the failing step + log to the user.
Manual approval gate — when the run reaches the approve-publish job (gated on the publish GitHub environment), surface the URL to the user. Tell them: "Manual approval required at <url>. Claude cannot click this — please approve in browser when ready." Then wait.
After approval, PyPI + npm + GitHub Release jobs run in parallel. Watch to completion.
refresh-context7 is the terminal job and may legitimately fail — that is not a release failure. This job runs after PyPI, npm, GitHub Release, and the desktop installers are already published. Context7's API rejects refresh requests inside a short cooldown window (observed: ~3–6 days between releases) with HTTP 429 (rate-limited); the workflow tolerates 429 and treats any other status as a hard failure. If the job is red, the release is still live. Open the job log, read the Response body: block between the ::stop-commands:: markers, and either accept the cooldown reason or file a follow-up about a new rejection cause. Do not delete or re-tag — see the recovery guidance in the Notes section below.
Never add set -x or curl -v to the refresh-context7 step to "debug" a failure. GHA only masks the verbatim secret value; curl -v prints the Authorization: Bearer <token> header, which is a transformed form that GHA's masking does not catch. Read the captured response body instead — it carries the same diagnostic signal without the leak risk.
Goal: confirm artifacts are live, draft the Discord announcement.
Smoke test the published wheel.
pip install --upgrade amd-gaia==<version>
gaia -vMust report <version>. If it reports the previous version, the squash-merge version.py regression slipped through — escalate immediately.
Verify the GitHub release page.
gh release view v<version> --repo amd/gaiaRequired artifacts: .whl, .tar.gz, .deb, .AppImage, .dmg, .exe, and the latest*.yml files for the Electron auto-updater. If any are missing, the corresponding build job didn't run or didn't upload — investigate.
Draft the Discord announcement. Read the just-shipped release notes (docs/releases/v<version>.mdx) to populate the highlight list — reuse the What's New bullets near-verbatim plus any Bug Fix worth surfacing. Same Notes format rules apply: bullets, plain, factual, no emoji.
The template and format rules live in
reference/discord-announcement.md — read it and
copy the template verbatim. Every element in it is load-bearing (the @gaia role
mention, the backticked version, the fenced install block, the fixed boilerplate
sentences); do not improvise the shape.
Show the user the smoke-test output, the artifact list, and the drafted Discord announcement in a fenced markdown block. Ask: "Post the announcement to Discord?" Wait for explicit yes — Discord posting is human-only (Claude does not have Discord access here, and announcements are visible to all users).
After every phase, output:
?, names the next destructive action).Do not bundle two phases into one user prompt. The gates exist for review.
git tag --sort=-v:refname | head -1.v0.15.4.1) follow the same flow; the validate_release_notes.py check accepts the four-part form.v<version>-rcN only (Phase 3.5). There is no RC form of a four-part hotfix tag.v0.18.0, v1.0.0) need a richer notes structure — a "Highlights" block, the pip install instructions, and migration notes if breaking. The skeleton above is patch-shaped; expand for non-patch releases by mirroring the prior minor/major release notes.gh run rerun <run-id> --failed), and let the rest of the pipeline complete idempotently. The tag is the source of truth — preserve it.© amd, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in .claude/skills/gaia-release of amd/gaia.
Open the folder on GitHubat commit 6c3bb5c
Gaia Release next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Gaia Release this skillamd/gaia | 1.6k | — | ~8.8k | Automated safety check: Pass | MIT | |
| Async Test And Doc Syncdiscord-php/DiscordPHP | 1.1k | — | ~3.4k | Automated safety check: Notes | MIT | |
| Nexu E2E Testnexu-io/nexu | 3.3k | — | ~1.7k | Automated safety check: Pass | MIT | |
| Openclaw Parallels SmokeSafeAI-Lab-X/ClawKeeper | 1k | — | ~1.1k | Automated safety check: Pass | None | |
| Agent Browser CLIvercel-labs/agent-browser | 44k | 24 repos | ~864 | Automated safety check: Pass | Apache-2.0 | |
| Electron App Automationvercel-labs/agent-browser | 44k | 5 repos | ~1.7k | Automated safety check: Pass | Apache-2.0 |
discord-php/DiscordPHP
Maintain test and documentation alignment — PHPUnit tests, async testing patterns, PHPDoc contracts, guide pages, and documentation workflow.
nexu-io/nexu
A skill your agent uses when verifying OpenClaw gateway fixes end-to-end, testing skill loading after restart, or running integration tests against the local Nexu+OpenClaw stack.
SafeAI-Lab-X/ClawKeeper
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests.
vercel-labs/agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking…
vercel-labs/agent-browser
Automates Electron desktop apps such as VS Code, Slack or Discord by connecting agent-browser to their Chrome DevTools Protocol port.
TermiX-official/cryptoclaw
Delegate coding tasks to Codex, Claude Code, or Pi agents via background process.
amd/gaia
Adds a release eval scorecard to a GAIA hub agent by writing a harness adapter, running a real eval, and wiring the result into the agent's README and release gate.
amd/gaia
Walks through releasing a GAIA sidecar agent as a frozen binary plus npm client through the tag-triggered Agent Hub CI pipeline, with a human gate before publishing.
amd/gaia
Mines local Claude Code session transcripts with a deterministic Python pipeline to show what the agent is actually used for, how often it fails and what it costs.
amd/gaia
Benchmarks AMD's GAIA agent against Claude Code and across models on quality, honesty, steps, tokens, time and real cost, using gaia eval tasks.
amd/gaia
Guides safe code changes by finding the right file with grep or semantic search, reading before editing, reproducing bugs first, and proving a fix with a real test run.
amd/gaia
Walks through scaffolding, writing and testing a new GAIA agent as a Python class with the SDK, from the base Agent subclass to registered tool methods.
Works with
Categories
Cut a GAIA release end-to-end: draft notes, open release PR, run pre-tag verification, push the tag, monitor the publish pipeline, and produce the Discord announcement. Gaia Release is an agent skill from amd/gaia. Cut a GAIA release end-to-end: draft notes, open release PR, run pre-tag verification, push the tag, monitor the publish pipeline, and produce the Discord announcement.
Gaia Release fits situations like: the user asks to cut a release; cut a release candidate.
Run `npx skills add amd/gaia --skill gaia-release -a claude-code`. Or copy the skill folder (.claude/skills/gaia-release in amd/gaia) into .claude/skills/gaia-release in your project. Claude Code loads it when a task matches its description.
Run `npx skills add amd/gaia --skill gaia-release -a codex`. Or copy the skill folder (.claude/skills/gaia-release in amd/gaia) into .agents/skills/gaia-release in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add amd/gaia --skill gaia-release -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/gaia-release, .gemini/skills/gaia-release, .github/skills/gaia-release and .opencode/skills/gaia-release in your project.
Going by SKILL.md and its folder, Gaia Release needs the command-line tools its instructions call (git, gh, pip, python, curl and node). Our summary lists: Python 3.
SKILL.md names 1 domain. In commands or code: github.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Gaia Release is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 8.8k tokens (SKILL.md is roughly 35k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Gaia Release: Async Test And Doc Sync (discord-php/DiscordPHP, 1.1k stars), Nexu E2E Test (nexu-io/nexu, 3.3k stars), Openclaw Parallels Smoke (SafeAI-Lab-X/ClawKeeper, 1k stars) and Agent Browser CLI (vercel-labs/agent-browser, 44k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
amd (a GitHub organization) maintains it in amd/gaia, which has 1,580 GitHub stars. The repository holds 44 skills in this directory. The repository was last updated on October 6, 2026.
Source: amd/gaia on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.