Skip to content
Back to skills

Release

ASecurity

Cut a new oracle-forms-mcp release — bump the version in both tag-guarded files consistently, update the changelog, run the pre-flight checks, and (on request) tag. Use when preparing a release or when a release tag failed the version-match guard.

  • 3 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsgokotlingitapi

Works with

  • claude code
  • api
  • mcp

Security analysis

A100/100

Scanned September 19, 2026

npx -y skills add aoreshkov/oracle-forms-mcp --skill release --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Release?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Release
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aoreshkov-release/badge)](https://www.skillsdirectory.com/skills/aoreshkov-release)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: release
description: Cut a new oracle-forms-mcp release — bump the version in both tag-guarded files consistently, update the changelog, run the pre-flight checks, and (on request) tag. Use when preparing a release or when a release tag failed the version-match guard.
disable-model-invocation: true
argument-hint: "[new version, e.g. 0.1.2]"
---

# Cut a release

The release workflow (`.github/workflows/release.yml`) is triggered by a `v*` tag and its
**first step is a hard version-match guard**: if the tag doesn't match the version in both
source-of-truth files, the whole release (GitHub release + GHCR image + MCP registry publish)
fails. This skill makes those files agree *before* the tag is pushed.

## 1. Determine the new version

Use `$ARGUMENTS` if given. Otherwise read the current version from `gradle.properties`
(`version=`), decide the bump with the user (semver), and confirm. Call the new value
`<VERSION>` (no `v` prefix inside files; the git tag is `v<VERSION>`).

## 2. Bump the version in BOTH guarded files

The tag guard checks these two exact patterns (keep the formatting identical):

1. `gradle.properties` — the line `version=<VERSION>` (guard: `^version=<VERSION>$`).
2. `server.json` — the top-level `"version": "<VERSION>"` (guard: `jq .version == <VERSION>`).
   Note: the publish job later rewrites `server.json` `.version` and `.packages[0].identifier`
   from the tag, but the guard still requires the committed value to match, so set it here.

**There is no third file.** The Claude Code plugin manifest
(`plugins/oracle-forms/.claude-plugin/plugin.json`) has a `version` too, but it is the *plugin's*
version, not the project's — bump it only when the plugin's own files change, never as part of a
release. The MCP `Implementation` version is baked at build time from
`project.version` into a classpath resource (`generateVersionResource` in
`server/build.gradle.kts` → `ServerVersion.kt`), and the MCPB bundle's manifest version comes from
the same place via the `@version@` token in `server/mcpb/manifest.template.json` — so neither can
drift from `gradle.properties`. Do not hand-edit a version constant in the Kotlin sources or the
manifest template. The `icons[].src` URLs in `server.json` also need no hand-editing: the publish
job re-pins them to the tag (the guard only checks they point at a `vX.Y.Z` tag, never a branch).
Confirm the two files:

```
grep -n "version=" gradle.properties
grep -n '"version"' server.json
```

## 3. Update the changelog

`CHANGELOG.md` follows Keep a Changelog. Move the `## [Unreleased]` items into a new
`## [<VERSION>] - <YYYY-MM-DD>` section, add a fresh empty `## [Unreleased]`, and update the
link-reference lines at the bottom (`[Unreleased]` compare range + a new `[<VERSION>]` tag link).
Use `git log <last-tag>..HEAD` to gather user-facing changes. (The GitHub release itself also
sets `generate_release_notes: true`, but the curated changelog is the human-facing record.)

## 4. Pre-flight checks (catch the known release-pipeline gotchas)

- **MCP registry field caps:** in `server.json`, both `.description` and `.title` must be **≤ 100
  characters** or the registry publish rejects the listing. Verify:
  `jq -r '.description | length, (.title | length)' server.json` → both ≤ 100. (The release
  workflow's guard step re-checks this, along with the icon URLs being tag-pinned.)
- **MCPB bundle builds:** `./gradlew :server:packageMcpb` produces
  `server/build/mcpb/oracle-forms-mcp-<VERSION>.mcpb`. Its sha256 is computed in CI and written
  into the registry listing, so a broken bundle fails the release. Sanity-check the archive has
  `manifest.json` at the root and an executable `server/bin/server` (`unzip -Z <bundle>`).
- **Claude Code plugin channel:** the plugin's launcher installs the release zip by checking it
  against the `oracle-forms-mcp-server-<VERSION>.zip.sha256` asset the release workflow publishes,
  so a release missing that asset breaks `/plugin install` for everyone on `server_version=latest`.
  Confirm the "Package distribution" step still writes it, and after the release confirm the asset
  is attached (`gh release view v<VERSION> --json assets`).
- **`gradlew` executable bit:** the wrapper must stay executable in git or the CI build fails
  on a fresh checkout. Verify: `git ls-files -s gradlew` shows mode `100755`.
- **No private paths leak:** confirm nothing under `docs/` (private) is referenced from
  released files, and `docs/` is gitignored (`git check-ignore docs/`).
- **Public API is in sync:** `./gradlew checkKotlinAbi` passes (run `updateKotlinAbi` first if it
  fails and the change was intentional).
- **Build is green:** `./gradlew build` passes, and `./gradlew :server:installDist` produces
  the distribution the release zip is built from.

## 5. Simulate the tag guard locally

Before tagging, run the guard's own logic so you don't discover a mismatch in CI:

```
VERSION="<VERSION>"
grep -q "^version=${VERSION}$" gradle.properties && \
jq -e --arg v "$VERSION" '.version == $v' server.json >/dev/null && \
echo "guard OK" || echo "guard WOULD FAIL"
```

## 6. Commit and (on explicit request) tag

Commit the version bump + changelog. **Only if the user explicitly asks**, create and push an
**annotated** `v<VERSION>` tag — pushing the tag triggers the live release, GHCR push, and MCP
registry publish. Otherwise stop after the commit and report that the tag is ready to push.

```
git tag -a v<VERSION> -m "oracle-forms-mcp v<VERSION>"
git push origin v<VERSION>
```

Use an annotated tag (`-a`), not a lightweight one: it carries the tagger, date, and message,
is preferred by `git describe`, and can be signed. This matches `v0.1.0`. Note that
`release.yml` triggers on either tag type (`on: push: tags: v*`), so this is hygiene, not a
functional requirement.

**Never re-tag or force-move an already-published tag** (e.g. `v0.1.1`, which is live on GHCR
and the MCP registry). Fix a bad release by cutting the next version, not by moving its tag.

## 7. Report

Summarize: old → new version, the two files updated, changelog entry, pre-flight results
(description/title length, MCPB bundle build, gradlew mode, checkKotlinAbi, build status, local
guard simulation), and whether a tag was pushed or is pending. Note that the tag publishes four
things: the GitHub release (zip + its `.sha256` + `.mcpb`), the GHCR image, and the MCP Registry
listing. The Claude Code plugin channel is not tagged — it serves from `main` — but it *consumes*
the release, so it only picks up the new server once the release assets are live.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.