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 now supports Elixir (Hex) packages alongside Rust (Crates.io) and JavaScript/TypeScript (npm).
If you’ve ever struggled with keeping changelogs updated, coordinating version bumps across dependent packages, or automating your Hex publishing process, this might interest you!
In a nutshell
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!




















