Wheelhouse docs

Learn that a release exists#

You will end up with a job somewhere else that tells you when a newer Wheelhouse version is published.

Before you start#

  • A machine that is not the router and can reach the download host.
  • Somewhere to send a message: an existing monitoring system, a mailbox, a chat webhook.

Step 1 — Know what you are running#

In the web interface: the Updates panel says This router runs 0.9.1, or Up to date. This router runs 0.9.1.; the Version panel beside it names the product and its version.

From another machine, with no credential: GET /health answers anyone who can reach the port with {"status":"ok","version":"…"}, the agent's version:

bash
curl -sk https://<router>:8443/health |
  python3 -c 'import json,sys; print(json.load(sys.stdin)["version"])'

That is the version the router compares with the channel. GET /api/version, which needs a token, answers something else: the base system's own version.

At the console: the banner above every login prompt gives the Wheelhouse version and the host name on its header line. wheelhouse-agent --version answers before any configuration is read or any secret file opened, so a router whose agent will not start still says what it runs.

Step 2 — Poll the channel index#

The download host carries a machine-readable channel index. stable.json names the newest release tag; beta.json names the newest pre-release tag, a release candidate such as v1.2.3-rc1. The router's Channel setting chooses which of the two it reads. Poll the channel you actually run. /latest/ and stable.json follow the newest stable tag, and publishing a release candidate moves neither, so a beta tester watching either of them never sees the candidate.

bash
curl -s https://releases.rhymelikedi.me/stable.json |
  python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["version"], d["notes"])'
stable.json
{
  "channel": "stable",
  "version": "0.9.1",
  "tag": "v0.9.1",
  "released": "2026-09-18T12:00:00Z",
  "base": "https://releases.rhymelikedi.me/v0.9.1/",
  "notes": "https://releases.rhymelikedi.me/v0.9.1/CHANGELOG.md",
  "checksums": "SHA256SUMS",
  "signature": "SHA256SUMS.asc",
  "signed": false,
  "artifacts": [
    {"name": "wheelhouse-0.9.1-amd64.iso", "kind": "iso", "arch": "amd64",
     "size": 512483328, "sha256": "…"}
  ]
}

The fields are stable. version is the comparison key; base plus an artefact name forms the download address; sha256 is what to check; signed says whether signature is real. Fields may be added, so a consumer must ignore what it does not recognise. The channel index needs no licence key; the release directories it points into do.

Step 3 — Compare it with what you run#

A small script on the monitoring host. It reads the running version from the router's /health, which needs no credential, and complains when the channel moves ahead of it.

/usr/local/bin/wheelhouse-release-check
#!/bin/sh
set -eu
channel=https://releases.rhymelikedi.me/stable.json
have=$(curl -fsSk https://edge:8443/health | python3 -c 'import json,sys; print(json.load(sys.stdin)["version"])')
want=$(curl -fsS "$channel" | python3 -c 'import json,sys; print(json.load(sys.stdin)["version"])')
[ "$have" = "$want" ] && exit 0
notes=$(curl -fsS "$channel" | python3 -c 'import json,sys; print(json.load(sys.stdin)["notes"])')
echo "edge runs $have; $want is published. Notes: $notes"
exit 1

Run it from cron and let the non-zero exit be the alert, or pipe the message into whatever you already use. The check is a string comparison, not a version comparison — which is enough for "these differ, go and look" and not enough to decide which is newer.

Step 4 — Read the release notes before you upgrade#

CHANGELOG.md is published beside the files on the download host, and the router's Updates panel shows the same notes under What’s new once it has checked them against the published checksums. Security fixes are called out in a Security section there. There is still no advisory feed and no published patch cadence — the changelog is where a security fix is announced, and nothing pushes it to you.

What the router does with the same index#

The agent reads the index of the channel it is set to, on the schedule the licence refresher uses, and checks it against the SHA256SUMS published beside it, and the release notes against their entry in that file, before showing a word of them. Both come from the same host, so that proves agreement, not authenticity, and the panel says so in words rather than showing a tick.

Reading the index sends nothing about the router: no licence key, no fingerprint, no host name, and not even a version in the User-Agent. When the index names a release newer than the one running, the router also fetches that release's checksum file and release notes from its release directory, and those two requests carry the licence key, because the release host serves a release directory only to a licensed router.

To stop all of it, turn off Check daily; then no request is ever made. For automation, the same setting is PUT /api/admin/updates, and on disk it is "enabled": false in <data-dir>/updates.json.

Check it worked#

Run the script by hand against a version you know is old and confirm it complains, then against the current one and confirm it is silent. A monitoring check that has never fired is not the same as a monitoring check that works.

Undoing it#

Remove the cron entry.

See also#

Updated 2026-09-18 upgrade releases automation