Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,37 @@ jobs:
- name: Validate CalVer tag and lineage
run: |
set -euo pipefail
[[ "${GITHUB_REF_NAME}" =~ ^v[0-9]{4}\.([1-9]|1[0-2])\.([0-9]|[1-9][0-9]*)$ ]] || {
echo "release tag must match v{YYYY}.{M}.{N}" >&2
tag_pattern='^v([0-9]{4})\.([1-9]|1[0-2])\.(0|[1-9][0-9]*)(-(alpha|beta|rc))?$'
[[ "${GITHUB_REF_NAME}" =~ ${tag_pattern} ]] || {
echo "release tag must match v{YYYY}.{M}.{N}[-alpha|-beta|-rc]" >&2
exit 1
}
release_year=$((10#${BASH_REMATCH[1]}))
release_month=${BASH_REMATCH[2]}
release_number=${BASH_REMATCH[3]}
git fetch origin main --tags
git merge-base --is-ancestor "${GITHUB_SHA}" origin/main || {
echo "release tag is not on main" >&2
exit 1
}
newest="$(git tag --list 'v*.*.*' --sort=-v:refname | head -1)"
[ "${newest}" = "${GITHUB_REF_NAME}" ] || {
echo "${GITHUB_REF_NAME} is not the newest release tag (${newest})" >&2
exit 1
}
tags="$(git tag --list 'v*.*.*')"
while IFS= read -r tag; do
[[ "${tag}" =~ ${tag_pattern} ]] || continue
year=$((10#${BASH_REMATCH[1]}))
month=${BASH_REMATCH[2]}
number=${BASH_REMATCH[3]}
if ((year == release_year && month == release_month && number == release_number)) &&
[ "${tag}" != "${GITHUB_REF_NAME}" ]; then
echo "${tag} shares the release number of ${GITHUB_REF_NAME}" >&2
exit 1
fi
if ((year > release_year ||
(year == release_year && month > release_month) ||
(year == release_year && month == release_month && number > release_number))); then
echo "${GITHUB_REF_NAME} is not the newest release tag (${tag})" >&2
exit 1
fi
done <<< "${tags}"
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
Expand Down Expand Up @@ -285,6 +302,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
# Maturity lives in the tag; keep this a full release so /releases/latest resolves.
gh release create "${GITHUB_REF_NAME}" \
--title "${GITHUB_REF_NAME}" \
--generate-notes \
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export FANOUT_AUTH_CODE_SECRET=$(openssl rand -hex 32)
fanout
```

Set `FANOUT_VERSION=v{YYYY.M}.{N}` to pin a release and `FANOUT_PREFIX` to choose the installation
Set `FANOUT_VERSION=v2026.10.1-alpha` to pin a release and `FANOUT_PREFIX` to choose the installation
directory. Native installs bind `127.0.0.1:7520`; set `FANOUT_ADDR=:7520` for remote access, then
follow the same first-boot setup.

Expand Down Expand Up @@ -205,16 +205,18 @@ generated assets, hooks, and project layout.

## Releases

Versions are CalVer — `v{YYYY.M}.{N}`, numbered from 0 within each month. Tagged releases publish
Versions are CalVer — `vYYYY.M.N[-alpha|-beta|-rc]`, numbered from 0 within each month across all
maturity suffixes. Fanout is currently alpha (for example, `v2026.10.1-alpha`); GA has no suffix.
Container tags omit the leading `v`, and every release moves `latest`. Tagged releases publish
identical manifests to Docker Hub (`labstack/fanout`) and GHCR (`ghcr.io/labstack/fanout`); GHCR is
canonical and also carries development images.

| Image tag | Points at |
| --- | --- |
| `labstack/fanout:latest` | the newest release, mirrored on Docker Hub |
| `labstack/fanout:2026.8.0` | that exact release, mirrored on Docker Hub |
| `labstack/fanout:2026.10.1-alpha` | that exact release, mirrored on Docker Hub |
| `ghcr.io/labstack/fanout:latest` | the newest release |
| `ghcr.io/labstack/fanout:2026.8.0` | that exact release |
| `ghcr.io/labstack/fanout:2026.10.1-alpha` | that exact release |
| `ghcr.io/labstack/fanout:main` | the tip of `main` |
| `ghcr.io/labstack/fanout:sha-<commit>` | one specific commit |

Expand Down
Binary file modified docs/images/system-overview-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/system-overview-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 11 additions & 6 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ Fanout publishes one release from a verified commit on `main`. A release contain

## Version contract

Tags use unpadded CalVer: `vYYYY.M.N`. The first release in a month is `.0`.
Container tags omit the leading `v`, so `v2026.8.0` publishes
`ghcr.io/labstack/fanout:2026.8.0` and `labstack/fanout:2026.8.0`.
Tags use unpadded CalVer: `vYYYY.M.N[-alpha|-beta|-rc]`. The suffix states product
maturity; GA has no suffix. The first release in a month is `.0`, and every
release increments `N` regardless of suffix. Fanout is currently alpha; after
`v2026.10.0`, the next release is `v2026.10.1-alpha`.
Container tags omit the leading `v`, so `v2026.10.1-alpha` publishes
`ghcr.io/labstack/fanout:2026.10.1-alpha` and `labstack/fanout:2026.10.1-alpha`.
Every release moves `latest`. GitHub Releases are not marked as prereleases:
the tag carries maturity, and the installer's `/releases/latest` must resolve.
Only release and `latest` tags are mirrored to Docker Hub; `main` and commit
tags remain GHCR-only.

Expand Down Expand Up @@ -60,15 +65,15 @@ also be verified directly:

```sh
sha256sum -c SHA256SUMS
gh attestation verify fanout_v2026.8.0_linux_amd64.tar.gz \
gh attestation verify fanout_v2026.10.1-alpha_linux_amd64.tar.gz \
--repo labstack/fanout
```

For containers, pin or record the digest returned by the registry:

```sh
docker buildx imagetools inspect ghcr.io/labstack/fanout:2026.8.0
docker buildx imagetools inspect docker.io/labstack/fanout:2026.8.0
docker buildx imagetools inspect ghcr.io/labstack/fanout:2026.10.1-alpha
docker buildx imagetools inspect docker.io/labstack/fanout:2026.10.1-alpha
```

## Supply-chain scope
Expand Down
2 changes: 1 addition & 1 deletion internal/mcp/apps/panels.html

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions internal/ui/dist/assets/chat._threadId-Baur0K0b.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import{t as e}from"./chat-DgzsRGm5.js";var t=e;export{t as component};
1 change: 0 additions & 1 deletion internal/ui/dist/assets/chat._threadId-CFa2fg-S.js

This file was deleted.

1 change: 1 addition & 0 deletions internal/ui/dist/assets/chat.index-Baur0K0b.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import{t as e}from"./chat-DgzsRGm5.js";var t=e;export{t as component};
1 change: 0 additions & 1 deletion internal/ui/dist/assets/chat.index-CFa2fg-S.js

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading