|
| 1 | +--- |
| 2 | +name: ohe-release-notes |
| 3 | +description: Generate consolidated OpenHands Enterprise release notes from multiple component repos |
| 4 | +triggers: |
| 5 | + - /ohe-release-notes |
| 6 | +--- |
| 7 | + |
| 8 | +# OpenHands Enterprise Release Notes Generator |
| 9 | + |
| 10 | +Generate a consolidated release notes page for an OpenHands Enterprise release by collecting and |
| 11 | +merging GitHub release notes from all component repositories into a single page under `enterprise/`. |
| 12 | + |
| 13 | +## Prerequisite: REPLICATED_API_KEY |
| 14 | + |
| 15 | +This skill derives **all** component versions automatically from the Replicated Vendor API, so it |
| 16 | +requires a `REPLICATED_API_KEY` environment variable with (at least) read access. |
| 17 | + |
| 18 | +**Before doing anything else, verify the key exists and works:** |
| 19 | + |
| 20 | +```bash |
| 21 | +if [ -z "$REPLICATED_API_KEY" ]; then |
| 22 | + echo "MISSING" |
| 23 | +else |
| 24 | + curl -s -o /dev/null -w "%{http_code}\n" \ |
| 25 | + -H "Authorization: $REPLICATED_API_KEY" \ |
| 26 | + "https://api.replicated.com/vendor/v3/apps" |
| 27 | +fi |
| 28 | +``` |
| 29 | + |
| 30 | +If the variable is missing (prints `MISSING`) or the request does not return `200`, **stop and ask |
| 31 | +the user to add it** before proceeding: |
| 32 | + |
| 33 | +> This skill needs a `REPLICATED_API_KEY` (read access is enough) to look up the component versions |
| 34 | +> for each Enterprise release. Please add it as a secret and let me know when it's ready. |
| 35 | +
|
| 36 | +## When to use |
| 37 | + |
| 38 | +Use this skill when asked to create or update Enterprise release notes. You derive every component |
| 39 | +version yourself from Replicated. |
| 40 | + |
| 41 | +## What you need to determine |
| 42 | + |
| 43 | +The only thing you truly need is **which two Enterprise releases to diff**: the `previous` release |
| 44 | +(already documented, usually the top `## X.Y.Z` heading in `enterprise/release-notes.mdx`) and the |
| 45 | +`new` release (the target you're documenting). Everything else — the four component version ranges |
| 46 | +plus the derived software-agent-sdk range — is derived from the Replicated release charts. |
| 47 | + |
| 48 | +By default: |
| 49 | +- **new** = the latest release on the Replicated `Stable` channel |
| 50 | +- **previous** = the most recent release already documented at the top of `enterprise/release-notes.mdx` |
| 51 | + |
| 52 | +## Step-by-step procedure |
| 53 | + |
| 54 | +### 1. Derive component versions from Replicated |
| 55 | + |
| 56 | +Each Replicated channel release bundles a set of Helm charts whose pinned image tags give you every |
| 57 | +component version. The Enterprise release version itself equals the `openhands` chart version (which |
| 58 | +is also the OpenHands-Cloud release version). |
| 59 | + |
| 60 | +#### 1a. Find the app, channel, and the two release sequences |
| 61 | + |
| 62 | +```bash |
| 63 | +# App id + default channel id (Stable) |
| 64 | +curl -s -H "Authorization: $REPLICATED_API_KEY" \ |
| 65 | + "https://api.replicated.com/vendor/v3/apps" \ |
| 66 | + | python3 -c " |
| 67 | +import json,sys |
| 68 | +for a in json.load(sys.stdin)['apps']: |
| 69 | + if a['slug']=='openhands': |
| 70 | + print('app', a['id']) |
| 71 | + for c in a['channels']: |
| 72 | + if c.get('isDefault'): |
| 73 | + print('channel', c['id'], '| current', c.get('currentVersion')) |
| 74 | +" |
| 75 | +``` |
| 76 | + |
| 77 | +```bash |
| 78 | +# List releases on the channel to find the sequence numbers for the two versions |
| 79 | +curl -s -H "Authorization: $REPLICATED_API_KEY" \ |
| 80 | + "https://api.replicated.com/vendor/v3/app/{APP_ID}/channel/{CHANNEL_ID}/releases?pageSize=50" \ |
| 81 | + | python3 -c " |
| 82 | +import json,sys |
| 83 | +for r in json.load(sys.stdin)['releases']: |
| 84 | + print(r.get('semver'), '| seq', r.get('sequence'), '| created', r.get('created')) |
| 85 | +" |
| 86 | +``` |
| 87 | + |
| 88 | +The Enterprise release version is the `semver` of the **new** release (e.g. `0.36.0`). |
| 89 | + |
| 90 | +#### 1b. Read the pinned component versions from the OpenHands-Cloud chart |
| 91 | + |
| 92 | +The `openhands` chart version equals the Enterprise release version and lives in the |
| 93 | +`OpenHands/OpenHands-Cloud` repo under the tag `openhands/{version}`. Read the pinned tags at both |
| 94 | +the **previous** and **new** versions to get each component's version range. |
| 95 | + |
| 96 | +| Component | Where the tag is pinned (in `OpenHands/OpenHands-Cloud` at `openhands/{version}`) | Notes | |
| 97 | +|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------|-----------------------------------------| |
| 98 | +| **OpenHands-Cloud** (Helm chart) | the release version itself (`charts/openhands/Chart.yaml` → `version`) | equals the Enterprise release version | |
| 99 | +| **Enterprise Server** | `charts/openhands/values.yaml` → top-level `image:` → `repository: ghcr.io/openhands/enterprise-server`, `tag:` | see prefix note below | |
| 100 | +| **Software Agent SDK** | `charts/openhands/charts/runtime-api/values.yaml` → `repository: ghcr.io/openhands/agent-server`, `tag: X.Y.Z-python` | strip the `-python` suffix | |
| 101 | +| **Runtime API** | `charts/openhands/charts/runtime-api/values.yaml` → top-of-file `tag:` (the runtime-api image) | tags are `vX.Y.Z` in GitHub | |
| 102 | +| **Automation** | `charts/openhands/charts/automation/values.yaml` → top-of-file `tag:` | tags are plain `X.Y.Z` in GitHub | |
| 103 | + |
| 104 | +Fetch any of these files with the GitHub contents API: |
| 105 | + |
| 106 | +```bash |
| 107 | +curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ |
| 108 | + "https://api.github.com/repos/OpenHands/OpenHands-Cloud/contents/{path}?ref=openhands/{version}" \ |
| 109 | + | python3 -c "import json,sys,base64; print(base64.b64decode(json.load(sys.stdin)['content']).decode())" |
| 110 | +``` |
| 111 | + |
| 112 | +Do this for both the **previous** and **new** Enterprise versions to build the range for each |
| 113 | +component (previous → new). |
| 114 | + |
| 115 | +#### 1c. Inform the user of the version jumps |
| 116 | + |
| 117 | +You don't need the user to confirm before proceeding — just **inform** them of the derived version |
| 118 | +jumps (previous → new for all five components) so they can double-check if they want to. Present the |
| 119 | +table and continue generating the page. Example: |
| 120 | + |
| 121 | +| Component | Previous | New | |
| 122 | +|------------------------------|----------|--------| |
| 123 | +| OpenHands-Cloud (Helm chart) | 0.28.0 | 0.36.0 | |
| 124 | +| Enterprise Server | 1.47.1 | 1.49.0 | |
| 125 | +| Software Agent SDK | 1.36.0 | 1.39.1 | |
| 126 | +| Runtime API | 0.5.2 | 0.7.0 | |
| 127 | +| Automation | 1.1.5 | 1.5.0 | |
| 128 | + |
| 129 | +### 2. Identify GitHub releases in range |
| 130 | + |
| 131 | +For each component repo, list all GitHub releases and identify which fall **after** the previous |
| 132 | +version and **up to and including** the new version. |
| 133 | + |
| 134 | +| Component | Repo | GitHub tag format | |
| 135 | +|---------------------|--------------------------------|--------------------------------| |
| 136 | +| Enterprise Server | `OpenHands/enterprise` | `X.Y.Z` (legacy `cloud-X.Y.Z`) | |
| 137 | +| Software Agent SDK | `OpenHands/software-agent-sdk` | `vX.Y.Z` | |
| 138 | +| Runtime API | `OpenHands/runtime-api` | `vX.Y.Z` | |
| 139 | +| Automation | `OpenHands/automation` | `X.Y.Z` | |
| 140 | +| OpenHands-Cloud | `OpenHands/OpenHands-Cloud` | `openhands/X.Y.Z` | |
| 141 | + |
| 142 | +```bash |
| 143 | +curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ |
| 144 | + "https://api.github.com/repos/{owner}/{repo}/releases?per_page=100" \ |
| 145 | + | python3 -c "import json,sys; [print(r['tag_name']) for r in json.load(sys.stdin)]" |
| 146 | +``` |
| 147 | + |
| 148 | +### 3. Fetch release notes |
| 149 | + |
| 150 | +For each release in range, fetch the body: |
| 151 | + |
| 152 | +```bash |
| 153 | +curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ |
| 154 | + "https://api.github.com/repos/{owner}/{repo}/releases/tags/{tag}" \ |
| 155 | + | python3 -c "import json,sys; print(json.load(sys.stdin).get('body',''))" |
| 156 | +``` |
| 157 | + |
| 158 | +### 4. Categorize into top-level sections with component subsections |
| 159 | + |
| 160 | +Group bullet points into **top-level sections** (Features, Bug Fixes, Maintenance), with **h4 component |
| 161 | +subsections** under each. The component order is: |
| 162 | + |
| 163 | +1. **Enterprise Server** — from `OpenHands/enterprise` |
| 164 | +2. **Software Agent SDK** — from `OpenHands/software-agent-sdk` |
| 165 | +3. **Runtime API** — from `OpenHands/runtime-api` |
| 166 | +4. **Automation** — from `OpenHands/automation` |
| 167 | +5. **OpenHands Cloud (Helm Chart)** — from `OpenHands/OpenHands-Cloud` |
| 168 | + |
| 169 | +Sort items by conventional commit prefix: |
| 170 | +- **Features** — lines starting with `* feat` |
| 171 | +- **Bug Fixes** — lines starting with `* fix` |
| 172 | +- **Maintenance** — lines starting with `* chore`, `* ci`, `* build`, `* refactor`, `* test`, etc. |
| 173 | + |
| 174 | +### 5. Filter out noise |
| 175 | + |
| 176 | +Apply these exclusions before categorizing entries: |
| 177 | + |
| 178 | +- Exclude every entry whose linked PR was authored by `dependabot[bot]`, regardless of its title or |
| 179 | + category. Use the release-note attribution or linked PR metadata to identify the author. |
| 180 | +- Exclude every version-only bump entry, regardless of its conventional commit prefix, scope, or |
| 181 | + author. This includes forms such as `bump X from A to B`, `bump X to B`, and `bump from A to B`, |
| 182 | + plus dependency, package, SDK, agent-server, image, and image-tag bumps. |
| 183 | + |
| 184 | +Also remove these automated/housekeeping lines that don't add value to customer-facing release notes: |
| 185 | + |
| 186 | +| Pattern | Reason | |
| 187 | +|------------------------------|------------------------------------------------------------| |
| 188 | +| `chore(main): release X.X.X` | Automated release PRs | |
| 189 | +| `fix(backport): ...` | Backport cherry-picks (the original fix is already listed) | |
| 190 | +| `Release vX.Y.Z` | Automated release PRs in software-agent-sdk | |
| 191 | +| `Verify ... model` | Model verification entries in software-agent-sdk | |
| 192 | + |
| 193 | +### 6. Write the page |
| 194 | + |
| 195 | +Create a new file `enterprise/release-notes/X.Y.Z.mdx` (where X.Y.Z is the release version). |
| 196 | +Each release gets its own page, following the Agent Canvas release notes format. |
| 197 | + |
| 198 | +**Directory setup:** If `enterprise/release-notes/` doesn't exist yet, create it. |
| 199 | + |
| 200 | +**Always include a Highlights section** at the top. Read all of the changelog entries for the release |
| 201 | +and identify 2-5 items worth calling out. Keep it high-level and short — only call out things |
| 202 | +genuinely worth highlighting like notable features, and don't enumerate individual fixes or config flags. |
| 203 | +If the release contains only bug fixes and maintenance, you can still highlight the most important |
| 204 | +fixes or just say "This release was focused on stability and maintenance fixes." |
| 205 | + |
| 206 | +**The Highlights section is for users, not developers.** Only include things a customer would |
| 207 | +recognize and care about when reading the release notes — new UI, new capabilities they can use, |
| 208 | +new integrations, behavior changes that affect them, or admin/org features they can act on. |
| 209 | +**Do not include developer-facing or internal plumbing items**, even if they are prominent in the |
| 210 | +underlying changelog. Examples of what to exclude from Highlights (even when present in the |
| 211 | +categorized sections below): |
| 212 | + |
| 213 | +- Internal APIs, admin-only lifecycle endpoints, or other backend-only surfaces |
| 214 | +- Feature-flag mechanisms, config plumbing, database schema/indexing changes |
| 215 | +- Build args, image variants, Docker layer refactors, CronJob splits, cleanup jobs |
| 216 | +- ACP provider additions, agent-server internals, SDK refactors |
| 217 | +- Secret-masking, subprocess env handling, and other security plumbing |
| 218 | +- CI/test/infra changes and dependency bumps |
| 219 | +- New model support unless it materially changes what a user can select in the product |
| 220 | + |
| 221 | +When in doubt, ask: "would a customer skimming release notes notice or care?" If not, leave it out |
| 222 | +of Highlights. It may still belong in the categorized sections below, just not in Highlights. |
| 223 | + |
| 224 | +**Page structure:** |
| 225 | + |
| 226 | +```mdx |
| 227 | +--- |
| 228 | +title: OpenHands Enterprise X.Y.Z |
| 229 | +description: Release notes for OpenHands Enterprise version X.Y.Z |
| 230 | +--- |
| 231 | + |
| 232 | +# OpenHands Enterprise X.Y.Z |
| 233 | + |
| 234 | +Released <Month Day, Year>. |
| 235 | + |
| 236 | +## Highlights |
| 237 | + |
| 238 | +- **<Short bold title>** — Brief description of the highlight. Include links to docs if relevant. |
| 239 | +- **<Another highlight>** — Brief description. |
| 240 | + |
| 241 | +## Features |
| 242 | + |
| 243 | +#### Enterprise Server |
| 244 | + |
| 245 | +* feat: ... by @author in https://github.com/OpenHands/enterprise/pull/... |
| 246 | + |
| 247 | +#### Software Agent SDK |
| 248 | + |
| 249 | +* feat: ... by @author in https://github.com/OpenHands/software-agent-sdk/pull/... |
| 250 | + |
| 251 | +#### Runtime API |
| 252 | + |
| 253 | +* feat: ... by @author in https://github.com/OpenHands/runtime-api/pull/... |
| 254 | + |
| 255 | +#### Automation |
| 256 | + |
| 257 | +* feat: ... by @author in https://github.com/OpenHands/automation/pull/... |
| 258 | + |
| 259 | +#### OpenHands Cloud (Helm Chart) |
| 260 | + |
| 261 | +* feat: ... by @author in https://github.com/OpenHands/OpenHands-Cloud/pull/... |
| 262 | + |
| 263 | +## Bug Fixes |
| 264 | + |
| 265 | +#### Enterprise Server |
| 266 | + |
| 267 | +* fix: ... by @author in https://github.com/OpenHands/enterprise/pull/... |
| 268 | + |
| 269 | +#### Software Agent SDK |
| 270 | + |
| 271 | +* fix: ... by @author in https://github.com/OpenHands/software-agent-sdk/pull/... |
| 272 | + |
| 273 | +## Maintenance |
| 274 | + |
| 275 | +#### Enterprise Server |
| 276 | + |
| 277 | +* chore: ... by @author in https://github.com/OpenHands/enterprise/pull/... |
| 278 | + |
| 279 | +#### Runtime API |
| 280 | + |
| 281 | +* ci: ... by @author in https://github.com/OpenHands/runtime-api/pull/... |
| 282 | + |
| 283 | +## Component Versions |
| 284 | + |
| 285 | +| Component | Version | |
| 286 | +|-----------|---------| |
| 287 | +| enterprise-server | X.XX.X | |
| 288 | +| agent-server | X.XX.X | |
| 289 | +| agent-canvas | X.XX.X | |
| 290 | +| automation | X.XX.X | |
| 291 | +| runtime-api | X.XX.X | |
| 292 | + |
| 293 | +## Full Changelog |
| 294 | + |
| 295 | +- [Enterprise Server releases](https://github.com/OpenHands/enterprise/releases) |
| 296 | +- [Software Agent SDK releases](https://github.com/OpenHands/software-agent-sdk/releases) |
| 297 | +- [Runtime API releases](https://github.com/OpenHands/runtime-api/releases) |
| 298 | +- [Automation releases](https://github.com/OpenHands/automation/releases) |
| 299 | +- [OpenHands Cloud releases](https://github.com/OpenHands/OpenHands-Cloud/releases) |
| 300 | +``` |
| 301 | + |
| 302 | +**Key formatting rules:** |
| 303 | +- Top-level sections are `## Highlights`, `## Features`, `## Bug Fixes`, `## Maintenance`, `## Full Changelog` |
| 304 | +- Under Features, Bug Fixes, and Maintenance, use `#### Component Name` for each component subsection |
| 305 | +- Keep the exact bullet text from the original release notes (author, PR link) |
| 306 | +- If a component has zero items in a category, omit that component subsection entirely |
| 307 | +- If an entire top-level section has zero items across all components, omit that section entirely |
| 308 | +- The Full Changelog section links to each component repo's releases page on GitHub |
| 309 | + |
| 310 | +### 7. Update navigation |
| 311 | + |
| 312 | +Add the new release page to `docs.json` under the Enterprise tab in a "Release Notes" group. |
| 313 | + |
| 314 | +**First time setup:** If there's no "Release Notes" group yet in the Enterprise tab, create one: |
| 315 | + |
| 316 | +```json |
| 317 | +{ |
| 318 | + "group": "Release Notes", |
| 319 | + "pages": [ |
| 320 | + "enterprise/release-notes/X.Y.Z" |
| 321 | + ] |
| 322 | +} |
| 323 | +``` |
| 324 | + |
| 325 | +**Adding subsequent releases:** Prepend the new release at the **top** of the "Release Notes" pages array, |
| 326 | +so the most recent release appears first in the navigation: |
| 327 | + |
| 328 | +```json |
| 329 | +{ |
| 330 | + "group": "Release Notes", |
| 331 | + "pages": [ |
| 332 | + "enterprise/release-notes/X.Y.Z", // ← new release at the top |
| 333 | + "enterprise/release-notes/A.B.C", // ← previous releases below |
| 334 | + "enterprise/release-notes/D.E.F" |
| 335 | + ] |
| 336 | +} |
| 337 | +``` |
| 338 | + |
| 339 | +The "Release Notes" group should appear after the other Enterprise documentation groups (like |
| 340 | +"OpenHands Enterprise" and "Integrations") in the Enterprise tab navigation. |
| 341 | + |
| 342 | +### 8. Commit |
| 343 | + |
| 344 | +```bash |
| 345 | +git add enterprise/release-notes/X.Y.Z.mdx docs.json |
| 346 | +git commit -m "Add Enterprise X.Y.Z release notes" |
| 347 | +``` |
0 commit comments