Perform Harbor release procedures — version bumping, codegen, committing, pushing, and drafting GitHub releases. Use this skill when the user wants to release a new version of Harbor, bump the version number, create a release on GitHub, run the release codegen pipeline, or anything related to shipping a new Harbor version. Triggers on phrases like "release Harbor", "bump version", "new release", "ship a new version", or "prepare a release".
77
96%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Releasing Harbor is a sequential pipeline: bump the version constant, run codegen (which propagates the version across the monorepo and syncs docs to the wiki), research what changed, update the README News section, run the same local lint gate used by CI, commit, push, and open a pre-filled GitHub release form.
Before starting, verify two things:
git status should show no uncommitted changes.
The codegen step touches many files; starting dirty makes the release commit noisy.release.sh pushes docs to ../harbor.wiki. If the
directory doesn't exist, the docs push will fail. Clone it first if missing:
git clone https://github.com/av/harbor.wiki.git ../harbor.wikiOpen .scripts/seed.ts and change the VERSION constant (line ~9):
const VERSION = "X.Y.Z";Bump patch by default (e.g. 0.4.2 → 0.4.3). Bump minor or major only
when the user explicitly asks.
This constant is the single source of truth — the seed script propagates it to
pyproject.toml, package.json, harbor.sh, app/package.json,
app/src-tauri/tauri.conf.json, app/src-tauri/Cargo.toml, and
services/boost/pyproject.toml.
bash .scripts/release.shNote: harbor dev only runs .scripts/*.ts Deno scripts, so release.sh must
be invoked directly with bash. The script:
harbor dev seed, seed-cdi, seed-traefik)harbor dev lint)app/src-tauri/Cargo.lock to match the bumped Cargo.toml
(cargo update --workspace); if cargo is missing it warns — sync the lock
manually before committing../harbor.wiki)Wait for it to complete. Check the output for errors — especially the wiki push,
which can fail if there are merge conflicts in ../harbor.wiki.
Identify what changed since the last release to write the release notes.
# Find the previous release tag
git tag --sort=-creatordate | head -5
# List commits since that tag
git log vPREV..HEAD --oneline
# If you need more detail on specific commits
git log vPREV..HEAD --statClassify each commit:
feat: <service-name> commits, or new services/compose.<name>.yml filesfeat: commits that aren't new servicesfix: commitschore: commits worth mentioning (not all are — skip routine ones)For merged PRs, check:
git log vPREV..HEAD --oneline --mergesUpdate the ## News list in README.md to include the new release. The list
lives between the screenshot image and the ## Documentation heading.
vX.Y.Z with a short
highlights summary (one sentence, 2-3 key changes from Step 3).The bullet format is:
- **vX.Y.Z** - Short highlights sentenceRun the lint checks before committing or pushing the release. release.sh
runs the human lint pass, but CI also has a strict Harbor rules gate where any
HARBORxxx finding fails the build. Do not publish a release with red CI.
bash harbor.sh dev lint-self-test
bash harbor.sh dev lint
bash harbor.sh dev lint --rules --json > rules.json
count=$(jq '.findings | length' rules.json)
if [ "$count" -ne 0 ]; then
echo "harbor dev lint --rules reported $count finding(s); CI would fail."
jq -r '.findings[] | " \(.file):\(.line) \(.severity) \(.rule) \(.message)"' rules.json
rm -f rules.json
exit 1
fi
rm -f rules.jsonIf this fails, fix every finding and rerun the full lint gate before proceeding.
Shellcheck warnings from bash harbor.sh dev lint may be pre-existing, but the
--rules --json gate must report zero findings.
Stage only the files touched by the release pipeline (never git add -A —
the working tree may hold unrelated in-flight work):
git add .scripts/seed.ts README.md pyproject.toml package.json harbor.sh \
app/package.json app/src-tauri/tauri.conf.json app/src-tauri/Cargo.toml \
app/src-tauri/Cargo.lock \
services/boost/pyproject.toml
git commit -m "chore: vX.Y.Z"
git push origin mainCheck git status afterwards for any other files the seed scripts touched
(e.g. regenerated compose/CDI/Traefik outputs) and add them to the same commit.
The commit message is always chore: vX.Y.Z — no variation.
Construct the URL and open it with xdg-open (not an internal browser).
Base: https://github.com/av/harbor/releases/new
Query parameters:
| Param | Value |
|---|---|
tag | vX.Y.Z |
target | main |
title | vX.Y.Z if no new services, otherwise vX.Y.Z - Service1, Service2 |
prerelease | false |
body | Release notes (see template below) |
The body value must be URL-encoded. Use Python or similar to build the URL:
python3 -c "
import urllib.parse
body = '''RELEASE_NOTES_HERE'''
params = urllib.parse.urlencode({
'tag': 'vX.Y.Z',
'target': 'main',
'title': 'vX.Y.Z',
'body': body,
'prerelease': 'false'
})
print(f'https://github.com/av/harbor/releases/new?{params}')
"Then open the printed URL with xdg-open.
### [ServiceName](https://github.com/av/harbor/wiki/2.x.x-Service-ServiceName)
<SCREENSHOT_PLACEHOLDER>
One sentence description of the service.
\`\`\`bash
harbor up servicename
\`\`\`
### Misc
- One short sentence per notable change.
- One short sentence per notable bugfix.
- One short sentence per notable improvement.
**Full Changelog**: https://github.com/av/harbor/compare/vPREV...vX.Y.ZIf no new services were added, omit the service sections entirely — just use the Misc section and the Full Changelog link.
The wiki link format for services follows the pattern 2.x.x-Category-ServiceName
where the category and numbering match the docs file (e.g. 2.3.0-Satellite-SearXNG).
Check the docs/ directory for the exact page name.
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.