Changelog and Versioning

@katforge/imp treats the changelog and the version as things it keeps correct for you, not paperwork you maintain by hand. This page is the reference for what it does, so you can trust the output without re-reading the diff.

The git tag is the version

The canonical version of a repo is its highest semver tag. Everything else — the CHANGELOG.md heading, the version fields in package manifests — is a copy @katforge/imp rewrites to match the tag, so the two can never drift.

shell
imp version          # show each manifest against the tag (exit 1 on drift)
imp version --sync    # rewrite drifted manifests to match the tag

The plain form exits non-zero on drift, so it gates CI. --sync leaves the change uncommitted for the next commit or release to carry.

One entry engine, two speeds

Every changelog entry comes from one generator, run at one of two speeds:

  • Diff-aware (default for humans). It reads the actual per-version diffs and asks the model to describe them from a user's perspective, sorting each change into Added, Changed, Fixed, or Removed.
  • Deterministic (--fast, and non-interactive runs). It reads the commit subjects and maps each Conventional Commit type to a category. The same commits always produce the same entry, and nothing waits on a model.
Commit typeDeterministic category
feat:### Added
fix:### Fixed
anything else### Changed

The diff-aware path adds a ### Removed category the deterministic path does not produce. Either way, the commit types in changelog:skipchore, release, merge by default — are dropped so release and merge noise never reaches an entry.

Which speed runs where:

CommandSpeed
imp release (interactive)diff-aware
imp release --yes, imp ship, imp tagdeterministic (cheap, CI-safe)
imp changelogdiff-aware
imp changelog --fastdeterministic

Non-interactive releases stay on the deterministic entry on purpose: a CI or agent release is reproducible and never blocks on a model. Interactive releases get the richer diff-aware entry, and you review it before it lands.

Writing the file with imp changelog

imp changelog maintains CHANGELOG.md directly, without cutting a release.

shell
imp changelog                  # top up [Unreleased] from commits since the last tag
imp changelog --fast            # same, deterministic entry
imp changelog --rebuild         # regenerate the whole file from history
imp changelog --rebuild --apply # also create or move the git tags it infers
imp changelog --since 2026      # limit the range to a date, tag, or commit

By default it is incremental: it generates an entry for the commits since the last tag and updates the [Unreleased] section in place, leaving released history and any hand edits alone. Running it twice never stacks a second [Unreleased] heading.

--rebuild regenerates the entire file from git history. It maps existing tags to version boundaries and, where a stretch of commits has no tags, infers where the releases should fall from the subjects. --rebuild --apply also creates or moves the git tags it inferred. Untagged trailing commits collect under [Unreleased].

Both paths write Keep-a-Changelog format from one shared header:

text
# Changelog

All notable changes to this project will be documented in this file.

## [1.2.0] - 2026-07-17
...

Manifests move with the tag

At release, @katforge/imp rewrites the version field in the package files it recognizes so a publish ships the released version, not a stale one. It handles package.json, composer.json, pyproject.toml, and cli/pyproject.toml; manifests with a dynamic (VCS-derived) version are left alone. A project can name its manifests explicitly in .imp instead of relying on detection.

Pre-release versions are translated to each ecosystem's native spelling — see Package manifests for the full table.

Release rolls back on failure

A release touches several things in sequence: the changelog, the manifests, a squash, a tag, a push. If any step fails, @katforge/imp restores what it changed rather than leaving a half-cut release:

  • The new tag is deleted.
  • HEAD hard-resets to the pre-release commit, if the release commit was made.
  • CHANGELOG.md is restored to its exact prior content, or removed if it did not exist before.
  • Every rewritten manifest is restored from its captured original.

The one case @katforge/imp does not unwind is a push that landed the commits but failed to push the tag: the work is already public, so @katforge/imp leaves it and tells you the exact command to finish the tag push. Nothing is silently half-done.

Keeping it honest

The categories, the reproducible deterministic entry, and the version-manifest lockstep are what make the changelog reviewable at a glance. The same engine that reads a diff for the changelog also keeps the prose documentation as honest — that is Documentation sync.