GoulvenClech
Sampo - automate changelogs, versioning, and publishing for Elixir (and multi-ecosystem monorepos)
Hey everyone ![]()
I’m excited to share Sampo, a tool suite to automate changelogs, versioning, and publishing—even for monorepos across multiple package registries. It currently Elixir (Hex) packages, alongside Rust (Crates), JavaScript/TypeScript (npm), Python (PyPI), PHP (Packagist)… And more coming soon!
In a nutshell
Sampo is a CLI, a GitHub App, and a GitHub Action, that automatically detects packages in your repository, and uses changesets (markdown files describing changes explicitly) to bump versions (in SemVer format), generate changelogs (human-readable files listing changes), and publish packages (to their respective registries). It’s designed to be easy to opt-in and opt-out, with minimal configuration required, sensible defaults, and no assumptions/constraints on your workflow (except using SemVer).
If you’ve ever struggled with keeping user-facing changelogs updated, coordinating version bumps across dependent packages, or automating your publishing process… Sampo might be the tool you were looking for!
In more details
Sampo is a CLI tool (for now only available on Cargo, but soon on your favorite OS package manager), a Github Action, and a GitHub App that work together to streamline your release process.
Sampo automatically discovers Elixir (and Rust/Javascript/Typescript) packages in your workspace (including umbrella projects), respects your mix.exs configuration, and calls mix hex.publish under the hood (you still need to have your HEX_API_KEY environment variable or Mix’s auth configured).
Like Hex.pm, Sampo enforces Semantic Versioning (SemVer) to indicate the nature of changes in each release. Versions follow the MAJOR.MINOR.PATCH format with three bump levels: patch — Bug fixes and backwards-compatible changes; minor — New features that are backwards-compatible: major — Breaking changes that are not backwards-compatible.
For example, a user can safely update from version 1.2.3 to 1.2.4 (patch) or 1.3.0 (minor), but should review changes before updating to 2.0.0 (major). Sampo also supports pre-release versions (e.g., 1.2.0-rc.1) as SemVer §9 conventions.
For each change made to your packages, you can use sampo add to create a new changeset file, the CLI will prompt you to select which packages were affected, the type of version bump (patch/minor/major), and a description of the change. You can use Sampo GitHub bot to get reminders on each PR without a changeset.
---
hex/back-end: minor
npm/web-app: patch
---
A helpful description of the change, to be read by your users.
Those changesets are markdown file, inspired by Changesets and Lerna, stored in the .sampo/changesets/ directory. Sampo consumes those changesets to determine version bumps, and update changelogs—a human-readable file listing all changes for each released version, at the root of every package.
# Example
## 0.2.0 — 2024-06-20
### Minor changes
- [abcdefg](link/to/commit) A helpful description of the changes. — Thanks @user!
## 0.1.1 — 2024-05-12
### Patch changes
- [hijklmn](link/to/commit) A brief description of the fix. — Thanks @first-time-contributor for their first contribution!
... previous entries ...
Run sampo release to process all pending changesets, bump package versions, and update changelogs. This can be automated in CI/CD pipelines using Sampo GitHub Action, with a release PR created whenever changesets are detected. As long as the release is not finalized, you can continue to add changesets and re-run the sampo release command. Sampo will update package versions and pending changelogs accordingly.
Finally, run sampo publish to publish updated packages to their respective registries and tag the current versions. This step can also be automated in CI/CD pipelines using Sampo GitHub Action, by merging the release PR, and can also create GitHub Releases and Discussions for each new tag.
Philosophy
Sampo is designed to be an helpful, reliable, and flexible tool that users can trust.
We want to make it easy to get started, with minimal configuration, sensible defaults, and automated workflows. At the same time, we want to provide rich configuration options, and flexible workflows to cover more advanced use cases. Finally, Sampo should be easy to opt in and opt out, with little to none assumptions, conventions to follow, or lock-ins.
It’s fully open-source, and we welcome contributions and feedback from the community! If you give it a try, please let us know what you think, and if we can do anything to improve the Elixir support ![]()
And leave a star on GitHub if you find it useful!
Most Liked
GoulvenClech
GoulvenClech
Hi @dimitarvp ,
Sorry for the slow reply, my weeks have been pretty packed lately and I’m only now catching up properly.
Thanks again for taking the time to check out Sampo. Just to clarify a couple of things :
Sampo never decides the bump level on its own: you explicitly declare the bump (patch, minor, or major), the packages affected, and the user-facing description of the change, either via the CLI or by editing the changeset file by hand. Sampo then just does the deterministic SemVer math from there. There’s no hidden logic trying to guess what the next version “should” be.
Sampo also doesn’t depend on Conventional Commits at all. One of the design goals was precisely to avoid mixing the technical history in git (written for and by contributors) with the API changelog (written for users, and sometimes reviewed/edited by product/docs owners). Changesets are the single source of truth, and the changelog and versions are generated from those.
It’s also meant to be modular. You can use it only to bump versions, generate changelogs, create git tags and GitHub releases, without letting it publish to registries. Similarly, you can stick to the CLI locally, and ignore both the GitHub App and the GitHub Action. The intent is that Sampo should be easy to opt in and out of, with as few assumptions, conventions, or lock-ins as possible. If there are still rough edges or sources of friction that made it feel “too heavy” in practice, I’m genuinely interested in hearing about them so I can keep smoothing things out ![]()
dimitarvp
Oh, just for the record for you or anyone else, here’s the bash abomination that me and Gemini worked on for about an hour in order to cover most failure modes and use proper native tools and not just use brittle CLI text manipulation: xqlite/scripts/release.sh at 5fd91f15c748f18bf5a0a91ebe39df252ef9f5ed · dimitarvp/xqlite · GitHub
Monstrosity. Just to bump a version in two files and do a little GIT magic.
It’s almost 2026. All this stuff should have been figured out and written in stone 10 years ago. Shameful. But maybe when I retire I’ll have the time.
Last Post!
a-maze-d
@GoulvenClech, sorry for the delay to answer.
Use cases I see missing are those where you have markdown/text files, like the README.md where you give instructions how to install your library. The default mix new my_app will create such instruction and therefore it’s common to see it in Elixir libraries (and I do like it because you can easily copy&paste it)
There are other use cases like livebook examples, or installation instructions in docs.
As the last example illustrates, it can even be within a link
For docs you can maybe get away with using a handcrafted mix job that you can run before the docs are created, but it would be neater if Sampo would support it
I hope that makes sense
Popular in Announcing
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









