Skip to main content
Glama
README.md
# changelogforge

A release is ready, the pull requests are merged, and now
someone has to turn that list into the changelog section
readers will actually scan. changelogforge does that one
job: it takes the merged pull requests for a release, sorts
them into labelled groups, and renders the section as
Markdown in a fixed, predictable shape.

- **Grouping by label** — each pull request joins the first
  label in `group_order` that it carries. The default order
  is `feature`, `bugfix`, `documentation`, `maintenance`,
  and you can supply your own list to rename, reorder, add,
  or drop groups. Matching is exact and case-sensitive.
- **An other group** — a pull request carrying none of the
  group labels lands in a final group whose heading is
  `Other changes`. Groups that end up empty are left out
  entirely, and the other group only appears when it has
  something in it.
- **Stable ordering** — groups follow `group_order` with
  the other group always last, and inside a group the pull
  requests are sorted by number ascending, so the same
  input always renders the same section.
- **Exact Markdown** — the version heading sits at
  `heading_level` (default 2) and group headings one level
  deeper. The result also returns the grouped structure
  itself, so a caller can render the same data another way.

Version and date are printed in the heading exactly as
given; neither is parsed or reformatted. Pull request
numbers must be unique across the list — a repeat is a
validation error naming both occurrences, for example
`pull_requests[2].number duplicates pull_requests[0].number`
— and every other malformed field is likewise an error
naming its path, with no partial section produced. The
computation is pure and local: no network, no
configuration, no files read beyond the input you pass in.

## CLI

```bash
npx @reneturcios/changelogforge generate --input args.json
npx @reneturcios/changelogforge --version
```

`args.json` contains the full arguments object:

```json
{
  "version": "1.2.0",
  "date": "2026-10-27",
  "pull_requests": [
    { "number": 7, "title": "Add export button", "labels": ["feature"] },
    { "number": 12, "title": "Fix crash on empty input", "labels": ["bugfix"] },
    { "number": 15, "title": "Tidy internals" }
  ]
}
```

`labels` defaults to `[]` per pull request, `group_order`
to `["feature", "bugfix", "documentation", "maintenance"]`,
and `heading_level` to `2`. The rendered section is printed
as JSON:

```json
{
  "version": "1.2.0",
  "date": "2026-10-27",
  "groups": [
    { "group": "feature", "heading": "feature", "pull_requests": [{ "number": 7, "title": "Add export button" }] },
    { "group": "bugfix", "heading": "bugfix", "pull_requests": [{ "number": 12, "title": "Fix crash on empty input" }] },
    { "group": "other", "heading": "Other changes", "pull_requests": [{ "number": 15, "title": "Tidy internals" }] }
  ],
  "markdown": "## 1.2.0 (2026-10-27)\n\n### feature\n\n- Add export button (#7)\n\n### bugfix\n\n- Fix crash on empty input (#12)\n\n### Other changes\n\n- Tidy internals (#15)",
  "total_pull_requests": 3
}
```

Exit codes: `0` on success, `1` on a runtime error (including
an unreadable or invalid input file, or invalid input), `2`
on a usage error.

## MCP server

```bash
npx -y @reneturcios/changelogforge mcp
```

MCP client config:

```json
{
  "mcpServers": {
    "changelogforge": {
      "command": "npx",
      "args": ["-y", "@reneturcios/changelogforge", "mcp"]
    }
  }
}
```

### Tools

- `generate_changelog` — Render a release changelog section
  from merged pull requests, grouped by label.
  - `version` (string, required) — release version label,
    printed verbatim in the heading
  - `date` (string, required) — release date, printed
    verbatim in the heading
  - `pull_requests` (array, required, at least one) — merged
    pull requests as `{number, title, labels?}` objects;
    `number` is unique across the list
  - `group_order` (array of strings, optional) — labels that
    define groups, in output order
  - `heading_level` (integer, optional, 1–5) — Markdown
    heading level for the version heading

  Returns `{version, date, groups, markdown,
  total_pull_requests}`.

## Docker

```bash
docker run -i ghcr.io/cloudcorprecords/changelogforge
docker run --rm -v "$PWD:/w" ghcr.io/cloudcorprecords/changelogforge generate --input /w/args.json
```

## Development

```bash
npm install
npm run build   # tsc -> dist/
npm test        # tsx --test test/*.test.ts (pure local, no network)
npm run dev     # run the CLI from source
```

## License

MIT — Copyright (c) 2026 Rene Turcios