Repository navigation
Release Checklist
Marmot is released by pushing a vX.Y.Z tag. The tag triggers release.yml,
which:
- checks that the tag matches
versioninpackage.json; - builds
docker/Dockerfileforlinux/amd64andlinux/arm64, each on a native runner (ubuntu-24.04/ubuntu-24.04-arm), and pushes the multi-arch image to GHCR with OCI labels and annotations (docker/metadata-action):- final release
v0.1.0→ghcr.io/thinkhumandotdev/marmot:0.1.0,:0.1and:latest; - prerelease
v0.2.0-rc.1→ only:0.2.0-rc.1(no:0.2, no:latest);
- final release
- smoke-tests the published image: checks the multi-arch manifest, pulls it through
docker/docker-compose.yml(+docker-compose.smoke.ymlfor ports) and runsscripts/smoke-test.sh– the same checks as the CI compose job (health endpoints through Caddy, socket.io handshake, security headers, worker boot, container healthchecks, a singleMARMOT_ROLE=allcontainer with a clean shutdown); - publishes the Helm chart (
charts/marmot) tooci://ghcr.io/thinkhumandotdev/charts/marmotwith the release version (see Kubernetes); - creates the GitHub Release with notes generated by git-cliff from
cliff.toml, marked as a prerelease for-rc/-betatags and for every0.xversion (Marmot is pre-release until v1.0). The image tags above don't change for0.x: a final0.xrelease still gets:X.Yand:latest.
Nothing is tagged or pushed automatically from a developer machine; the steps below are manual.
-
mainis green in CI (Postgres and MongoDB, Docker image & compose smoke). -
Milestone issues for the version are closed or moved.
-
Migrations: the Postgres chain in
src/migrations/postgresapplies cleanly to an empty database (NODE_ENV=production pnpm migrate) and to a database at the previous release (upgrade path). No migration file was edited by hand. -
pnpm generate:typesproduces no diff. -
Dependencies:
pnpm audithas no unaddressed high/critical findings; Dependabot PRs are merged or consciously deferred. -
Configuration docs: every key in
src/env.tsis in.env.exampleand Configuration (tests/int/docs.int.spec.tsenforces it); new instance settings are documented. -
Documentation: pages marked (landing in the current release) in
docs/describe features that actually merged; remove the markers (and the page fromLANDING_PAGESintests/int/docs.int.spec.ts) or move the feature to planned in Comparison. -
THIRD_PARTY_NOTICES.mdlists every file ported from Uptime Kuma or kan.bn. -
Manual smoke test of the release candidate image (
docker build -f docker/Dockerfile -t marmot:rc .):- fresh compose stack with Postgres: setup wizard, HTTP monitor with live heartbeats, a test notification, a published status page opened anonymously, an accepted invitation;
- the same with
docker-compose.mongo.yml; - upgrade path: start the previous release, add data, swap the image tag,
docker compose up -d; history is intact and the worker reconnects; - backup and restore according to Deployment;
- OIDC login against a test provider when the release touched
src/auth/.
-
Choose the version (SemVer; while
0.x, breaking changes bump the minor). -
On an up-to-date
main:git switch main && git pull --ff-only pnpm release:prepare 0.1.0scripts/release.shsetspackage.jsonversion, the default image tag (${MARMOT_VERSION:-0.1.0}) indocker/docker-compose.yml, the image tag of the Railway template images (deploy/railway/*/Dockerfile), the Helm chartversionandappVersion(charts/marmot/Chart.yaml), rebuilds the GitHub Action bundle (action/dist) and regeneratesCHANGELOG.mdwithpnpm dlx git-cliff@2(setGIT_CLIFFto use another binary). It prints the next commands and does not commit, tag or push. -
Review
CHANGELOG.md. Commit messages are the source: fix wording by editingcliff.toml(grouping, skips) rather than the generated file, or accept small hand edits for this release only. Call out breaking changes and required manual steps (new required env vars, migrations that take long).
-
Commit on a branch and open a PR titled
chore(release): vX.Y.Z(this exact form is skipped by the changelog):git switch -c chore/release-0.1.0 git add package.json docker/docker-compose.yml charts/marmot/Chart.yaml deploy/railway action/dist CHANGELOG.md git commit -m "chore(release): v0.1.0" git push -u origin chore/release-0.1.0 -
Wait for CI, squash-merge.
-
Tag the merge commit on
mainand push the tag:git switch main && git pull --ff-only git tag -a v0.1.0 -m "v0.1.0" git push origin v0.1.0
-
Watch the Release workflow (Actions tab):
prepare→build(one job per platform) →image→smoke→chart→release. Ifsmokefails, the image is already on GHCR but no GitHub Release is created; fix forward with a patch version rather than moving the tag. -
If the run failed because of the workflow itself (not the code being released), fix the workflow on
mainand re-run the release without moving the tag: Actions → Release → Run workflow onmainwith the tag (v0.1.0). It builds and releases the tagged commit withmain's workflow.
-
First release only: in GHCR (Packages → marmot → Package settings) set the visibility to Public and link the package to the repository, otherwise
docker pullrequires a login. Do the same for the charts/marmot package (the Helm chart). -
Clean
docker compose upsmoke on a machine (or VM) without a checkout or cached images (while the repository is private, copydocker/docker-compose.yml,docker/Caddyfileanddocker/.env.examplefrom the tag instead of using the raw URLs):mkdir marmot-smoke && cd marmot-smoke base=https://raw.githubusercontent.com/ThinkHumanDotDev/marmot/v0.1.0/docker curl -fsSL -O "$base/docker-compose.yml" -O "$base/Caddyfile" curl -fsSL "$base/.env.example" -o .env sed -i "s/^PAYLOAD_SECRET=.*/PAYLOAD_SECRET=$(openssl rand -hex 32)/" .env docker image rm ghcr.io/thinkhumandotdev/marmot:0.1.0 2>/dev/null || true docker compose pull docker compose up -d --wait curl -fsS http://localhost/api/health # {"ok":true,...} curl -fsS 'http://localhost/socket.io/?EIO=4&transport=polling' # contains "sid" docker compose logs worker | grep 'worker booted' docker compose ps # web, realtime healthy
Open
http://localhost, complete the first-run setup, create an HTTP monitor and see heartbeats arrive live. Then clean up withdocker compose down -v. -
On an arm64 host (Apple Silicon, Raspberry Pi, Graviton) repeat at least
docker compose up -d --waitand the health check; CI only runs the published image on amd64. -
docker buildx imagetools inspect ghcr.io/thinkhumandotdev/marmot:0.1.0listslinux/amd64andlinux/arm64;:latestand:0.1point at the same digest (final releases only).
The GitHub Action is versioned with the repository: the release tag is its version
(uses: thinkhumandotdev/marmot/action@vX.Y.Z), so there is nothing to publish separately.
- The GitHub Action workflow is green on the release commit: the committed bundle
(
action/dist/index.mjs) matches its sources and the action passes against the mocked API. - In a scratch repository, a workflow with
uses: thinkhumandotdev/marmot/action@vX.Y.Z(mode: runagainst a test instance) passes for an up monitor and fails for a down one;mode: applyon apull_requestshows the plan in the job summary. - While Marmot is
0.x, do not create moving major tags (v0); from v1.0 on, movev1to eachv1.Y.Zrelease so@v1users get fixes. - GitHub Marketplace listing: only actions whose
action.ymlis at the root of a public repository can be listed, so a listing needs a dedicatedthinkhumandotdev/marmot-actionrepository that mirrorsaction/per release (not set up yet).
- Review the generated GitHub Release notes; add upgrade notes or highlights at the top if needed.
- Update deployment docs if the upgrade needs manual steps.
This wiki is published from docs/ on every push to main; edits made in the wiki are overwritten.
Found a mistake? Open a pull request with the docs(docs): … prefix.
Run it
- Getting started
- Configuration
- Deployment
- Kubernetes
- Single sign-on
- Security
- Telemetry
- Billing
- Demo mode
Use it
- Monitors
- Monitor types
- Probe locations
- Notifications
- Status pages
- Maintenance
- Organizations and members
- Integrations
- MCP server for AI agents
- Import and export
- CLI and monitors as code
- GitHub Action
Change it