Skip to content
Development
Skill

/api-changelog

Draft or audit the REST API changelog (docs/developers-guide/api-changelog.md) by semantically diffing the checked-in OpenAPI spec between two git refs. Use when asked "has the API changelog been updated", "what are the breaking API changes in vNN", when cutting a release

BOOST
From plugin
metabase
50k34 skills11 agents23 commands
Install
$ npx -y skills add metabase/metabase --skill api-changelog --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/api-changelog

Context preview

The summary Claude sees to decide when to auto-load this skill.

Draft or audit the REST API changelog (docs/developers-guide/api-changelog.md) by semantically diffing the checked-in OpenAPI spec between two git refs. Use when asked "has the API changelog been updated", "what are the breaking API changes in vNN", when cutting a release

SKILL.md

api-changelog.SKILL.md
name: api-changelog
description: Draft or audit the REST API changelog (docs/developers-guide/api-changelog.md) by semantically diffing the checked-in OpenAPI spec between two git refs. Use when asked "has the API changelog been updated", "what are the breaking API changes in vNN", when cutting a release branch, or when reviewing whether a PR needs a changelog entry.

API changelog

Answers "what changed in the REST API between two versions, and is the changelog honest about it?"

Ground truth

`resources/openapi/openapi.json` is generated from the Malli endpoint schemas, so the spec at any git ref is what the API actually was at that ref. Diff the spec, do not read endpoint source or boot a server.

Response coverage is partial: about 199 response entries declare a real schema and are compared, but roughly 1,700 are description-only `2XX/4XX/5XX` stubs. For an endpoint with no declared response schema, a response-shape change is invisible here. Say so rather than implying the diff is complete.

Check the spec is fresh first - it usually is not

The self-healing CI job (`.github/workflows/openapi-check.yml`) only runs on PRs labelled `openapi-self-healing`, so the committed spec drifts behind master by default. Verify before trusting a diff:

./bin/mage openapi-staleness

If the source is newer, regenerate before diffing the new ref:

bun run generate-openapi   # rewrites resources/openapi/openapi.json in place

This staleness check only matters when you are diffing the committed spec. `--refs` (below) generates each ref's spec from its own source, so it is not subject to this drift at all - prefer it.

When you do read a committed spec, a change present in source but absent from that spec is a **false negative**: the diff will not report it, and an empty result is indistinguishable from an API that did not change. Confirm suspected gaps with `grep -rn "defendpoint" src/.../api.clj`.

Steps

1. Pick the refs. Default old ref = the previous release branch (`origin/release-x.63.x`), new ref = the one being released (`origin/release-x.64.x`) or `origin/master`. Confirm with the user if ambiguous. `git fetch origin` first.

2. Extract and diff:

   # Preferred: generate both specs from source. ~2 min (two JVM boots), no drift.
   ./bin/mage openapi-diff --refs origin/release-x.63.x origin/release-x.64.x --severity breaking

   # Fast, but reads the committed spec, which lags source. Warns when it does.
   ./bin/mage openapi-diff --refs --committed origin/release-x.63.x origin/release-x.64.x

   # Two spec files directly.
   ./bin/mage openapi-diff /tmp/old.json /tmp/new.json --severity breaking

`--refs` checks each ref out into a throwaway worktree and runs that ref's own `generate-openapi-spec`, so it is not limited to refs that carry a committed spec and never touches your checkout. Very old refs may not build with the current toolchain; it falls back to the committed spec and says so when that happens. Prefer it. `--committed` compares whatever blob each ref happens to carry, and when a release branch and master share a stale one it reports far fewer findings than the API actually changed - an artifact of the spec, not of the API.

Start from the grouped view

A single upstream change can produce hundreds of findings. `--grouped` collapses identical findings and sorts by blast radius, which is the shape you draft from:

   ./bin/mage openapi-diff --refs <old> <new> --severity breaking --grouped

On the real v63 -> master delta that turns 239 breaking findings into 113 distinct changes. The top entry spans 217 endpoints and is one PR (#82447, closing `mu/defn` argument schemas) - **one changelog entry, not 217**.

Drop `--grouped` when you need the per-endpoint view to check a specific route.

A change spanning many endpoints is usually one upstream PR: write it once, name the cause, and say which endpoints it spans. The long tail of single-endpoint changes is where the individually-interesting entries are - the v63 -> master run surfaced a `pinned_state` -> `pinned-state` query param rename there.

Findings are classified and sorted breaking-first.

**A change is breaking when an existing caller, sending exactly what it sent before, can now fail or get a different result.** That covers three cases: the API requires more of the request, provides less in the response, or behaves differently for the same request. The first two invert between request and response:

| | Breaking | Not breaking | |---|---|---| | **Request** | field or param becomes required; type, enum, or bound (`minimum`, `minLength`, `pattern`, ...) narrowed; `additionalProperties: false` added; default changed or dropped | new *optional* field or param; type, enum, or bound widened; field made nullable; schema opened; default added | | **Response** | field removed or no longer always returned; field may now be `null`; new enum value | new field returned; field that was nullable never is | | **Endpoint** | removed | added |

When the tool cannot tell, it ranks the change breaking: a false alarm costs you one look, a miss ships undocumented. Two rules follow from that, not from the definition, so check them before drafting an entry:

  • **A removed request field** is ranked breaking because the spec does not say

whether the server rejects or acts on keys it does not declare. If the endpoint ignores unknown keys, the removal is not breaking.

  • **A change to a schema keyword the tool does not model** is ranked breaking

so that it is never hidden. Read the finding to decide.

A reworded description, title, or example is DOC_ONLY.

Adding an optional parameter is not breaking. Returning extra data is not breaking. Existing callers keep working in both cases.

Start from `--severity breaking`. The long tail of API c

Read more
Ships withmetabase

Metabase is the easy, open-source way for everyone in your company to ask questions and learn from data.

Get the whole plugin

Other skills on metabase.