---
name: code-changelog
description: >
  Add a developer-facing changelog entry as a file in the changelogs/ directory, documenting
  a change so it lands in the next release. Use when the user says /code-changelog, /changelog,
  'add changelog', 'add a changelog entry', 'ajoute un changelog', 'ajoute une entrée de changelog',
  'écris le changelog', 'documente ce changement', 'note ce changement pour la release',
  'changelog entry', 'write a changelog', or needs to record a change for the next release.
  Distinct from /code-release-notes (user-facing notes in FR/EN/IT for stores and docs) and
  /code-get-next-version (which only computes the next semver from existing changelog entries).
argument-hint: "[optional: description override]"
allowed-tools:
  - Bash
---

Create a changelog entry file in the `changelogs/` directory.

## Decide first — a new entry is not always needed

Before generating, ask whether this work is a **net-new, separately-announceable change** or a **correction/adjustment to work whose changelog entry is still pending** — i.e. the entry describing it still sits as a file under `changelogs/` and has **not** shipped yet (a release merges those files into `CHANGELOG.md` and deletes them, so a still-present `changelogs/*.md` file = not released). Two cases let you avoid creating a second entry:

1. **No new entry — open the MR without a changelog.** The correction makes a still-unreleased change behave as the pending entry *already describes* (a pre-release bug found before shipping, a follow-up tweak). Users will only ever see the final behaviour, described once by the existing entry — there is nothing new to announce. `/glab-mr` allows a changelog-less MR in exactly this case.
2. **Update the existing pending entry.** The correction *changes the behaviour the pending entry describes*, so that entry would become inaccurate. Reword the existing entry instead of adding a second one, so the release notes stay correct and singular.

To locate the pending entry, look under `changelogs/` for the file describing the change being corrected — often `changelogs/<original-branch>.md`, or `grep -rl "(#<original-iid>)" changelogs/`.

A **new** entry *is* required whenever the work is an independent change that users should hear about on its own — even if it touches the same area as a pending entry.

### Editing an existing pending entry (the one sanctioned manual edit)

The "never hand-edit `changelogs/`" rule below forbids hand-**creating** an entry. **Updating the prose of an entry that already exists** — to reflect a behaviour change — is the single allowed exception, because the generator can only write the *current* branch's file and cannot retarget another branch's entry. When you edit one:
- Keep the exact skeleton `* <type>: <description> (#<iid>)` — change only the wording (and the `<type>` if the nature of the change flipped, e.g. `feat` → `fix`).
- Never alter the `(#<iid>)` unless the original ticket reference is genuinely wrong.
- Run `pysae-ai-tools code changelog validate --fix` afterwards — it must pass before the MR.

**CRITICAL — read carefully:**

- **Always use the script below.** It is the *only* sanctioned way to create or modify a file under `changelogs/`. The script resolves the correct filename from `mr_source_branch` via `detect_context` and emits the strict format `* <type>: <description> (#<iid>)`.
- **Never use `Write`, `Edit`, `cat >`, `echo >`, or any other tool to _create_ or _overwrite_ a file under `changelogs/`.** Even if the script's output looks too short, truncated, or imperfect — do not "fix it up" manually. If the result is wrong, re-run the script with a better `--type` or description argument, or report the issue to the user. Hand-written entries silently break the format (`* #IID Description...` instead of `* type: description (#IID)`) and the release pipeline. (The **one exception** is rewording an *already-existing* pending entry to reflect a behaviour change — see "Editing an existing pending entry" above — where you keep the skeleton and re-run `validate --fix`.)
- **Never include `(#IID)` in the description argument** — the script appends it.
- **`description` is a positional argument, not a flag.** There is no `--description` option — pass the text directly after the options, quoted.
- **Changelog entries are always written in English** (conventional-commits style: lowercase, imperative). The auto-resolved description source (issue title, MR title, commit message, branch slug — see below) is often in French; when it is, **pass an explicit English `description` argument** so the entry lands in English. Never let a French title flow through into the entry.

```bash
pysae-ai-tools code changelog generate --write --json "english description from $ARGUMENTS"
```

**Generation requires a `CHANGELOG.md` at the repo root.** Its presence is the
signal that the project uses the changelog system. When it is absent the script
generates **nothing** and exits 0 with `{"skipped": "changelog_md_absent"}` — do
not work around this with `Write`/`Edit`; the repo simply doesn't use changelogs.
This is the only case where the *script*, once invoked, generates nothing.
(Separately, the "Decide first" section above may tell you not to invoke the
script at all — when the work needs no new entry — which is a deliberate choice,
not a skip.)

To **opt a repo into** the changelog system, run the idempotent bootstrap (it
creates `changelogs/` and an empty `CHANGELOG.md`, leaving any existing files
untouched), then re-run `generate`:

```bash
pysae-ai-tools code changelog init   # safe to re-run; --root <path> to target another dir
```

Only run `init` when the user explicitly wants to start using changelogs in this
repo. It is the clean alternative to the one-shot `--create-directory` escape hatch.

**Optional overrides** (use only when auto-detection picks the wrong value):
- `--type <feat|fix|tech|…>` — force the change type
- `--issue-iid <IID>` — force the `(#IID)` suffix when the branch name has no IID (e.g. `main`, cherry-pick branches) or when the auto-detected IID is the wrong ticket
- `--create-directory` — legacy escape hatch: generate even when there is no `CHANGELOG.md`, creating `changelogs/` as needed. Use only if the user explicitly wants to bootstrap the changelog system in a repo that lacks it.

To validate all entries in `changelogs/` against **both** the strict conventional
commits format **and** the ≤ 200-char length budget (optionally auto-fixing
non-conforming entries):

```bash
pysae-ai-tools code changelog validate           # lint only (format + length)
pysae-ai-tools code changelog validate --fix     # lint + auto-fix format
```

`--fix` repairs format issues (missing `* ` bullet, wrong type prefix) but
**cannot** fix an over-budget entry — trimming a description is a semantic edit.
A too-long entry always surfaces as a failure reporting how many chars to trim;
reword it under 200 chars and re-run. This is the same budget `generate`
enforces, so an over-long entry can no longer slip past `validate` into a release.

The script handles everything automatically:
- Filename: `changelogs/<mr_source_branch>.md` (with `/` replaced by `-`), fallback to `git_branch`
- Type: issue `type::*` label > branch prefix > commit prefix > `tech`
- Description: issue title > MR title > commit message > branch slug
- Issue ref `(#IID)`: added automatically — **never include `(#IID)` in the description**

**Length budget.** Total entry length (prefix `* ` included) must be ≤ 200 chars.
If the resolved description blows the budget, the script exits 1 and emits an
error JSON of the form:

```json
{
  "error": "description_too_long",
  "current_length": 223,
  "max_total_length": 200,
  "max_description_length": 187,
  "type": "feat",
  "issue_iid": "123",
  "description": "<original description that was too long>",
  "content": "<the full over-budget entry>"
}
```

When you get this error, **rewrite the description yourself** so it fits within
`max_description_length` characters (keep meaning, drop filler words), then
re-run the same command with the shorter text as `$ARGUMENTS`. Do *not* simply
chop the original — produce a clean, idiomatic shorter description. Repeat
until the script succeeds.

Display the JSON output to the user. Do not commit.

$ARGUMENTS
