Releasing
Releasing
How a version of fictty goes out. The first was v0.1.0, on 11 October 2026. The ship skill
(.claude/skills/ship/SKILL.md) is the whole end-of-session routine; this is the release part.
The rule for now: CI is a signal, not a gate
We’re moving fast. Tag, push, freeze the demo and publish without waiting for CI. The release workflow runs in the background; check it later, and fix what it finds in the next commit. Turn it into a gate when the project slows down and more people depend on releases.
Until a tag’s binaries arrive (a few minutes), the one-liners build from source, so a reader with Rust is fine and one without it waits. That’s the trade we accept.
Cutting a release
-
Pick the version. While it’s 0.x: a minor bump (
0.2.0) for a session that changes the format or adds features, a patch (0.1.1) for fixes. SetversioninCargo.toml, runcargo buildsoCargo.lockfollows, and commit. -
Tag and push, with what’s in it and the line to try it:
git tag -a v0.2.0 -m "fictty 0.2.0: <what's new, in a line> Try it: curl -fsSL https://fictty.com/try.sh | sh -s -- v0.2.0" git push origin v0.2.0Ask Aram before the first tag of a session: a tag is a public release.
-
Carry on: freeze the post’s demo on the tag (
scripts/freeze-demo.sh <slug> v0.2.0 "<title>"), write the post, deploy. Don’t wait for step 4. -
Later, look at the run (
gh run list --workflow release.yml). If a job failed, fix the workflow or the code, push, and rebuild that tag’s binaries by hand:gh workflow run release.yml -f tag=v0.2.0That rebuilds every target and replaces the release’s files; it never moves the tag.
What the workflow builds
.github/workflows/release.yml, on any v* tag: fictty-<target>.tar.gz (the binary alone)
for aarch64-apple-darwin, x86_64-apple-darwin, x86_64-unknown-linux-gnu and
aarch64-unknown-linux-gnu, attached to the GitHub release (created if it doesn’t exist).
- Intel Macs are cross-built on Apple silicon (
macos-14): GitHub’s Intel Mac runners (macos-13) never start any more. A job stuck in “queued” for minutes means a runner that’s gone; change the matrix rather than waiting. - Linux binaries are built on Ubuntu 22.04, so they need glibc 2.35 or newer.
- Builds use
--locked: a tag whoseCargo.lockis stale fails. Build before tagging.
How readers get it
curl -fsSL https://fictty.com/try.sh | shrunsmainwhen cargo is there, and the newest release when it isn’t (releases/latest), with that release’s binary.… | sh -s -- v0.2.0runs that release; a post’s frozen demo (web/public/try/<post>.sh) usually pins one. Release tags download the binary; commits and branches build from source.- A tag is fetched as it is on GitHub. Never move or delete a pushed tag: frozen demos and readers depend on it. A broken release gets a new patch version instead.
Checks after a release
gh release view v0.2.0lists the four.tar.gzfiles (once CI is done).- Without Rust, the pinned demo runs the binary (
release binaryin its output): put a PATH with no cargo in front ofscripts/try-test.py <script> --expect "release binary" --expect Showcase. crates.ioisn’t published yet (see the plan).