Releasing wharfy — one binary, to every channel

Making your own binary installable from every package manager is fiddly. wharfy (from wharf) is a CLI that settles it with one config file — I’ve released it. The job is to ship one binary to every channel, from a single wharfy.yaml, like this:

wharfy.yaml ──▶ Homebrew / Scoop / apt / rpm / container(ghcr)
                AUR / winget / go install / curl | sh

What was the problem

Every channel has its own format

Channel What you place
Homebrew a Ruby formula
Scoop a JSON manifest
winget three YAML files (version / installer / locale)
apt / rpm deb·rpm plus repository index metadata
AUR a PKGBUILD and .SRCINFO

On top sit signing, the git tag, and the place you publish to (a tap, a hosted repo). Each extra channel needs its own dance. Doing it all by hand every release isn’t something one person keeps up.

A release isn’t always driven by a human anymore

The thing operating a CLI now often includes an AI agent — and distribution is no exception.

But existing tools assume a human reads docs and writes YAML. Point an agent at that, and the cost piles up before the actual release. If distribution stays in a shape “a human memorizes and runs”, you can’t hand it to an agent as-is. That’s the problem I wanted to solve.

How I solved it

wharfy is an application that releases to multiple channels at once.

wharfy absorbs the per-channel formats

Write only what to ship, and where, in wharfy.yaml, and wharfy generates the shape each channel wants — the formula, the manifest, the winget YAML, the deb/rpm — and ships it to each destination.

Make it drivable by an agent

That leaves the “a human runs it by hand” assumption. wharfy closes, one by one, the costs an agent pays before the real work of a release.

Cost an agent pays up front wharfy’s answer
discovering which commands exist wharfy agent returns the whole capability map at once
parsing unstructured output every command takes --json
tracking what’s published, and where status reconciles record vs reality and shows the drift
guarding destructive steps it writes only what it owns; --dry-run and next: show first

The entry point is wharfy agent. It returns the commands, their order, and the channels in one map, so an agent reads it first and can drive from there.

$ wharfy agent
wharfy — ship one binary to every channel. Read this once, then drive.

COMMANDS (usual order)
  wharfy agent     print this capability map   → next: status
  wharfy build     cross-compile for every os/arch   → next: release
  wharfy release   upload the github release   → next: publish
  wharfy publish   push to owned channels; prepare gated ones   → next: verify
CHANNELS  homebrew scoop apt rpm container aur goinstall script  + winget homebrew-core(gated)

And every command ends with the next step. Each line under next: is a runnable command.

$ wharfy version
✓ 0.2.4
next:
  wharfy agent     # print this capability map (read once, then drive)

It never dirties your root either. wharfy writes only the distribution artifacts it owns, and even its intermediate files go under .wharfy/. State never quietly converges — if it has drifted, you see a diff. Because what happens is visible in the output, it’s also harder to send off the rails when an agent drives it.

In closing

wharfy packages distribution to many channels with an AI-friendly design as the premise. Install instructions for your environment are on the product site, wharfy.io.

☕ Tip me