Release Process¶
Agent Factory ships on two channels (#1041):
| Channel | Version shape | Cut by | GitHub release |
|---|---|---|---|
| Stable | 1.x.y (e.g. 1.1.0) |
Maintainer, manually | Normal release, marked latest |
| Preview | 1.x.y-preview-z (e.g. 1.1.1-preview-3) |
CI, automatically every 3 hours | Prerelease, never marked latest |
Version scheme¶
Previews are based on the next patch after the latest stable: if the
latest stable is 1.1.0, previews are 1.1.1-preview-1, 1.1.1-preview-2,
… — each cut from the current master HEAD. Because a prerelease sorts
below its own release in semver, this keeps ordering standard across both
channels:
z increments on every preview and resets to 1 whenever a new stable
changes the base. Version computation lives in
.github/scripts/next-preview-version.sh
and is unit-tested in scripts/release_scripts_test.go.
Preview releases (automatic)¶
The auto-release.yml workflow runs
every 3 hours (and on manual dispatch). When master has new commits since
the last tag, it runs the release preflight (gofmt, vet, race tests, build),
tags v1.x.y-preview-z, builds the four platform tarballs with the version
stamped via -ldflags "-X main.version=...", and publishes a GitHub
prerelease.
Previews never commit to master — the old per-release
"chore: bump version" commits are gone. The version var in main.go is
only the dev-build fallback and holds the latest stable base.
Stable releases (manual)¶
To cut a stable release, run the Stable Release workflow
(stable-release.yml) from the
Actions tab (workflow_dispatch) and enter the version with no leading v,
e.g. 1.1.0. The maintainer chooses which digit to bump; the workflow
validates the version (well-formed, untagged, strictly greater than the
latest stable — see
.github/scripts/validate-stable-version.sh),
runs the same preflight, and builds all four artifacts before mutating
anything; only then does it commit the version bump to main.go, tag,
and publish the release marked latest. A failed preflight or build
therefore never leaves a dangling commit or tag on master.
Releasing the current preview base as-is (e.g. 1.0.138 while
1.0.138-preview-9 exists) is supported — it "promotes" what the preview
channel has been testing, and subsequent previews move to 1.0.139-preview-1.
How updates flow to users¶
- Auto-update follows the stable channel by default. On launch
(throttled to once every 6h),
afresolves the newest release on the configured channel and swaps the binary in place. With the defaultupdate_channel: "stable"it asks GitHub'sreleases/latestendpoint, which is pinned to the newest non-prerelease release — previews never appear there, and there is no release list to page through. - A running daemon checks too, and reports rather than installs. An
autostart daemon serving the web UI and firing tasks may go weeks without
an interactive launch, so it runs the same channel-aware check itself. It
shares the one 6-hour window with the launch path — it stands down when an
interactive
afhas just checked, and never closes the window on its own, so anaflaunch always finds the window it would have found anyway. When it finds a newer release it logs it; it does not swap the binary. Settingauto_update = false(orAGENT_FACTORY_AUTO_UPDATE=0in the daemon's environment) stops the daemon check entirely. - A daemon can be opted in to installing what it finds, with
AGENT_FACTORY_DAEMON_UPGRADE=1in its environment. That routes the upgrade through the transactional path rather than an in-place swap: the previous binary is preserved, the new one starts in probation, and it is rolled back automatically unless it reaches a version-matched, fully ready state. It is off by default while the end-to-end forward-then-rollback integration is still being built, andauto_update = falseoverrides it either way. - Preview tracking is opt-in via the global config key
update_channel: "preview"(see configuration.md) — the updater then lists releases and picks the version-newest tag including1.x.y-preview-zprereleases, which are normally the newest. Prereleases are invisible to thereleases/latestAPI/redirect, so the updater addresses release assets by tag. af upgraderesolves through the same configured channel and compares the channel's newest release against the running binary before installing, so a manual upgrade never downgrades. If the resolved release is older than the current build — which happens when you flipupdate_channelfrompreviewback tostablewhile the newest stable is behind the preview you're on — the command is a no-op and prints, e.g.,af upgrade would downgrade 1.0.141-preview-2 -> 1.0.140 (stable channel). Re-run with --allow-downgrade to proceed.Passing--allow-downgradeinstalls the older release anyway (and prints aDowngrading X -> Ynotice); when you're already on the channel's newest release it reportsAlready on the latest <channel> release (<version>).install.shand fresh installs use thereleases/latest/download/...redirect, which GitHub pins to the newest stable — new users start (and by default stay) on stable. A specific version (stable or preview) can be pinned withinstall.sh --version <tag>.