Execute the rtp2httpd release workflow — cumulative prerelease and formal release notes, tagging, GitHub releases, collapsing superseded prerelease notes after GA, CI handling, and stable branch updates.
64
76%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Fix and improve this skill with Tessl
tessl review fix ./.agents/skills/release/SKILL.mdThis skill orchestrates the entire release process for rtp2httpd.
Follow these steps in order.
cd there first if needed).git branch --show-current.git status --porcelain. If the workspace is not clean, abort with instructions.git fetch origin main --tags. Use
origin/main, not a potentially stale local branch, as the endpoint for release-note diffs.gh release list --exclude-drafts --limit 1 --json tagName --jq '.[0].tagName' (e.g., v3.14.2-rc.2). Save it as
the immediately previous release tag so its donation block can be removed after publishing. "Immediately previous"
means the most recently published non-draft GitHub Release, whether formal or prerelease.-rc.1, -beta.2, or
-alpha.1. Also record its base version by stripping the suffix (for example, v3.15.0-rc.2 has base version
v3.15.0). Prereleases skip the versioned Makefile and stable branch steps.gh release list --exclude-drafts --limit 100 --json tagName,isPrerelease,publishedAt; if 100
results are returned, increase the limit so the relevant release series cannot be truncated. Identify:
origin/main;If the user did not provide an explicit target tag, use AskQuestion with header "Release type":
What type of release is this?
Options (single-select):
Based on the answer and latest version, compute the new tag (e.g., v3.15.0).
Release-note history and git history serve different purposes:
origin/main diff.For a prerelease: use rolling cumulative notes.
gh release view <tag> --json body.For a formal release: prefer the prerelease notes for that version.
origin/main for omissions, but preserve the prerelease
wording where it remains accurate. The formal notes should represent the finalized cumulative prerelease notes plus
later work.Before using a source tag, verify that it belongs to the release branch with
git merge-base --is-ancestor "<source-tag>" origin/main. Abort for clarification if it is not an ancestor. Use git
history for the applicable ranges above:
git log "<source-tag>..origin/main" --oneline --no-merges --format="%s (%h)"Categorize commits by type (feat:, fix:, perf:, refactor:, chore: etc.) to understand what changed. Treat commit
subjects as evidence, not release-note copy: retain user-focused wording from existing release notes when possible.
<details> accordion if present (drop the outer
<details> / <summary> / </details> tags and keep only the inner markdown; do not treat the summary line as a
release-note item), remove the complete donation table using the donation asset URL as its marker, then split at the
standalone --- separator into Chinese and English sections. Do not confuse that separator with the donation
table's | --- | row.Draft bilingual release notes in a file (e.g., /tmp/release-notes-v3.x.y.md) following these conventions.
Release notes must always contain both Chinese and English:
--- separator.---.Patch release format:
- {Chinese description}
- Detail if needed
- {Chinese description}
| 如果这个项目对你有帮助,不妨请作者喝一杯咖啡 ☕️ |
| --- |
| <img width="360" src="https://github.com/user-attachments/assets/fc5c3498-40e9-43b9-93a3-6a5a7917847b" /> |
---
- {English description}
- Detail if needed
- {English description}Minor/major release format:
## 新功能
- {feature description in Chinese}
- Detail if needed
- ...
## 问题修复
- {fix description in Chinese}
- Detail if needed
- ...
| 如果这个项目对你有帮助,不妨请作者喝一杯咖啡 ☕️ |
| --- |
| <img width="360" src="https://github.com/user-attachments/assets/fc5c3498-40e9-43b9-93a3-6a5a7917847b" /> |
---
## New Features
- {feature description in English}
- Detail if needed
- ...
## Bug Fixes
- {fix description in English}
- Detail if needed
- ...Always include this canonical donation block in the new release, regardless of whether the release is a patch, minor, major, or prerelease:
| 如果这个项目对你有帮助,不妨请作者喝一杯咖啡 ☕️ |
| --- |
| <img width="360" src="https://github.com/user-attachments/assets/fc5c3498-40e9-43b9-93a3-6a5a7917847b" /> |Place the block exactly once, immediately after the Chinese content and before the --- separator that introduces
the English content. Do not append another donation block after the English content. If the user-provided notes
already contain the block, move it to the required position if necessary rather than adding a duplicate.
Release notes guidelines:
---)--- separatorCloses / Fixes #123 — those belong in git history onlyShow the drafted notes to the user by reading and outputting the full release notes file content so the user can directly review the complete bilingual notes and donation block.
Use AskQuestion with header "Ready to release?":
Ready to create release v3.x.y?
Show a summary: release notes file path, the release-note sources used (including inherited prereleases), lint, tag creation, release creation, previous-release donation cleanup, collapsing same-series prerelease notes after a formal release, and the CI/stable behavior appropriate for a formal release or prerelease.
Options:
After user approval, continue.
main with a Clean Workspace# Switch to main if not already there, only if workspace is clean
git checkout main
git pull --ff-only origin mainIf there are uncommitted changes preventing a branch switch, advise the user to stash or commit first and abort.
First, install frontend dependencies to avoid stale local caches:
pnpm installThen regenerate src/embedded_web_data.h so the released binary includes the latest frontend:
pnpm run web-ui:buildThis updates src/embedded_web_data.h. Commit it if it changed:
git add src/embedded_web_data.h
git commit -m "chore: update embedded_web_data.h for v3.x.y"If the file did not change (no diff), skip the commit.
pnpm run lintIf lint fails, show the output and ask the user whether to fix and retry or abort.
main, Then Create and Push Taggit push origin main
git tag -a "v3.x.y" -m "v3.x.y"
git push origin "v3.x.y"For a formal release:
gh release create "v3.x.y" \
--title "v3.x.y" \
--notes-file /tmp/release-notes-v3.x.y.mdFor a prerelease, include --prerelease:
gh release create "v3.x.y-rc.n" \
--title "v3.x.y-rc.n" \
--notes-file /tmp/release-notes-v3.x.y-rc.n.md \
--prereleaseAfter this, the CI release workflow is triggered automatically (it listens for release.published events).
Only the latest published release, including a prerelease, may display the donation QR code. Immediately after the new release is published, inspect only the previous release tag recorded during Step 0 and remove the canonical donation table from that release if it contains one.
gh release edit --notes-file rather than passing multiline notes as command arguments.uv run, never directly through python.The intended end state is:
latest published release (formal or prerelease): exactly one donation block
immediately previous release: no donation blockIf the GitHub Release is a prerelease, skip this step entirely. Earlier prereleases in an in-progress series must remain fully visible.
After a formal release is published, the same-base-version prereleases are superseded by the GA notes. Collapse each of those prerelease GitHub Release bodies into a default-hidden accordion so they no longer occupy the releases page.
Use the same-series prerelease tags identified in Step 0 — every published prerelease whose SemVer suffix strips to
exactly the new formal tag's base version (for example v3.16.0-beta.0, v3.16.0-beta.1, v3.16.0-beta.2 after
publishing v3.16.0). Do not include prereleases from a different base version.
For each such tag:
gh release view <tag> --json body.<details> accordion, skip that tag. Do not nest another wrapper.open attribute — the
section must be collapsed by default. Leave a blank line after </summary> so GitHub renders the inner markdown:<details>
<summary>预发布说明(已并入 v3.x.y) / Prerelease notes (included in v3.x.y)</summary>
{original body}
</details>Replace v3.x.y with the formal tag just published. Keep the summary wording exactly in this bilingual form.
gh release edit <tag> --notes-file .... Do not
pass multiline notes as command arguments.uv run, never directly through python.Do not wrap the newly published formal release, prereleases from another base version, or older formal releases.
Verify afterward that each updated prerelease body contains <details> and </details>, does not contain
<details open, and still includes its original Chinese/English notes.
versioned JobIf the GitHub Release is a prerelease, skip this step entirely. The workflow intentionally skips the versioned
job for prereleases, so do not poll for a versioned Makefile commit and do not treat the skipped job as a failure.
The CI workflow has a versioned job that commits Makefile.versioned files back to the main branch. Wait for this commit to appear on main:
# Loop until the versioned makefiles commit appears on main
# The commit message pattern is "chore: update versioned Makefiles for v3.x.y"
while true; do
git fetch origin main
if git log origin/main --oneline --grep="versioned Makefiles for v3.x.y" | head -1 | grep -q "v3.x.y"; then
echo "Versioned Makefiles commit found!"
break
fi
echo "Waiting for versioned Makefiles commit... (retry in 30s)"
sleep 30
done
# Update local main
git pull origin mainIf the CI run fails or the commit doesn't appear within 10 minutes, alert the user and stop. Check CI status via:
# Get the latest workflow run ID for the release tag
gh run list --workflow=release.yaml --branch "v3.x.y" --limit 1 --json databaseId,status,conclusion --jq '.[0]'stable Branch for Formal Releases OnlyIf the release is a prerelease, skip this step and leave stable unchanged.
For a formal release:
git checkout stable
git pull origin stable
git merge --ff-only origin/main
git push origin stableIf git merge --ff-only origin/main fails (non-fast-forward), it means the stable branch has diverged — alert the user and abort. Do not force-push.
maingit checkout mainFor a formal release, print a completion summary:
✅ Release v3.x.y complete!
- Tag: v3.x.y (pushed)
- GitHub Release: https://github.com/stackia/rtp2httpd/releases/tag/v3.x.y
- Same-series prereleases: notes collapsed into a default-hidden accordion
- stable branch: updated (fast-forward merge)
- CI: running (Docker, OpenWRT, static binaries, macOS)For a prerelease, explicitly report that versioned Makefile polling and the stable update were skipped by design:
✅ Prerelease v3.x.y-rc.n complete!
- Tag: v3.x.y-rc.n (pushed)
- GitHub Release: https://github.com/stackia/rtp2httpd/releases/tag/v3.x.y-rc.n
- Donation QR: present only on this latest release
- Versioned Makefiles: skipped for prerelease
- stable branch: unchanged
- CI: running (Docker, OpenWRT, static binaries, macOS)release.yaml) builds Docker images, OpenWRT IPK/APK packages, Linux/macOS/FreeBSD static binaries, and uploads them as release assets.versioned job commits openwrt-support/rtp2httpd/Makefile.versioned and
openwrt-support/luci-app-rtp2httpd/Makefile.versioned back to main.versioned job is intentionally skipped and stable must remain unchanged.<details>
accordion. Leave in-progress prerelease series fully visible. Do not wrap the new formal release.main or stable.gh run list and gh run view to monitor CI progress.33fecb8
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.