# 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): ```sh aircloud version ``` ## Install with install.sh (recommended) ```sh 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`: ```sh 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 ` for each. See [The AI-Skill](ai-skill.md). ## Homebrew ```sh brew install aircloudhq/tap/aircloud ``` The formula downloads the same archives from `get.simpleservices.com.br`. ## npm ```sh npm install -g @aircloudhq/cli ``` `@aircloudhq/cli` resolves the binary from a per-platform package (`@aircloudhq/cli--`). 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: ```sh docker pull ghcr.io/aircloudhq/aircloud ``` In a script or CI, pin a version, and mount the product directory as the working directory: ```sh 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](login.md#service-accounts-ci-and-headless-machines)). 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: ```sh 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 ```sh 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](../reference/changelog.md) 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](login.md#macos-one-new-login-after-each-upgrade). ## What a release contains `get.simpleservices.com.br` serves a signed manifest at its root and each release under `versions//`: | file | what it is | |---|---| | `latest.json`, `latest.json.sig` | the latest version and when it was issued, and its signature | | `versions//checksums.txt` | the SHA-256 of every archive of the release | | `versions//checksums.txt.sig` | the signature over `checksums.txt` (base64 of an ECDSA P-256 signature over its SHA-256) | | `versions//aircloud___.tar.gz` | the archive, `` `darwin` or `linux`, `` `amd64` or `arm64` | | `versions//aircloud___.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: ```text -----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: ```sh 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 `: 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: ```sh cosign verify --key cosign.pub --insecure-ignore-tlog ghcr.io/aircloudhq/aircloud@sha256: ``` ## 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. --- Rendered from aircloud 0.1.12 at commit d84a0ce6dae53629277f656d96d81549df36807e.