uf0.0.0-alpha

Getting started

Install

uf is a single native binary. It needs a JavaScript host — Node.js, Bun or Deno — because Vite and your test bodies run there, but it is not installed through one.

From a release

Every tagged release publishes binaries for macOS and Linux, on both x86-64 and ARM64:

The script picks the binary for your platform, checks it, and puts it on your PATH. It works under sh, bash and zsh. Read it before you run it — it is short, and it is served from https://setup.uniflowed.dev/install.sh if you would rather fetch it first.

What it checks, and what that proves

Two separate things, because they answer two questions.

The SHA-256 beside the archive proves transit: the bytes that arrived are the bytes that host advertised, which catches a truncated download or a corrupting proxy. It proves nothing about origin — the archive and the checksum come from the same host, so whoever can replace one can replace the other.

The signature proves origin. Every release archive is signed with keyless Sigstore from the release workflow's own GitHub OIDC identity, and the installer verifies the bundle against that identity — a root that is not on the host serving the archive. Install cosign and the check runs; without it the installer says the signature was not checked rather than implying it was.

VariableDefaultWhat it does
UF_VERIFY_ORIGINautorequire refuses an install whose origin nothing established; off skips the check
UF_CHECKSUM_BASEunsetA <base>/<version>/<asset>.sha256 layout on a host that does not serve the archive. The two digests must agree
UF_VERSIONlatestA specific release
UF_RELEASE_BASEunsetA mirror serving the flat <base>/<version>/<asset> layout
UF_INSTALL_ROOT, UF_BIN_DIRXDG pathsWhere the runtime and the shims go

A signature that is present and does not verify always refuses, whatever UF_VERIFY_ORIGIN says — and so does a second opinion that disagrees. The failure prints cosign's own words, because a signature made by somebody else and a cosign too old to read the bundle exit the same way and are not the same problem. uf's own release pipeline installs with UF_VERIFY_ORIGIN=require, so a release whose signature does not verify never reaches you.

The default is auto and not require for one reason, which will stop being true: releases published before signing existed carry no bundle, and a default that refused them would make every pinned UF_VERSION of an older release uninstallable by the current script. Pass UF_VERIFY_ORIGIN=require today to get the stricter behaviour; it is what the default becomes once every release a person can still install is signed.

On Windows

There is no Windows build yet. The release workflow produces four artifacts, all of them macOS and Linux, so irm https://setup.uniflowed.dev/install.ps1 | iex resolves — deliberately, so the URL says something useful — and then prints an error telling you the same thing.

Two paths that do work: run uf under WSL2, where the Linux install above applies unchanged; or build it from source with cargo install, below, which needs no artifact.

From source

uf builds with a pinned nightly Rust toolchain — Flow's own crates need box_patterns, which is still unstable — and vendors the Flow and React Compiler sources as submodules.

git clone --recurse-submodules https://github.com/ubugeeei-prod/uf
cd uf && cargo build --release --bin uf

The toolchain file in the repository selects the right nightly, so rustup will fetch it on the first build. Expect the first build to take a while: it compiles the Flow parser and the React Compiler.

The JavaScript host

uf does the parsing, transforming, scheduling and reporting itself, and hands the rest to a host:

HostDev and buildTestsNotes
Node.jsyesyesThe default. Flow modules load through module.register().
BunyesyesFlow modules load through a --preload plugin.
Denonot yetnot yetNo Flow loader on any path. packages/vite/driver.js registers Node's hooks and Bun is started with --preload; Deno gets neither, so the first Flow module a command imports fails to parse. uf test refuses it up front with a message rather than failing later on a syntax error. See #246.

uf detects what is available and picks one. To pin a project to a host:

uf use bun

which writes the choice into uf.config.js. uf info prints what was detected and what was chosen.

Checking the install

uf info

prints the version, the resolved host, and the project it found. If it reports no project, you are outside one — that is fine, and the next page starts one.

Next: Your first project