| name | sw-changelog |
| description | Generate a customer-facing Superwall changelog for a given day or date range by reviewing what landed on the main branch in that window, then publish it as a GitHub release. Classifies each change as customer-facing (SDK, dashboard, product, integrations) versus internal (repo tooling, build, CI, refactors) and omits everything internal. Use when the user wants a changelog, release notes, or a "what shipped" summary for a date or date range. |
| user-invocable | true |
Superwall Changelog
Generates a customer-facing changelog for a day or date range and publishes it as a GitHub release.
The changelog answers one question for a Superwall customer: what changed in the product during this window? It covers SDK releases, dashboard changes, new integrations, and anything core to the Superwall product. It omits everything internal to the repo — build tooling, CI, redirects plumbing, component refactors, skills, dependency bumps, formatting/typo fixes, and anything else a customer would never notice.
Hard rules
- Read-only on the repo. This skill only reads git history and publishes a GitHub release. It must never edit, create, or delete repository files, and never commit anything.
- Skip entirely when there is nothing to ship. If the window has no changes at all, or only internal changes, produce no release — do not create an empty or internal-only release.
- The release tag is the end day of the range (
YYYY-MM-DD), not the current date.
Input: the time period
The user gives a time period — either a single day (2026-06-30) or a range (2026-06-01 to 2026-06-30). If none is given, ask for one; never assume "today".
Interpret the period as full calendar days in the repo's local timezone:
- Start =
YYYY-MM-DD 00:00:00 of the first day.
- End =
YYYY-MM-DD 23:59:59 of the last day (for a single day, first day = last day).
The end day (YYYY-MM-DD) is the release tag (see the final step).
What counts as "in the window"
Use the date a change landed on main, not the date it was originally authored.
A commit written on Jan 1 on a feature branch and merged into main on Jan 15 belongs in the Jan 15 changelog.
Practically, this means filtering by commit/merge date on the first-parent history of main (the landing time), not by author date.
Voice & writing style
Changelog entries are short and factual, but they should still read in Superwall's customer voice. The principles below are distilled from Superwall's GTM customer-voice research — apply them when writing each entry's title and description.
This section is a point-in-time snapshot. The demand signals and phrases below were captured from research at a fixed moment and only reflect features and language that existed then — they say nothing about what shipped after. Treat them as a style guide, not a checklist:
- Never ignore or downgrade a real change just because it doesn't match the vocabulary here. A brand-new product area with no phrase in this list is still changelog-worthy — describe it plainly in customer terms.
- Don't force a change to fit a listed phrase or demand signal if it isn't actually about that. The actual diff (step 3) is always the source of truth; this section only shapes how you phrase what genuinely shipped.
- The "avoid" guidance (no jargon, no hype, no invented claims) is durable and always applies; the specific phrase/signal lists are illustrative and will go stale.
Core principle — lead with the customer job, not the internal feature name. Customers don't care about "a paywall SDK" in the abstract; they care about being able to change, test, and learn from their monetization without waiting on app releases or engineering. Frame what shipped in terms of what a growth/marketing team can now do.
What Superwall customers care most about (use this to frame and prioritize entries): paywall A/B testing and experimentation; promotions, win-back, offers, and abandoned-transaction recovery; onboarding flow optimization; price testing and localization; web paywalls / web2app; paywall analytics; and shipping changes without an app release.
Phrases that match the customer's language (reuse where they fit the actual change — never to embellish one that didn't happen):
test anything fast · no app release · no engineering queue · paywall experiments · price tests · offer tests · onboarding experiments · abandoned-transaction recovery · one place for the data · web and app monetization · growth teams · subscription apps · variants at a glance · full-funnel testing.
Avoid:
- Leading with SDK-first or repo/commit jargon (translate it into the customer outcome).
- Generic AI/SaaS filler — "unlock growth," "seamless," "revolutionize," "game-changing," vague "unlock revenue."
- Numeric lifts or outcome claims that aren't in the actual change (never invent a "+X% conversion").
- Marketing hype generally. A changelog states what shipped — keep it accurate and concrete; the customer framing is the only embellishment allowed, and only when it's true.
Workflow
1. Resolve the repo
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
$REPO (e.g. superwall/docs) is used for the --repo flag throughout.
2. Collect everything that landed on main in the window
Merged PRs are the primary source — merged: is the landing date, which is exactly what we want:
gh pr list --repo "$REPO" --base main --state merged \
--search "merged:{START_DATE}..{END_DATE}" \
--json number,title,mergedAt,labels,files \
--limit 300
Then catch any direct pushes to main that never went through a PR. Filter the first-parent history by committer date (the landing time):
git log --first-parent main \
--since="{START} 00:00:00" --until="{END} 23:59:59" \
--date=local \
--pretty=format:'%h%x09%cI%x09%an%x09%s'
De-duplicate: a commit already represented by a merged PR is not also listed as a standalone commit.
3. Inspect the actual changes — don't trust titles alone
Titles, commit messages, PR descriptions, and labels are hints, not evidence. They are often wrong, stale, or vague. Before classifying or describing anything, read the real diff for each candidate change and base every decision on what the code/content actually does.
gh pr diff {number} --repo "$REPO" --patch
gh pr view {number} --repo "$REPO" --json files,title,body
git show --stat {sha}
git show {sha}
Use the diff to:
- Verify the claim. A PR titled "fix typo" that actually adds a new integration guide is a New Feature; a "feat: ..." PR that only touches CI config is internal. Trust the changed files and patch over the title.
- Find the real customer-facing substance. Read the added/changed content (e.g. what the SDK changelog entry actually says, what a new docs page documents) so the changelog describes what genuinely shipped.
- Catch mixed changes. A single PR can contain both a customer-facing change and internal noise; classify on the customer-facing part and describe only that.
Then decide per change using the file paths and patch contents:
Customer-facing (include): anything that reflects a change to the Superwall product that a customer would care about —
- SDK releases / version updates / SDK changelog entries (iOS, Android, Flutter, Expo, React Native).
- New or meaningfully expanded integration guides (e.g. a new analytics/attribution integration).
- New product capabilities, dashboard features, or paywall/builder features.
- Substantive new docs that document a real product capability for the first time.
Internal (omit): anything a customer would never notice —
- Build/CI/tooling config, redirects plumbing, dependency bumps, performance/infra work.
- React component or site refactors, layout/styling of the docs site itself.
- Skills, agent config, repo meta,
CLAUDE.md/AGENTS.md.
- Pure maintenance of existing docs: typo/grammar/link fixes, formatting, restructuring, image swaps — when no product behavior changed.
When unsure, ask: would a Superwall customer care that this changed? If no, omit it.
4. Bucket the customer-facing changes
- New Features — net-new capability: a new integration, a new SDK feature, a new dashboard/product feature, brand-new documentation of a real capability.
- Improvements — enhancements, fixes, clarifications, and maintenance SDK version bumps to existing functionality.
For an SDK version bump, read the corresponding SDK changelog entry (content/docs/<sdk>/changelog.mdx or upstream) to decide: if it headlines a genuinely new capability, it's a New Feature; routine release/fix bumps go under Improvements. A single release can contribute one entry to each section when it clearly does both.
5. Write the changelog
Exact format — a title linked to the live docs page, an em dash, then a one-line description:
## New Features
[Feature Gating](https://superwall.com/docs/android/quickstart/feature-gating) — Gate any part of your app behind an entitlement and let Superwall decide when to paywall.
## Improvements
[Paywall Presentation](https://superwall.com/docs/ios/paywalls/presentation) — Paywalls now present more reliably before configuration has finished loading.
Rules for entries:
- Link the title to the live docs page where the customer can read more —
[Title](https://superwall.com/docs/{slug}). Derive the URL from the docs page the change is about (see Mapping changed files to live docs URLs below). This docs link is the only link in an entry.
- No author attribution and no PR/commit link. Don't append a
[name](url) byline; the person who edits the docs is usually not the person who built the feature, so crediting the docs author is misleading.
- Write the title and description in customer language about the product, not in repo/commit jargon — follow Voice & writing style above. Translate
feat(ios): update for 4.15.4 into what shipped for the customer.
- Ground every description in the diff you read in step 3 — describe what actually changed, not what the title or PR description claimed. Don't restate a commit message you couldn't verify against the changes.
- Keep descriptions to one concise sentence.
- Omit any section that has no entries (e.g. if there are only improvements, don't emit an empty
## New Features).
- Order entries within a section by impact, most significant first.
Mapping changed files to live docs URLs
- Docs content lives in
content/docs/**; the live site serves it under https://superwall.com/docs/**.
- A file
content/docs/{slug}.mdx maps to https://superwall.com/docs/{slug} (drop the .mdx). An index.mdx maps to its directory — content/docs/android/index.mdx → https://superwall.com/docs/android.
- Pick the single most relevant page the entry is about: usually the main content page the diff added or changed. Ignore
meta.json, images, shared partials/snippets, and engineering files when choosing the link target.
- For an SDK version bump, link to that SDK's changelog page —
https://superwall.com/docs/{sdk}/changelog — unless a specific new feature page is the better destination for what shipped.
- Verify the URL resolves on the live site before using it (e.g.
curl -sI -o /dev/null -w '%{http_code}' https://superwall.com/docs/{slug}). Paths can differ from the file tree via redirects-map.ts, so confirm rather than assume. If a page 404s, fall back to the nearest existing parent page (e.g. the section index). Never invent a URL.
- If no published docs page documents the change, link to the closest relevant existing page; only if truly none exists, leave the title unlinked (plain
**Title**).
6. Publish (or skip)
If there are no customer-facing entries, stop here and tell the user nothing was released for the window — do not run gh release create.
Otherwise create the release. The tag is the end day of the range in YYYY-MM-DD form (for a single day, that day; for a range, the last day) — not the current date.
Durability check — does a release for this day already exist? Before creating, look it up:
gh release view "{YYYY-MM-DD}" --repo "$REPO" --json tagName,name,body,createdAt 2>/dev/null
-
If it does not exist, create it:
gh release create "{YYYY-MM-DD}" \
--repo {repo} \
--title "some title" \
--target main \
--notes "{changelog content}"
-
If a release for that day already exists, do not blindly overwrite it. Read its existing notes and use judgement:
-
If your new changelog is a superset of what's there (same window, now with more/clearer entries), replace the notes:
gh release edit "{YYYY-MM-DD}" --repo "$REPO" --notes "{changelog content}"
-
If the existing release covers a different but overlapping slice of the same day (e.g. it was published earlier for a narrower window), merge: combine the entries, de-duplicate by PR/commit, keep the ## New Features / ## Improvements structure, and write the merged result back with gh release edit.
-
Never duplicate an entry that's already present, and never drop an existing valid entry that your new run didn't rediscover.
-
{repo} is $REPO; {changelog content} is the markdown from step 5.
-
Give the release a concise human --title — the date or range, optionally with a short summary (e.g. June 30, 2026 or 2026-06-01 – 2026-06-30).
Final response
After publishing, reply in chat with a short summary: the window covered, how many changes landed vs how many were customer-facing, the release tag/URL, and the changelog markdown. If you skipped, say so and why (no changes, or internal-only).