Installing and verifying the CLI
The aircloud CLI ships for macOS and Linux, on x86-64 and arm64. Windows is not supported. Every channel
installs the same signed release. A release is identified by its version (x.y.z), and aircloud version prints
it together with the day it was released and the platform build it was made from (the date is read from the
download origin; offline, the version is still printed and the CLI says why the date is not):
aircloud version
Install with install.sh (recommended)
curl -fsSL https://get.simpleservices.com.br/install.sh | sh
The script installs aircloud into ~/.local/bin without sudo. Before it installs anything it checks the
release: it verifies the signed latest.json, verifies the signature over checksums.txt with openssl against
the public key embedded in the script, and then checks the archive's SHA-256 against checksums.txt. A mismatch
stops the install. To install a specific release instead of the latest, set AIRCLOUD_VERSION:
curl -fsSL https://get.simpleservices.com.br/install.sh | AIRCLOUD_VERSION=0.1.12 sh
Make sure ~/.local/bin is on your PATH.
At the end the script offers to install the AI-Skill for your coding agent: on an interactive terminal it runs
aircloud skill install --detect --prompt, which asks before each agent it finds. Without a terminal, set
AIRCLOUD_INSTALL_SKILL to a comma-separated list of agents (for example claude,codex) and it runs
aircloud skill install --agent <agent> for each. See The AI-Skill.
Homebrew
brew install aircloudhq/tap/aircloud
The formula downloads the same archives from get.simpleservices.com.br.
npm
npm install -g @aircloudhq/cli
@aircloudhq/cli resolves the binary from a per-platform package (@aircloudhq/cli-<os>-<arch>).
The npm packages install on Node.js >=22.0.0. Node.js only runs the small launcher that starts the native
binary, and the install is tested on each Node.js LTS line in that range. On an older Node.js, npm warns
EBADENGINE and skips the per-platform package, so the install reports success without the binary. aircloud
then refuses to run: it names your Node.js version and the supported range. Install a Node.js inside the range
and run npm install -g @aircloudhq/cli again.
If you install with --omit=optional, npm skips the per-platform package too, and aircloud names the
package it could not find. Reinstall without that flag.
Docker
The image ghcr.io/aircloudhq/aircloud is a multi-arch image whose entrypoint is aircloud. It is tagged with
each version and latest, and signed by digest:
docker pull ghcr.io/aircloudhq/aircloud
In a script or CI, pin a version, and mount the product directory as the working directory:
docker run --rm -v "$PWD:/product" -w /product ghcr.io/aircloudhq/aircloud:0.1.12 check
A container has no keychain, so a command that calls the platform logs in as a service account (see
Logging in). Keep the session in a directory of the host
through XDG_CONFIG_HOME, run as your own user so the files stay yours, and mount the key file read-only at the
same path for every run:
docker run --rm --user "$(id -u):$(id -g)" -e XDG_CONFIG_HOME=/state -v "$HOME/.aircloud-ci:/state" \
-v "$HOME/ci-key.json:/keys/ci-key.json:ro" \
ghcr.io/aircloudhq/aircloud:0.1.12 login --service-account /keys/ci-key.json
docker run --rm --user "$(id -u):$(id -g)" -e XDG_CONFIG_HOME=/state -v "$HOME/.aircloud-ci:/state" \
-v "$HOME/ci-key.json:/keys/ci-key.json:ro" -v "$PWD:/product" -w /product \
ghcr.io/aircloudhq/aircloud:0.1.12 release create --wait
Keep the key file outside the product directory, so it is never committed with the product.
Upgrading
aircloud changelog
aircloud upgrade
aircloud upgrade --version 0.1.12
aircloud changelog shows where your CLI stands: the latest release, the notes of every newer release — each with
the day it was released — and the command that upgrades your install (--check exits 1 when a newer release
exists). Every release's notes and date are on the Release notes page too, in the
main menu.
aircloud upgrade replaces the binary with the latest release, or with the release --version names. The release
is verified before it runs: the signed latest.json, the signature over checksums.txt against the key the
running binary embeds, and the checksums of the archive and of the release notes. Any mismatch leaves the binary
as it is. After the upgrade it prints what changed — the notes of every release it moved across, newest first,
each with the day it was released, with what to do when something you use changed. A release older than
the running one is refused unless --version names it. A binary that Homebrew or npm installed belongs to that
manager, and aircloud upgrade tells you to use it instead: brew update && brew upgrade aircloud (Homebrew
refreshes a tap on its own only once a day, so brew upgrade alone can miss a release that just shipped), or
npm install -g @aircloudhq/cli@latest.
On macOS, the first command after an upgrade asks you to log in once more: see Logging in.
What a release contains
get.simpleservices.com.br serves a signed manifest at its root and each release under versions/<version>/:
| file | what it is |
|---|---|
latest.json, latest.json.sig |
the latest version and when it was issued, and its signature |
versions/<version>/checksums.txt |
the SHA-256 of every archive of the release |
versions/<version>/checksums.txt.sig |
the signature over checksums.txt (base64 of an ECDSA P-256 signature over its SHA-256) |
versions/<version>/aircloud_<version>_<os>_<arch>.tar.gz |
the archive, <os> darwin or linux, <arch> amd64 or arm64 |
versions/<version>/aircloud_<version>_<os>_<arch>.tar.gz.sbom.json |
the archive's software bill of materials |
A published release never changes.
Verifying a release by hand
install.sh and aircloud upgrade run these checks for you. To run them yourself you need only openssl and
shasum. These are the release public keys, every key version oldest first — the same set install.sh and the
binary embed. A release is signed with one of them, normally the last:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgMxKVDQ4N2AJqbEiKoG4sUAelsHR
Gmt4z8RgKflPGq9e/rq5ThFvcZ01pG4bOFH/mQYPQf1+YNB3hQXkBp2hsg==
-----END PUBLIC KEY-----
Save one key, from its -----BEGIN PUBLIC KEY----- line to its -----END PUBLIC KEY----- line, as cosign.pub.
Then, for a version and your platform:
V=0.1.12
ARCHIVE=aircloud_${V}_linux_amd64.tar.gz
curl -fsSLO https://get.simpleservices.com.br/versions/${V}/checksums.txt
curl -fsSLO https://get.simpleservices.com.br/versions/${V}/checksums.txt.sig
curl -fsSLO https://get.simpleservices.com.br/versions/${V}/${ARCHIVE}
openssl base64 -d -A -in checksums.txt.sig -out checksums.txt.der
openssl dgst -sha256 -verify cosign.pub -signature checksums.txt.der checksums.txt
grep " ${ARCHIVE}\$" checksums.txt | shasum -a 256 -c
openssl prints Verified OK when the signature holds, and shasum prints <archive>: OK when the archive is
the one the signed checksums name; when openssl prints Verification failure, try the set's other keys before
you reject the release. The same two steps verify latest.json against latest.json.sig.
The Docker image is signed by digest, with no transparency-log entry:
cosign verify --key cosign.pub --insecure-ignore-tlog ghcr.io/aircloudhq/aircloud@sha256:<digest>
macOS and Gatekeeper
The macOS binaries are not yet notarized. install.sh and Homebrew install them without the quarantine
attribute, so they run. A binary you download with a browser is quarantined, and Gatekeeper refuses to run it as
unidentified: install with install.sh or Homebrew instead.