Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 124 additions & 25 deletions .cursor/skills/sdk-changelog/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Generate changelogs for SDK pod packages following the monorepo GitFlow.

## Workflow

Every step is mandatory. Do **not** ask the user whether to do `CHANGELOG_LLM.md` or
`NOTICE` β€” they are part of this skill and always run.

### Step 1: Identify Target Package

If the user doesn't specify, ask which SDK pod package they want to generate a changelog for.
Expand Down Expand Up @@ -56,20 +59,126 @@ With migration flags:
node scripts/sdk/generate-changelog-sdk-pod.cjs --package=<name> --base-commit=<sha> --base-version=<version>
```

### Step 4: Generate CHANGELOG_LLM.md (if requested)
The script automatically excludes:

- PRs tagged `[skiplog]`.
- **Backmerge PRs** (subjects starting with `Backmerge` or `Merge release …`).
Backmerges merge a release branch back into main; their content is already
documented in the release branch's own changelog, so listing them here is noise.
- PRs whose title fails the SDK PR-format validator (these are warned, not silently
dropped β€” fix the title and re-run, or surface to the PR author).

For `[mod]` PRs, the script extracts the `Added`/`Updated`/`Removed` model lists
from the PR body and renders them as **indented continuation lines beneath the
bullet** in `CHANGELOG.md` (each section on its own line β€” never inline as one
giant row). The same filtered lists are written to `models.md`.

The extractor applies two policies (in this order):

1. **Companion entries are dropped.** Companions are auxiliary files that ship
alongside a primary model but aren't independently usable β€” vocab files,
lexicons, raw data shards, metadata blobs. The filter recognises constant
suffixes (`*_LEX`, `*_VOCAB`, `*_DATA`, `*_METADATA`) **and** any free-form
description containing the word "companion". Only first-class models reach
the changelog.
2. **Entry-count suffixes are stripped.** `(N entries)` /
`(N entries β€” short note)` decorations are removed from the displayed
text β€” readers can follow the `models.md` link for exact counts.

After both filters, each section is trimmed to `MAX_INLINE_MODELS` (currently
**5**) entries, with `(and N more)` for the remainder. Example:

```
- Regenerate model registry. (see PR [#123](...)) - See [model changes](./models.md)
Added: NMT_Q0F16, NMT_Q4_0 (and 12 more)
Removed: MARIAN_OPUS_*
```

If after filtering a section is empty, it's omitted. If all sections are empty
the bullet emits with no continuation lines.

When writing the human-readable `CHANGELOG_LLM.md` (Step 4), apply the same
"no informational value" rule manually: skip backmerges, automated bumps, and any
entry whose subject would just repeat what a previous release already said. For
the Models section, mirror the script's policy β€” keep it concise in the body
(highlight the most notable adds/removes) and defer the full constant list to
the `### Added` / `### Removed` blocks at the bottom.

### Step 4: Generate CHANGELOG_LLM.md (mandatory)

Always run this step. Do not ask the user β€” it's part of the skill.

After raw changelog files exist, generate the human-readable version at
`packages/<package>/changelog/<version>/CHANGELOG_LLM.md`.

After raw changelog files exist, generate the human-readable version.
See [references/changelog-llm-format.md](references/changelog-llm-format.md) for the format guide.

After writing the file, re-run the raw generator (or rebuild the root aggregate) so
`packages/<package>/CHANGELOG.md` picks up the new `CHANGELOG_LLM.md` (the aggregator
prefers it over `CHANGELOG.md`). Easiest way: re-run the script from Step 3 β€” it's idempotent.

### Step 5: Generate `announcement-post.txt` (mandatory)

Always run this step after Step 4. It produces a Slack-ready copy-paste post at
`packages/<package>/changelog/<version>/announcement-post.txt`.

The file is **gitignored** (`packages/*/changelog/*/announcement-post.txt`) β€” it's a
local working artifact, not a committed deliverable. Never `git add` it.

```bash
node scripts/sdk/generate-changelog-sdk-pod.cjs --package=<name> --generate-announcement-post
```

The script parses `CHANGELOG.md` for the package's current version (from
`package.json`) and emits the Slack template:

- `:qvac: SDK <version> :rocket: NPM Public release` header.
- NPM, GitHub release, and full-changelog tree links.
- `:warning: Breaking Changes` section (with link to `breaking.md`) β€” only if any
PR is breaking.
- `Release Date: YYYY-MM-DD`.
- One Slack section per CHANGELOG.md section (`:sparkles: Features`,
`:electric_plug: API`, `:ladybug: Fixes`, `:package: Models`, `:blue_book: Docs`,
`:test_tube: Tests`, `:broom: Chores`, `:gear: Infrastructure`).
- Each bullet uses `β€’`, wraps the PR URL in `<...>` (suppresses Slack unfurl), and
appends ` :boom: breaking` when the bullet is breaking.
- Sections are capped at `MAX_ANNOUNCEMENT_BULLETS` (currently **10**). The
`... And much more, see full list in changelog :memo:` line is only added
when a section has *more than 10* entries; anything 10 or fewer is emitted
verbatim.
- Footer: `Thanks to everyone on QVAC team :green_heart: :qvac: :green_heart:`.

If the post needs hand-tuning (e.g. the Models section needs custom count summaries
that the parser can't infer), edit the file directly. It's gitignored, so changes
won't pollute the diff.

### Step 6: Update NOTICE file for the target package

After Step 5 completes, run notice-generate for the same `--package` to ensure
its NOTICE file reflects any dependency changes in the release:

```bash
source .env
node .cursor/skills/notice-generate/scripts/generate-notice.js <package-name>
```

Do NOT commit the announcement post (gitignored) and let the user review the rest
before committing.

See `.cursor/skills/notice-generate/SKILL.md` for full details.

## CLI Parameters

| Flag | Required | Description |
| ---------------- | -------- | ------------------------------------------------------------------ |
| `--package` | Yes | Package name (e.g., `sdk`) |
| `--base-commit` | No | Initial commit SHA for migration (overrides tag lookup) |
| `--base-version` | No | Version label for base commit (display only) |
| `--release-type` | No | `minor` or `patch` (auto-detected from package.json version) |
| `--dry-run` | No | Preview output without writing files |
| Flag | Required | Description |
| ------------------------------- | -------- | ------------------------------------------------------------------ |
| `--package` | Yes | Package name (e.g., `sdk`) |
| `--base-commit` | No | Initial commit SHA for migration (overrides tag lookup) |
| `--base-version` | No | Version label for base commit (display only) |
| `--release-type` | No | `minor` or `patch` (auto-detected from package.json version) |
| `--dry-run` | No | Preview output without writing files |
| `--update-root-changelog` | No | Rebuild only the root aggregate `packages/<pkg>/CHANGELOG.md` |
| `--generate-announcement-post` | No | Generate `announcement-post.txt` for the package's current version |
| `--version` | No | Override version when used with `--generate-announcement-post` |

## Output

Expand All @@ -79,7 +188,9 @@ Generates changelog files in `packages/<package>/changelog/<version>/`:
- `breaking.md` - Breaking changes detail (if `[bc]` PRs)
- `api.md` - API changes detail (if `[api]` PRs)
- `models.md` - Model changes (if `[mod]` PRs)
- `CHANGELOG_LLM.md` - Human-readable version (generated separately via Step 4)
- `CHANGELOG_LLM.md` - Human-readable version (always generated, see Step 4)
- `announcement-post.txt` - Slack copy-paste post (always generated, see Step 5,
**gitignored** β€” never commit)

Additionally:

Expand All @@ -95,19 +206,6 @@ Examples:
- `sdk-v0.8.1` (patch β€” used as base for next patch release)
- `rag-v2.0.0`

### Step 5: Update NOTICE file for the target package

After changelog generation completes, run notice-generate for the same `--package` to ensure its NOTICE file reflects any dependency changes in the release:

```bash
source .env
node .cursor/skills/notice-generate/scripts/generate-notice.js <package-name>
```

Do NOT commit β€” the user will review and commit.

See `.cursor/skills/notice-generate/SKILL.md` for full details.

## Quality Checklist

Before completing:
Expand All @@ -116,9 +214,10 @@ Before completing:
- [ ] Base reference resolved (tag or `--base-commit`)
- [ ] PRs scoped to package path only
- [ ] Changelog files written to correct version directory
- [ ] If CHANGELOG_LLM.md requested, follows format guide
- [ ] CHANGELOG_LLM.md generated (mandatory) and follows format guide
- [ ] announcement-post.txt generated (mandatory, gitignored)
- [ ] NOTICE file updated for the target package
- [ ] Root CHANGELOG.md rebuilt from all version folders
- [ ] Root CHANGELOG.md rebuilt from all version folders (and picks up CHANGELOG_LLM.md)
- [ ] Versions sorted in descending semver order
- [ ] No duplicated versions
- [ ] Root file is deterministic (fully regenerated)
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ packages/**/.npmrc
packages/sdk/bun.lock
NOTICE_LOG.txt
NOTICE_FULL_REPORT.txt

# Slack/Discord copy-paste announcement posts generated by the
# changelog skill (see scripts/sdk/generate-changelog-sdk-pod.cjs
# --generate-announcement-post). These are local working artifacts,
# not release deliverables β€” never commit them.
packages/*/changelog/*/announcement-post.txt
.claude/worktrees

# Auto-generated agent config (run /setup to regenerate)
Expand Down
Loading
Loading