release flow: VERSION, CHANGELOG, tagged releases, and a tag-resolving installer that pins box #32

Closed
opened 2026-07-18 17:22:22 +00:00 by dan-claude-bot · 2 comments
dan-claude-bot commented 2026-07-18 17:22:22 +00:00 (Migrated from github.com)

The problem

rig has no version identity at all: no VERSION file, no CHANGELOG.md, no tags, no GitHub releases, and no rig --version. install.sh downloads archive/refs/heads/main and upgrades by rm -rf + reinstall — so "what rig is this host running?" has no answer better than "whenever it last curl'd main". For the tool that hardens servers and closes root, that's the wrong answer: an incident wants to know exactly which rig converged this host.

This is the rig half of the flow designed in heavy-duty/box#83 — same shape, minus box's extra machinery, plus the cross-repo pin.

The flow

1. Grow the version surface first.

  • Add VERSION (start at 0.1.0) and a rig --version verb that reads it.
  • Add CHANGELOG.md with an ## Unreleased section; from then on, feature PRs land their entry as part of the PR (box's convention).

2. A release is a PR, then a tag.

  • A small PR — release: X.Y.Z — bumps VERSION and stamps the Unreleased section with version + date. CI (shellcheck, cli tests, the db round-trip) green on it.
  • Merge, tag the merge commit bare X.Y.Z (matching box's tag scheme), push the tag.

3. release.yml, on tag push:

  • Assert tag == VERSION — fail loudly on mismatch, create nothing.
  • Extract that version's CHANGELOG.md section and gh release create with it as the body.
  • No assets: for a pure-bash tree, GitHub's source tarball for the tag is the package.

4. The installer defaults to the latest release, not main.

  • RIG_REF unset → resolve the latest tag by following the releases/latest redirect (Location header — no API, no token), download archive/refs/tags/$TAG.tar.gz.
  • RIG_REF set → try refs/tags/$REF first, fall back to refs/heads/$REF.
  • Three channels from one script: default = latest release, RIG_REF=0.1.0 = pinned, RIG_REF=main = dev. README documents all three; "Re-run any time to upgrade" stays true and now means "upgrade to the latest release".

(rig's installer replaces $DEST wholesale, which is fine — rig is root-plumbing with no long-lived state under the tree, so it does not need box's side-by-side versions/ layout.)

5. rig pins the box it installs.

rig puts box onto hosts (docs/plans/2026-07-17-host-installs-box.md; #29 already flags the unpinned install). Once box installs from tags (heavy-duty/box#83), rig's box-install path sets BOX_REF=<tag> to the box version this rig was drilled against, and each rig release's notes state the box version it ships/requires. The repos still release independently — the tag is the contract surface, not a lockstep version.

Order

  1. Version surface (VERSION, --version, CHANGELOG.md).
  2. release.yml + tag-resolving installer (near-verbatim copies of box's, from heavy-duty/box#83).
  3. Cut 0.1.0.
  4. After box's next tagged release: pin BOX_REF in the host-installs-box path.
## The problem rig has no version identity at all: no `VERSION` file, no `CHANGELOG.md`, no tags, no GitHub releases, and no `rig --version`. `install.sh` downloads `archive/refs/heads/main` and upgrades by `rm -rf` + reinstall — so "what rig is this host running?" has no answer better than "whenever it last curl'd main". For the tool that hardens servers and closes root, that's the wrong answer: an incident wants to know exactly which rig converged this host. This is the rig half of the flow designed in heavy-duty/box#83 — same shape, minus box's extra machinery, plus the cross-repo pin. ## The flow **1. Grow the version surface first.** - Add `VERSION` (start at `0.1.0`) and a `rig --version` verb that reads it. - Add `CHANGELOG.md` with an `## Unreleased` section; from then on, feature PRs land their entry as part of the PR (box's convention). **2. A release is a PR, then a tag.** - A small PR — `release: X.Y.Z` — bumps `VERSION` and stamps the Unreleased section with version + date. CI (shellcheck, cli tests, the db round-trip) green on it. - Merge, tag the merge commit bare `X.Y.Z` (matching box's tag scheme), push the tag. **3. `release.yml`, on tag push:** - Assert tag == `VERSION` — fail loudly on mismatch, create nothing. - Extract that version's `CHANGELOG.md` section and `gh release create` with it as the body. - No assets: for a pure-bash tree, GitHub's source tarball for the tag **is** the package. **4. The installer defaults to the latest release, not main.** - `RIG_REF` unset → resolve the latest tag by following the `releases/latest` redirect (`Location` header — no API, no token), download `archive/refs/tags/$TAG.tar.gz`. - `RIG_REF` set → try `refs/tags/$REF` first, fall back to `refs/heads/$REF`. - Three channels from one script: default = latest release, `RIG_REF=0.1.0` = pinned, `RIG_REF=main` = dev. README documents all three; "Re-run any time to upgrade" stays true and now means "upgrade to the latest *release*". (rig's installer replaces `$DEST` wholesale, which is fine — rig is root-plumbing with no long-lived state under the tree, so it does not need box's side-by-side `versions/` layout.) **5. rig pins the box it installs.** rig puts box onto hosts (`docs/plans/2026-07-17-host-installs-box.md`; #29 already flags the unpinned install). Once box installs from tags (heavy-duty/box#83), rig's box-install path sets `BOX_REF=<tag>` to the box version this rig was drilled against, and each rig release's notes state the box version it ships/requires. The repos still release independently — the tag is the contract surface, not a lockstep version. ## Order 1. Version surface (`VERSION`, `--version`, `CHANGELOG.md`). 2. `release.yml` + tag-resolving installer (near-verbatim copies of box's, from heavy-duty/box#83). 3. Cut **0.1.0**. 4. After box's next tagged release: pin `BOX_REF` in the host-installs-box path.
dan-claude-bot commented 2026-07-18 19:12:24 +00:00 (Migrated from github.com)

Companion filed: #35 (versioned installs + real uninstall, box#79's layout ported). Sequencing note: #35 wants this issue's VERSION file first — the version key is the tree's own VERSION — and the tag-resolving installer then pins into the same versions/ layout, exactly the box#79 → box#83 pairing.

Companion filed: #35 (versioned installs + real uninstall, box#79's layout ported). Sequencing note: #35 wants this issue's VERSION file first — the version key is the tree's own VERSION — and the tag-resolving installer then pins into the same versions/<v> layout, exactly the box#79 → box#83 pairing.
dan-claude-bot commented 2026-07-18 20:45:32 +00:00 (Migrated from github.com)

Scope update: step 1 is now partially landed — #36 delivered VERSION (currently 0.1.0-dev), rig --version, and the side-by-side versions/<v> install layout (rig adopted box's #79 layout after all, superseding this issue's "replaces $DEST wholesale" note). Remaining scope here: CHANGELOG.md, release.yml, and the tag-resolving installer. Step 5 (pinning BOX_REF) stays deferred until box cuts its first post-heavy-duty/box#83 tag.

Scope update: step 1 is now partially landed — #36 delivered `VERSION` (currently `0.1.0-dev`), `rig --version`, and the side-by-side `versions/<v>` install layout (rig adopted box's #79 layout after all, superseding this issue's "replaces $DEST wholesale" note). Remaining scope here: `CHANGELOG.md`, `release.yml`, and the tag-resolving installer. Step 5 (pinning `BOX_REF`) stays deferred until box cuts its first post-heavy-duty/box#83 tag.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/rig#32
No description provided.