Changelog generator
Turn git history into one unified changelog that works for everyone in the
company: clear enough for managers and non-tech colleagues, detailed enough for
the developers. There is no "dev vs non-tech" split. Write a single changelog
from both worlds.
Pre-loaded git context
The data below is injected automatically when the skill loads (the ! commands
run first, their output is embedded here). Use it directly. Only fall back to the
Bash tool for cases this data does not cover: an explicit custom range
(v2.0.0..HEAD), a window older than 14 days, or to git fetch for freshness.
if git show-ref --verify --quiet refs/heads/main; then base=main; else base=master; fi
work=$(git rev-parse --abbrev-ref HEAD)
echo "release branch: $base | working branch: $work | today: $(date +%Y-%m-%d)"
echo
echo "=== UNRELEASED ($base..$work) ==="
git log "$base..$work" --no-merges --pretty=format:"%h|%ad|%s" --date=format:"%Y-%m-%d %H:%M"
echo
echo "=== LAST 14 DAYS on $work ==="
git log "$work" --since="14 days ago" --no-merges --pretty=format:"%h|%ad|%s" --date=format:"%Y-%m-%d %H:%M"
1. Pick the commit range from the injected data
- Default (no range args, or "unreleased" / "vs main" / "branch"): use the
UNRELEASED block above.
- If UNRELEASED is empty (common here:
master and develop are kept in
sync with no release tags), fall back to the last 3 days from the LAST 14
DAYS block and tell the user ("master and develop are in sync, showing the
last 3 days instead").
- Date ranges: filter the LAST 14 DAYS block by date using "today" from the
injected header.
- "today" → commits dated today
- "yesterday" → commits dated yesterday only
- "today and yesterday" → both
- "last week" / "7 days" → last 7 days
- Explicit range (
v1.2.0..HEAD, two tags/branches, or a window > 14 days):
the injected data won't cover it. Run the Bash tool yourself:
git log <range> --pretty=format:"%h|%ad|%s" --date=format:"%Y-%m-%d %H:%M" --no-merges
If the chosen range is genuinely empty, say so plainly and stop (don't invent entries).
2. Decide language
There is only one changelog style (see section 3), so the only choice is
language. If the user named it in args ("slovak", "sk", "en", "english"), use it.
Otherwise default to Slovak — do not ask. Only produce English when the user
explicitly requests it ("en" / "english").
3. Write the changelog
One changelog, for the whole company. Each entry must be understandable by a
manager or non-tech colleague, while still carrying enough detail that a developer
recognizes exactly what shipped. Aim for "plain language first, precise detail
second" on every line.
- Read the commit subjects (and PR titles when a subject is terse) to understand
what each change does. Translate intent into clear language; don't just reformat
the raw subject line.
- Map Conventional Commit prefixes:
feat→new feature, fix→fix,
perf→speed/performance, chore/deps→housekeeping, revert→rolled back,
docs→documentation.
- Plain language, but not baby talk. Lead with what changed and where, in
words anyone in the company understands. Don't expose deep code internals (table
names, function names, query patterns, commit hashes) in the wording. But do
keep the vocabulary people recognize: UI elements (badge, menu, nav, hero,
banner, filter, checkout, product card, modal, dropdown, tab) and plain
technical concepts that matter (login, permissions, security, backups, speed).
Translate the mechanism, keep the meaning: e.g. "N+1 queries" → "pages load
faster with less strain on the server".
- Keep the proper names people recognize. Code internals get translated
away, but real names that identify the change must stay: product and section
names (Exclusive Club, special box, tester kit), campaign and integration
names (Bloomreach, Packeta, Doklado), badge and page labels ("Skvelé na
cesty"), and concrete numbers (product IDs, prices, percentages) when they're
the point of the change. Stripping these out makes the line useless. When in
doubt whether a name is "internal noise" or "the thing that shipped", keep it.
- Carry detail for both worlds. Say specifically what changed and where (which
page, section, element, or area), not just "something was improved". Where it
helps a developer trace the change without hurting readability, append a light
reference in parentheses at the end of the line, e.g. a PR number (
#1234) or a
short area tag (payroll, auth). Keep these unobtrusive: plain meaning first,
reference last. Never lead with a hash or internal name.
- Be detailed, don't collapse changes. Give every meaningful change its own
line. Do not merge several distinct changes into one fuzzy summary, and do not
drop a change just because it seems minor. The only things to omit are pure
internal noise with zero impact on anyone (CLAUDE.md edits, throwaway-script
cleanup, doc-file deletes, lint/formatting-only commits, CI tweaks with no
behavior change).
- Group by what people notice, and use as many sections as the changes
warrant. Don't force everything into three buckets. Pick the sections that
actually fit what shipped, and split a broad area into finer sub-sections when
it has several distinct changes. A useful palette to draw from (use only the
ones that apply, add your own when needed):
- Shopping experience — storefront, product pages, cart, checkout, badges,
navigation, search, filters
- Marketing & campaigns — promos, discount codes, gift cards, newsletter,
Bloomreach / integration-driven campaigns
- Speed — anything that makes a page or action faster
- Back office — admin lists, widgets, order/parcel management, internal
tools the team uses
- Sign-in & security — login, permissions, auth, data protection
- Under the hood — refactors, infrastructure, deploy/CI, dependency bumps
that still matter, written plain-first so a manager gets the gist and a
developer gets the specifics
When a section would hold only one line, fold it into the nearest fitting
section rather than leaving a one-item heading. When a section runs long,
split it (e.g. "Shopping experience" → "Product pages" + "Cart & checkout").
- Calibrate length per line: one tight sentence by default. State what
changed and where, then stop. Add a second sentence or a nested sub-bullet
ONLY when it carries information the reader needs (an exact name, number,
edge case, or who it affects). Don't pad with restated mechanism, and don't
strip a line down so far it loses its point. If a line reads as a vague
"something was improved", it's too short; if it explains how the code works,
it's too long.
- Link to e-shop pages when you can. If a change adds a new page or updates
an existing user-facing page/section, and you know the live URL, link it with a
Markdown link so the reader can click straight to it:
- New [size guide](https://shop.example.com/size-guide) page in the footer.
- Find the base URL without guessing: check the repo for it (
.env APP_URL
/ APP_FRONTEND_URL, package.json homepage, a config or constants file,
or the production domain in deploy config). If you genuinely can't determine
it, ask the user once for the storefront base URL, or skip the link rather
than invent a domain.
- Build the full URL from the base plus the route the change touches (e.g.
base
https://shop.example.com + route /exclusive-club →
https://shop.example.com/exclusive-club). Only link routes you can see in
the commit/diff or that the user confirms. Never fabricate a path.
- Link the most specific page that changed, not the bare homepage. For
back-office/admin-only pages, link only when it's genuinely useful.
- Respect global doc style: no em-dashes and no sentence-joining hyphens;
rephrase with periods, commas, or parentheses.
- For Slovak output, write natural Slovak (not a literal translation), and keep
product/section names (Exclusive Club, "looks", special box) as the team uses them.
4. Output format (Markdown)
Output clean, standard GitHub-flavored Markdown:
- Use a
## heading for the title (date range / scope). For each
section/category use a bold label on its own line (**Shopping experience**), NOT a ### heading.
- Use real Markdown list items:
- for each change. You can nest up to 3
levels deep (two-space indentation per level) when a change has sub-points,
e.g. a feature with its details and edge cases. Only nest when it adds clarity;
keep flat lists flat.
- Bold with
**double asterisks**. Use inline code for version numbers or
literal labels when helpful.
- Use Markdown links
[text](url) for new or changed e-shop pages when the live
URL is known (see the linking rule in section 3).
- Put the date range / scope in the title so the reader has context.
- Always output directly in the chat. Never write it to a file. Print it
inside a single fenced code block so the raw Markdown survives copy-paste.
Example shape:
## Changelog (unreleased: master → develop)
**Shopping experience**
- New [Exclusive Club](https://shop.example.com/exclusive-club) page, with product cards that match the regular e-shop layout
- Limited editions show in-stock products first
- New "Sale" badge on discounted product cards
- Shows the exact percentage off
- Hidden once a product sells out
- Main navigation menu reordered, with a clearer "My account" dropdown
- Account dropdown now groups orders, wishlist, and settings
- Wishlist count appears as a small badge next to the icon
- Homepage hero banner now links straight to the active campaign
**Speed**
- Storefront and account pages load faster
- Product listing filters apply without a full page reload
**Under the hood**
- Stronger sign-in security: login sessions expire reliably and sign-in is limited to the approved company domain (auth, #1248)
- Daily backups now exclude session data and secrets, so backups are smaller and safer
- Payroll code consolidated into one shared module, reducing duplication (payroll)
Argument cheatsheet
There is one unified style for everyone, so the only option is language, which
defaults to Slovak.
/changelog → default: main/master vs develop (unreleased), Slovak
/changelog sk → unreleased, Slovak
/changelog en → unreleased, English
/changelog today → today's commits, Slovak
/changelog yesterday sk → yesterday, Slovak
/changelog v2.0.0..HEAD → explicit range (Bash), Slovak
1---2name: changelog3description: Generates a single unified changelog from git history, written in plain language for the whole company, defaulting to Slovak and comparing the release branch against develop for unreleased changes.4---56# Changelog generator78Turn git history into one unified changelog that works for everyone in the9company: clear enough for managers and non-tech colleagues, detailed enough for10the developers. There is no "dev vs non-tech" split. Write a single changelog11from both worlds.1213## Pre-loaded git context1415The data below is injected automatically when the skill loads (the `!` commands16run first, their output is embedded here). Use it directly. Only fall back to the17**Bash** tool for cases this data does not cover: an explicit custom range18(`v2.0.0..HEAD`), a window older than 14 days, or to `git fetch` for freshness.1920```!21if git show-ref --verify --quiet refs/heads/main; then base=main; else base=master; fi22work=$(git rev-parse --abbrev-ref HEAD)23echo "release branch: $base | working branch: $work | today: $(date +%Y-%m-%d)"24echo25echo "=== UNRELEASED ($base..$work) ==="26git log "$base..$work" --no-merges --pretty=format:"%h|%ad|%s" --date=format:"%Y-%m-%d %H:%M"27echo28echo "=== LAST 14 DAYS on $work ==="29git log "$work" --since="14 days ago" --no-merges --pretty=format:"%h|%ad|%s" --date=format:"%Y-%m-%d %H:%M"30```3132## 1. Pick the commit range from the injected data3334- **Default** (no range args, or "unreleased" / "vs main" / "branch"): use the35 **UNRELEASED** block above.36 - **If UNRELEASED is empty** (common here: `master` and `develop` are kept in37 sync with no release tags), fall back to the **last 3 days** from the LAST 1438 DAYS block and tell the user ("master and develop are in sync, showing the39 last 3 days instead").40- **Date ranges**: filter the LAST 14 DAYS block by date using "today" from the41 injected header.42 - "today" → commits dated today43 - "yesterday" → commits dated yesterday only44 - "today and yesterday" → both45 - "last week" / "7 days" → last 7 days46- **Explicit range** (`v1.2.0..HEAD`, two tags/branches, or a window > 14 days):47 the injected data won't cover it. Run the **Bash** tool yourself:48 `git log <range> --pretty=format:"%h|%ad|%s" --date=format:"%Y-%m-%d %H:%M" --no-merges`4950If the chosen range is genuinely empty, say so plainly and stop (don't invent entries).5152## 2. Decide language5354There is only **one** changelog style (see section 3), so the only choice is55language. If the user named it in args ("slovak", "sk", "en", "english"), use it.56Otherwise **default to Slovak** — do not ask. Only produce English when the user57explicitly requests it ("en" / "english").5859## 3. Write the changelog6061One changelog, for the whole company. Each entry must be understandable by a62manager or non-tech colleague, while still carrying enough detail that a developer63recognizes exactly what shipped. Aim for "plain language first, precise detail64second" on every line.6566- Read the commit subjects (and PR titles when a subject is terse) to understand67 what each change does. Translate intent into clear language; don't just reformat68 the raw subject line.69- Map Conventional Commit prefixes: `feat`→new feature, `fix`→fix,70 `perf`→speed/performance, `chore`/`deps`→housekeeping, `revert`→rolled back,71 `docs`→documentation.72- **Plain language, but not baby talk.** Lead with what changed and where, in73 words anyone in the company understands. Don't expose deep code internals (table74 names, function names, query patterns, commit hashes) in the wording. But *do*75 keep the vocabulary people recognize: UI elements (badge, menu, nav, hero,76 banner, filter, checkout, product card, modal, dropdown, tab) and plain77 technical concepts that matter (login, permissions, security, backups, speed).78 Translate the *mechanism*, keep the *meaning*: e.g. "N+1 queries" → "pages load79 faster with less strain on the server".80- **Keep the proper names people recognize.** Code internals get translated81 away, but real names that identify the change must stay: product and section82 names (Exclusive Club, special box, tester kit), campaign and integration83 names (Bloomreach, Packeta, Doklado), badge and page labels ("Skvelé na84 cesty"), and concrete numbers (product IDs, prices, percentages) when they're85 the point of the change. Stripping these out makes the line useless. When in86 doubt whether a name is "internal noise" or "the thing that shipped", keep it.87- **Carry detail for both worlds.** Say specifically what changed and where (which88 page, section, element, or area), not just "something was improved". Where it89 helps a developer trace the change without hurting readability, append a light90 reference in parentheses at the end of the line, e.g. a PR number (`#1234`) or a91 short area tag (`payroll`, `auth`). Keep these unobtrusive: plain meaning first,92 reference last. Never lead with a hash or internal name.93- **Be detailed, don't collapse changes.** Give every meaningful change its own94 line. Do not merge several distinct changes into one fuzzy summary, and do not95 drop a change just because it seems minor. The only things to omit are pure96 internal noise with zero impact on anyone (CLAUDE.md edits, throwaway-script97 cleanup, doc-file deletes, lint/formatting-only commits, CI tweaks with no98 behavior change).99- **Group by what people notice, and use as many sections as the changes100 warrant.** Don't force everything into three buckets. Pick the sections that101 actually fit what shipped, and split a broad area into finer sub-sections when102 it has several distinct changes. A useful palette to draw from (use only the103 ones that apply, add your own when needed):104 - **Shopping experience** — storefront, product pages, cart, checkout, badges,105 navigation, search, filters106 - **Marketing & campaigns** — promos, discount codes, gift cards, newsletter,107 Bloomreach / integration-driven campaigns108 - **Speed** — anything that makes a page or action faster109 - **Back office** — admin lists, widgets, order/parcel management, internal110 tools the team uses111 - **Sign-in & security** — login, permissions, auth, data protection112 - **Under the hood** — refactors, infrastructure, deploy/CI, dependency bumps113 that still matter, written plain-first so a manager gets the gist and a114 developer gets the specifics115 When a section would hold only one line, fold it into the nearest fitting116 section rather than leaving a one-item heading. When a section runs long,117 split it (e.g. "Shopping experience" → "Product pages" + "Cart & checkout").118- **Calibrate length per line: one tight sentence by default.** State what119 changed and where, then stop. Add a second sentence or a nested sub-bullet120 ONLY when it carries information the reader needs (an exact name, number,121 edge case, or who it affects). Don't pad with restated mechanism, and don't122 strip a line down so far it loses its point. If a line reads as a vague123 "something was improved", it's too short; if it explains how the code works,124 it's too long.125- **Link to e-shop pages when you can.** If a change adds a new page or updates126 an existing user-facing page/section, and you know the live URL, link it with a127 Markdown link so the reader can click straight to it:128 `- New [size guide](https://shop.example.com/size-guide) page in the footer`.129 - Find the base URL without guessing: check the repo for it (`.env` `APP_URL`130 / `APP_FRONTEND_URL`, `package.json` `homepage`, a config or constants file,131 or the production domain in deploy config). If you genuinely can't determine132 it, ask the user once for the storefront base URL, or skip the link rather133 than invent a domain.134 - Build the full URL from the base plus the route the change touches (e.g.135 base `https://shop.example.com` + route `/exclusive-club` →136 `https://shop.example.com/exclusive-club`). Only link routes you can see in137 the commit/diff or that the user confirms. Never fabricate a path.138 - Link the most specific page that changed, not the bare homepage. For139 back-office/admin-only pages, link only when it's genuinely useful.140- Respect global doc style: **no em-dashes** and no sentence-joining hyphens;141 rephrase with periods, commas, or parentheses.142- For Slovak output, write natural Slovak (not a literal translation), and keep143 product/section names (Exclusive Club, "looks", special box) as the team uses them.144145## 4. Output format (Markdown)146147Output clean, standard **GitHub-flavored Markdown**:148149- Use a `##` heading for the title (date range / scope). For each150 section/category use a **bold label** on its own line (`**Shopping151 experience**`), NOT a `###` heading.152- Use real Markdown list items: `-` for each change. You can nest up to **3153 levels deep** (two-space indentation per level) when a change has sub-points,154 e.g. a feature with its details and edge cases. Only nest when it adds clarity;155 keep flat lists flat.156- Bold with `**double asterisks**`. Use `inline code` for version numbers or157 literal labels when helpful.158- Use Markdown links `[text](url)` for new or changed e-shop pages when the live159 URL is known (see the linking rule in section 3).160- Put the date range / scope in the title so the reader has context.161- **Always output directly in the chat. Never write it to a file.** Print it162 inside a single fenced code block so the raw Markdown survives copy-paste.163164Example shape:165166```167## Changelog (unreleased: master → develop)168169**Shopping experience**170- New [Exclusive Club](https://shop.example.com/exclusive-club) page, with product cards that match the regular e-shop layout171- Limited editions show in-stock products first172- New "Sale" badge on discounted product cards173 - Shows the exact percentage off174 - Hidden once a product sells out175- Main navigation menu reordered, with a clearer "My account" dropdown176 - Account dropdown now groups orders, wishlist, and settings177 - Wishlist count appears as a small badge next to the icon178- Homepage hero banner now links straight to the active campaign179180**Speed**181- Storefront and account pages load faster182- Product listing filters apply without a full page reload183184**Under the hood**185- Stronger sign-in security: login sessions expire reliably and sign-in is limited to the approved company domain (auth, #1248)186- Daily backups now exclude session data and secrets, so backups are smaller and safer187- Payroll code consolidated into one shared module, reducing duplication (payroll)188```189190## Argument cheatsheet191192There is one unified style for everyone, so the only option is language, which193defaults to Slovak.194195- `/changelog` → default: main/master vs develop (unreleased), Slovak196- `/changelog sk` → unreleased, Slovak197- `/changelog en` → unreleased, English198- `/changelog today` → today's commits, Slovak199- `/changelog yesterday sk` → yesterday, Slovak200- `/changelog v2.0.0..HEAD` → explicit range (Bash), Slovak