14 KiB
stamp — Workflow Guide
stamp is a language-agnostic, changesets-style versioning and changelog tool.
It works with any project type and supports monorepos.
Concepts
| Term | Meaning |
|---|---|
| Stamp file | A .stamp/*.md file describing a change and which projects it affects. Committed alongside the code change that caused it. |
| Bump type | How to increment a version: major, minor, patch, or a pre-release variant. |
| Pending stamps | Stamp files that have been committed but not yet consumed by a version run. |
stamp version |
Consumes pending stamp files → bumps versions in stamp.toml → prepends entries to CHANGELOG.md files → commits the result. |
stamp release-pr |
Same versioning logic as stamp version, but commits the changes onto a dedicated branch and opens (or updates) a pull request. The actual release happens when that PR is merged. |
stamp publish |
Creates git tags and publishes releases (with optional artifact uploads) to GitHub or Gitea. |
Two Release Workflows
Direct release
Run stamp version and stamp publish directly on the base branch. Good for small projects, CLIs, or repos where a human is doing releases manually.
feature branch ──► merge to main ──► stamp version ──► git push ──► stamp publish
Release PR (recommended for automation)
stamp release-pr runs in CI whenever a change is merged to the base branch. It opens a pull request that contains all the version bumps and changelog updates. Merging that PR is the explicit, reviewable release trigger. A second CI job runs stamp publish after the merge.
feature branch ──► merge to main ──► stamp release-pr ──► release PR
│
merge to main
│
stamp publish ──► tags + releases
The two CI jobs (create PR and publish) both run on every push to main. They are each no-ops when there is nothing for them to do — stamp release-pr exits silently if there are no pending stamp files, and stamp publish skips any tag that already exists.
Day-to-day: Adding a Stamp File
When making a code change that should result in a release, add a stamp file alongside it:
# Interactive wizard
stamp add
# Non-interactive — good for scripts and AI agents
stamp add --project=my-app --bump=minor --message="Add X feature" --no-interactive
This creates a file like .stamp/brave-river.md:
---
bumps:
my-app: minor
---
Add X feature
Commit and push the stamp file together with your code. Your CI PR-check job (see below) will update its comment automatically.
Bump type reference
| Type | What it does | Example |
|---|---|---|
major |
Breaking change | 1.2.3 → 2.0.0 |
minor |
New feature | 1.2.3 → 1.3.0 |
patch |
Bug fix | 1.2.3 → 1.2.4 |
premajor |
Pre-release major | 1.2.3 → 2.0.0-beta.0 |
preminor |
Pre-release minor | 1.2.3 → 1.3.0-beta.0 |
prepatch |
Pre-release patch | 1.2.3 → 1.2.4-beta.0 |
prerelease |
Increment pre-release counter | 1.2.4-rc.0 → 1.2.4-rc.1 |
Checking Pending Stamps
stamp status
📦 Pending stamps: 2
PROJECT CURRENT NEXT BUMP STAMPS
------- ------- ---- ---- ------
my-app 1.2.3 1.3.0 minor 2
my-lib 0.4.1 0.4.1 — 0
Workflow A: Direct Release
Use this when you release manually or from CI without a release PR.
# 1. Bump versions, update changelogs, and commit
stamp version
# 2. Push the version commit and tags
git push
# 3. Create GitHub / Gitea releases and upload artifacts
STAMP_REPO=owner/repo stamp publish
For a pre-release snapshot (does not require stamp preview):
stamp version --snapshot=rc
git push
stamp publish
--snapshot overrides the bump type for every affected project so that it produces a pre-release version with the given identifier. It is independent of stamp preview mode.
Skipping the git commit
If you want to inspect or further modify the files before committing:
stamp version --no-commit
# review the diff, make additional edits…
git add -A && git commit -m "chore: version packages"
Workflow B: Release PR
Use this for fully automated, reviewable releases in CI.
How it works — step by step
-
Check for pending stamps. If none exist,
stamp release-prexits immediately with no side effects. This makes it safe to run on every push. -
Fetch origin and reset the release branch (default:
stamp/release) from the tip oforigin/<base>. The branch is always recreated cleanly, so it is always fast-forwardable and never diverges from the base branch. -
Apply version changes — bump versions in
stamp.toml, prepend changelog entries, delete consumed stamp files. This is identical to whatstamp version --no-commitdoes. -
Commit and force-push the release branch to
origin. -
Upsert the pull request. A hidden marker (
<!-- stamp-release-pr -->) is embedded in the PR body. On the first run a new PR is opened; on subsequent runs the existing PR's title and body are updated to reflect any newly merged stamp files. Only one stamp release PR is ever open at a time.
The PR body contains a version table:
## 📦 Pending releases
| Project | Current | Next | Bump |
|---------|---------|-------|-------|
| my-app | 1.2.3 | 1.3.0 | minor |
| my-lib | 0.4.1 | 0.4.2 | patch |
- Merge the PR. Merging triggers the publish job (see below) which creates git tags and GitHub/Gitea releases.
CI setup — GitHub Actions
Job 1: open / update the release PR — runs on every push to main
# .github/workflows/stamp-release-pr.yml
name: release PR
on:
push:
branches: [main]
jobs:
release-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Full clone so stamp can fetch and reset the release branch.
fetch-depth: 0
- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Install stamp
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
- name: Create or update release PR
run: stamp release-pr --base=main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
STAMP_REPO: ${{ github.repository }}
Job 2: publish after the release PR is merged — also runs on every push to main
# .github/workflows/stamp-publish.yml
name: publish
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Install stamp
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
- name: Publish releases
run: stamp publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
STAMP_REPO: ${{ github.repository }}
Both jobs run on every push to
main. They are each idempotent and safe to run concurrently:stamp release-pris a no-op when there are no pending stamps;stamp publishskips tags that already exist.
CI setup — Gitea Actions
Job 1: open / update the release PR
# .gitea/workflows/stamp-release-pr.yml
name: release PR
on:
push:
branches: [main]
jobs:
release-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure git
run: |
git config user.name "stamp-bot"
git config user.email "stamp-bot@users.noreply.gitea.com"
- name: Install stamp
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
- name: Create or update release PR
run: stamp release-pr --base=main
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_BASE_URL: ${{ gitea.server_url }}
STAMP_REPO: ${{ gitea.repository }}
Job 2: publish after the release PR is merged
# .gitea/workflows/stamp-publish.yml
name: publish
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure git
run: |
git config user.name "stamp-bot"
git config user.email "stamp-bot@users.noreply.gitea.com"
- name: Install stamp
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
- name: Publish releases
run: stamp publish
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_BASE_URL: ${{ gitea.server_url }}
STAMP_REPO: ${{ gitea.repository }}
Note on
GITEA_TOKEN: Gitea Actions does not automatically inject a token the way GitHub Actions does. You must create a personal access token (or a bot account token) in your Gitea account settings with repository read/write permissions, then store it as a repository secret namedGITEA_TOKEN.
PR Commenting (stamp comment)
Use stamp comment in CI to post a summary comment on every pull request. It keeps reviewers and contributors informed about what will be released.
- No stamp file → the comment warns the author and shows how to add one.
- Stamps found → the comment shows a table of affected projects and their projected next versions.
The comment is created on first run and updated in place on subsequent runs (identified by a hidden marker in the body).
GitHub Actions
# .github/workflows/stamp-check.yml
name: stamp check
on:
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install stamp
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
- name: Comment on PR
run: stamp comment --pr=${{ github.event.pull_request.number }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
STAMP_REPO: ${{ github.repository }}
Gitea Actions
# .gitea/workflows/stamp-check.yml
name: stamp check
on:
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install stamp
run: go install git.thokra.dev/thokra/stamp/cmd/stamp@latest
- name: Comment on PR
run: stamp comment --pr=${{ gitea.event.pull_request.number }}
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_BASE_URL: ${{ gitea.server_url }}
STAMP_REPO: ${{ gitea.repository }}
Pre-release Mode (stamp preview)
stamp preview lets you put an individual project into pre-release mode. While in this mode, every stamp version or stamp release-pr run produces pre-release versions instead of normal ones, regardless of the bump types in the stamp files.
# Enter pre-release mode — all future versions for my-app will be pre-releases
stamp preview enter my-app beta
# → next stamp version will produce e.g. 1.3.0-beta.0
# If a pre-release version already exists, subsequent runs increment the counter
# → 1.3.0-beta.0 → 1.3.0-beta.1 → 1.3.0-beta.2 …
# Exit pre-release mode — the next stamp version will produce a normal release
stamp preview exit my-app
# → next stamp version will produce e.g. 1.3.0
stamp preview enter sets the pre_tag field on the project in stamp.toml and commits nothing — it is a local config change you commit yourself. stamp preview exit clears the field.
Typical pre-release workflow
# 1. Enter beta mode
stamp preview enter my-app beta
git add .stamp/stamp.toml && git commit -m "chore: enter beta mode for my-app"
# 2. Normal development — add stamp files as usual, merge PRs
# stamp release-pr will produce beta versions automatically
# 3. When ready to release, exit beta mode
stamp preview exit my-app
git add .stamp/stamp.toml && git commit -m "chore: exit beta mode for my-app"
# 4. The next release-pr or stamp version will produce the full release (e.g. 1.3.0)
Stamp File Format Reference
Stamp files live in .stamp/ alongside stamp.toml, and use Markdown with YAML or TOML frontmatter.
YAML frontmatter (default)
---
bumps:
my-app: minor
my-lib: patch
---
Short description used as the changelog entry.
- Optional bullet points
- for more detail
TOML frontmatter
+++
[bumps]
my-app = "minor"
+++
Short description.
A stamp file can affect multiple projects in a single file (as shown above). Each project gets its own changelog entry with the description from the file.
Configuration Reference
# .stamp/stamp.toml
[config]
base_branch = "main" # Base branch targeted by release PRs (default: main)
[[projects]]
name = "my-app"
path = "apps/my-app" # Relative to repository root
version = "1.2.3" # Current version — managed by stamp, do not edit manually
changelog = "CHANGELOG.md" # Relative to `path` (default: CHANGELOG.md)
pre_tag = "" # Set by `stamp preview enter`; blank means normal releases
[projects.publish]
tags = true # Create an annotated git tag on publish
releases = true # Create a GitHub / Gitea release on publish
artifacts = [ # Glob patterns for files to upload to the release
"apps/my-app/dist/my-app-linux-amd64",
"apps/my-app/dist/my-app-darwin-arm64",
]
Tag format: <name>@v<version> for monorepos (e.g. my-app@v1.3.0), or v<version> for single-project repositories where name is empty.
Environment Variables
| Variable | Purpose |
|---|---|
STAMP_REPO |
Repository slug owner/repo — required for publish, comment, and release-pr |
GITHUB_TOKEN |
GitHub token — automatically injected by GitHub Actions; no setup needed |
GITEA_TOKEN |
Gitea access token — must be created manually and stored as a secret |
GITEA_BASE_URL |
Gitea instance URL (e.g. https://gitea.example.com) — presence of this variable also activates Gitea mode |