Changelog plugins
molt resolves its changelog generator through a Python entry point, so third parties can publish and ship a generator without molt ever knowing it exists.
Every line molt writes into a CHANGELOG.md comes from a changelog generator: a small, named piece of code that turns one changeset (and the releases it caused) into Markdown. molt ships two -- git and github -- and treats them exactly like a plugin you wrote yourself. This page explains the plugin seam, the contract a generator implements, and how to point your config at one. To build one end to end, see Custom generators.
Why entry points
changesets names its generator with an npm module path:
molt does the idiomatic Python equivalent -- a importlib.metadata entry point in the molt.changelog group. A generator package declares itself:
Once that package is installed, emoji is a name molt can resolve -- with no code change and no import path baked into your config. This is the same mechanism pytest, Sphinx, and console_scripts use, and it satisfies molt's rule that configuration must be readable without executing user code: your config names a plugin, it does not point at a file that gets run just to parse settings. Executable config and arbitrary shell hooks are deliberately refused (see Why molt and Design decisions); a typed, named plugin is the sanctioned extension point instead.
molt's own git and github generators are registered exactly this way, so there is no privileged built-in path -- a plugin you publish is a first-class peer of the defaults.
The contract
A generator implements two functions -- the direct descendants of changesets' getReleaseLine and getDependencyReleaseLine. One renders a line for this package changed; the other renders a line for a dependency of this package changed.
Both functions may be sync or async -- molt inspects each at call time, so a generator that needs the network (resolving commit authors, PR numbers) can be async def while the plain git generator stays synchronous.
Key points:
- You return lines, not layout. A function returns the text for one bullet. molt owns the surrounding structure -- the
## <version>heading, the### Major/Minor/Patch Changessections, ordering, and blank-line spacing. That structural layer is a separate, Jinja2-templated concern; see Changelog templates. - Forge info is injected, not imported. When the active forge is GitHub, molt passes a
Forgeadapter as theforgeargument, so the generator resolves commit -> author and PR links through molt's cached, rate-limited client instead of opening its own. A generator that does not need a forge simply ignores the argument;forgeisNonewhen no forge is configured. See GitHub for what the adapter exposes. - Options pass through verbatim. Whatever you put in the config options table arrives as the
optionsdict, untouched. A generator validates its own options (and may declare a typed options model so molt can check them at startup rather than mid-release). - Errors abort before any write. If a generator raises, molt fails the whole
versionrun before touching a single file -- consistent with its atomic, buffer-then-flush discipline. You never get a half-written changelog.
Unlike changesets -- whose changelog plugins only ever see the two callback arguments -- molt also exposes the surrounding release plan to a generator that wants it, closing a gap changesets flagged as future work in 2020 and never shipped.
Choosing a generator
The generator is selected by the changelog option in [tool.molt]. It accepts the same three shapes changesets uses, in TOML:
molt resolves the changelog name in three ways, in order -- mirroring changesets' "installed package or local path" duality:
- Entry point -- a name in the
molt.changeloggroup (git,github, or any installed plugin). The normal case. - Dotted path --
my_pkg.changelog:generator, for an in-repo generator onsys.pathyou have not packaged. - File path --
./changelog.py, resolved relative to the.changeset/directory first, then the project root, for a one-off script.
Full option details live in the Options reference.
The default generators
molt ships two, both registered as entry points:
The git generator works with no configuration and no network, which is why it is the default. github adds the links most public projects want; point changelog at it and give it a repo (or let it read GITHUB_REPOSITORY in CI).
Where to go next
- Custom generators -- write, register, and configure your own generator, with a worked Jinja2 example.
- Changelog templates -- customize the structure of an entry (headings, dates, sections) without writing a plugin.
- GitHub -- what the injected forge adapter provides.
- Options reference -- the full
changelogoption.