Use this runbook whenever you need to prove that the public installer is actually pulling the current latest stable Flow release.
The fastest repo-local check is now:
./scripts/verify-install-latest-release.shOr through Flow:
f verify-install-latest-releaseThis is the check that matters for users:
curl -fsSL https://myflow.sh/install.sh | shAfter a stable release, these values must all agree:
Cargo.tomlpackage version- pushed release tag
vX.Y.Z - GitHub
releases/latesttag - version reported by a fresh temp-home install of
~/.flow/bin/f
If any one of those differs, the public install story is broken.
The script performs all of these checks:
- validate expected tag vs
Cargo.tomlviascripts/check_release_tag_version.py - poll GitHub
releases/latestuntil it matches the expected tag - run the real public installer in a fresh temp
HOME - verify the installed binary version
- download the direct release asset for the current platform and verify that too
Default usage:
./scripts/verify-install-latest-release.shUseful options:
./scripts/verify-install-latest-release.sh --latest-timeout 300
./scripts/verify-install-latest-release.sh --tag v0.1.3
./scripts/verify-install-latest-release.sh --skip-asset
./scripts/verify-install-latest-release.sh --keep-tempRun this after:
- cutting a new stable release tag
- changing
install.sh - changing release packaging
- changing versioning logic
- fixing a release mismatch bug
The installer is correct only if all of these are true:
- the release tag matches
Cargo.toml - GitHub marks that tag as latest stable
- a fresh temp-home install gets that same version
- a direct release asset download reports that same version
If the one-command script fails, use the manual steps below to see exactly where the mismatch is.
Read the package version from the repo:
python3 - <<'PY'
import pathlib, re
text = pathlib.Path("Cargo.toml").read_text(encoding="utf-8")
match = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE)
if not match:
raise SystemExit("failed to read Cargo.toml version")
print(match.group(1))
PYIf you already know the expected tag, validate it directly:
python3 scripts/check_release_tag_version.py v0.1.3That script should fail hard on mismatches.
Check the public API that the installer uses:
curl -fsSL https://api.github.com/repos/nikivdev/flow/releases/latest \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["tag_name"])'This should print the expected stable tag, for example:
v0.1.3
Optional cross-checks:
gh release list --limit 5
gh release view v0.1.3 --json tagName,publishedAt,isDraft,isPrerelease,urlThis is the main test. Use a fresh HOME and a minimal PATH so an existing install cannot leak in.
tmp_home="$(mktemp -d)"
echo "$tmp_home"
HOME="$tmp_home" PATH="/usr/bin:/bin:/usr/sbin:/sbin" sh -c \
'curl -fsSL https://myflow.sh/install.sh | sh'
HOME="$tmp_home" "$tmp_home/.flow/bin/f" --versionExpected result:
- install succeeds
~/.flow/bin/fexists under the temp homef --versionreports the latest stable version
Example expected output:
flow 0.1.3
Use this one-shot comparison:
latest_tag="$(curl -fsSL https://api.github.com/repos/nikivdev/flow/releases/latest \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["tag_name"])')"
tmp_home="$(mktemp -d)"
HOME="$tmp_home" PATH="/usr/bin:/bin:/usr/sbin:/sbin" sh -c \
'curl -fsSL https://myflow.sh/install.sh | sh >/dev/null'
installed_version="$(HOME="$tmp_home" "$tmp_home/.flow/bin/f" --version \
| python3 -c 'import sys,re; m=re.search(r"flow ([0-9][^ ]*)", sys.stdin.read()); print(m.group(1) if m else "")')"
echo "latest_tag=$latest_tag"
echo "installed_version=$installed_version"
test "v$installed_version" = "$latest_tag"If that final test fails, the installer path is not trustworthy.
If the fresh install reports the wrong version, download the release asset directly.
Choose the target for your machine:
- macOS Apple Silicon:
aarch64-apple-darwin - macOS Intel:
x86_64-apple-darwin - Linux x64:
x86_64-unknown-linux-gnu - Linux arm64:
aarch64-unknown-linux-gnu
Example for macOS Apple Silicon:
latest_tag="$(curl -fsSL https://api.github.com/repos/nikivdev/flow/releases/latest \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["tag_name"])')"
tmp_dir="$(mktemp -d)"
cd "$tmp_dir"
curl -fsSLO \
"https://github.com/nikivdev/flow/releases/download/${latest_tag}/flow-aarch64-apple-darwin.tar.gz"
tar -xzf flow-aarch64-apple-darwin.tar.gz
./f --versionInterpretation:
- direct asset wrong too: release artifact/versioning bug
- direct asset correct but installer wrong: installer selection logic bug
- API still shows old tag: release publication/propagation is not complete yet
Symptom:
python3 scripts/check_release_tag_version.py vX.Y.Zfails
Meaning:
- the release was tagged from the wrong crate version
Fix:
- bump
Cargo.toml - refresh generated artifacts if needed
- cut a new release tag
Symptom:
- release workflow is green
- release page shows the new version
releases/lateststill returns the old tag for a short time
Meaning:
- GitHub publication or cache propagation delay
Fix:
- wait and retry until
releases/latestflips - do not declare success until the API itself returns the new tag
Symptom:
releases/latestreturns the new tag- temp-home install still reports an older version
Meaning:
- likely wrong binary inside the published release asset
Fix:
- test the direct asset
- if direct asset is also wrong, cut a corrected release
Symptom:
- your test is clean
- user machine still reports an older version by plain
f --version
Meaning:
- user shell is resolving another binary earlier on
PATH
Fix:
- ask them to run:
which -a f
~/.flow/bin/f --versionAfter publishing a stable tag:
- run
python3 scripts/check_release_tag_version.py vX.Y.Z - wait for the Release workflow to complete
- verify
releases/latestreturnsvX.Y.Z - run
./scripts/verify-install-latest-release.sh - if there is any mismatch, test the direct asset before debugging the installer
Do not mark the release done until step 4 is green.