> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# How to install the Aspect CLI

> Install the Aspect CLI on macOS, Linux, or Windows via curl, Homebrew, direnv, GitHub Actions, or manual download to launch the right Bazel version.

You can install the Aspect CLI using several methods. All of them install the `aspect-launcher`, a small binary added to your PATH as `aspect`. This launcher downloads and runs the version of the Aspect CLI binary [configured in your repository](/docs/cli/version-pinning). It operates similarly to how `bazelisk` fetches the configured version of Bazel, or how `nvm` or `n-` manages Node.js versions.

Find the latest releases at [https://github.com/aspect-build/aspect-cli/releases](https://github.com/aspect-build/aspect-cli/releases).

<Tip>
  After installing, follow the [Quickstart](/quickstart) for a 10-minute end-to-end walkthrough: build, test, customize built-ins, and extend the CLI with your first custom task.
</Tip>

## Install with curl

The curl script works on macOS and Linux without any prerequisite package manager. Run:

```shell theme={null}
curl -fsSL https://install.aspect.build | bash
```

This installs the `aspect-launcher` binary as `aspect` on your PATH.

### Updating with curl

To update the `aspect-launcher` with curl, re-run the installation script:

```shell theme={null}
curl -fsSL https://install.aspect.build | bash
```

## Install with Homebrew (macOS)

To install via Homebrew, run the following command:

```shell theme={null}
brew install aspect-build/aspect/aspect
```

Alternatively, tap the repository first and then install:

```shell theme={null}
brew tap aspect-build/aspect
brew install aspect
```

This installs the `aspect-launcher` binary as `aspect` on your PATH.

### Updating with Homebrew (macOS)

To update the `aspect-launcher` with Homebrew, run the following commands:

```shell theme={null}
brew update
brew upgrade aspect
```

## Install the Aspect CLI with `direnv` and `multitool`

This method assumes your development environment uses `bazel_env.bzl`. For examples, refer to the [aspect-starters repositories on GitHub](https://github.com/aspect-starters).

1. Add `aspect` to the multitool lockfile, as shown in [this example](https://github.com/aspect-starters/shell/blob/main/tools/tools.lock.json).
2. Build and run your `bazel_env` target. Bazel will handle the installation of `aspect`, making it available on your PATH.

For more details on this pattern, watch the Aspect Insights podcast episode "Developer Tooling in Monorepos with `bazel_env`":

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/TDyUvaXaZrc" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

## Install with GitHub Actions

Use the [`aspect-build/setup-aspect`](https://github.com/aspect-build/setup-aspect) action. It installs the launcher, installs Bazelisk (unless `bazel` is already on `PATH`), wires `--disk_cache` / `--repository_cache` to the GHA cache, and exchanges your `ASPECT_API_TOKEN` for a short-lived JWT, all in one step. The same one-liner works on provider-hosted runners (`ubuntu-latest`, `macos-latest`) and on Aspect Workflows CI runners.

```yaml theme={null}
permissions:
  id-token: write    # required for Aspect CLI's ArtifactUpload feature

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: aspect-build/setup-aspect@2306377a61c45954ab2df7c7311698b109364352 # v2026.26.9
        with:
          aspect-api-token: ${{ secrets.ASPECT_API_TOKEN }}
      - run: aspect test --task:name=test -- //...
```

Pin to a full-length commit SHA (with the version annotated in a trailing comment) per [GitHub's third-party action security guidance](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-third-party-actions). Find the SHA for the latest release on the [setup-aspect releases page](https://github.com/aspect-build/setup-aspect/releases), each release's notes carry a copy-paste snippet.

The CLI version itself is pinned by your repo's `.aspect/version.axl` (see [version pinning](/docs/cli/version-pinning)), the launcher reads that file and downloads the matching CLI on first `aspect` invocation, so local and CI stay in sync without bumping a launcher version in your workflow YAML.

### Without `setup-aspect`

If for some reason you'd rather install the launcher inline (or you're on a CI provider without an equivalent action, Buildkite, GitLab, CircleCI), the curl one-liner works:

```yaml theme={null}
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Aspect CLI
        run: curl -fsSL https://install.aspect.build | bash
      - name: Test
        run: aspect test --task:name=test -- //...
```

You give up GHA caching, the API-token-to-JWT exchange, and the Bazelisk install, all of which `setup-aspect` does for you.

## Install the Aspect CLI manually from GitHub

Visit the [Aspect CLI Releases page on GitHub](https://github.com/aspect-build/aspect-cli/releases) to download the appropriate binary for your platform, such as `aspect-launcher-aarch64-apple-darwin` for macOS arm64, or equivalents for other architectures and operating systems.

### macOS example

1. Download the `aspect-launcher-aarch64-apple-darwin` binary from the [Aspect CLI Releases page](https://github.com/aspect-build/aspect-cli/releases).
2. In your terminal, run these commands to clear the untrusted developer attribute, make the binary executable, and move it to your PATH:

   ```shell theme={null}
   xattr -c ~/Downloads/aspect-launcher-aarch64-apple-darwin
   chmod u+x ~/Downloads/aspect-launcher-aarch64-apple-darwin
   sudo mv ~/Downloads/aspect-launcher-aarch64-apple-darwin /usr/local/bin/aspect
   ```

## Keep your team typing `bazel` with the `tools/bazel` wrapper

A common objection when adopting the Aspect CLI is "we don't want to teach our developers a new command name." You don't have to. Drop a `tools/bazel` shell wrapper into your workspace and Bazelisk will exec it on every `bazel` invocation, routing each command to the right tool, `aspect` for the verbs `aspect` wraps (`build`, `test`, `run`, `lint`, `format`, `gazelle`, `delivery`, any custom `.axl` task), vanilla `bazel` for everything else (`query`, `info`, `clean`, …).

| You type                                | What runs                                             |
| --------------------------------------- | ----------------------------------------------------- |
| `bazel build //... --keep_going`        | `aspect build //... --bazel-flag=--keep_going`        |
| `bazel test //... --test_output errors` | `aspect test //... --bazel-flag=--test_output=errors` |
| `bazel lint --config=ci //src/...`      | `aspect lint --bazel-flag=--config=ci //src/...`      |
| `bazel query 'deps(//foo)'`             | vanilla `bazel`, unchanged                            |
| `bazel my-custom-task //...`            | `aspect my-custom-task //...`                         |

<Note>
  **Requires Bazelisk.** The `tools/bazel` hook is a [Bazelisk](https://github.com/bazelbuild/bazelisk) feature, the real `bazel` binary does not look for it. This works if the `bazel` on your team's `PATH` is Bazelisk, which is the most common setup (every Bazelisk release since 2019 honors the hook).
</Note>

The Aspect CLI can drop it in for you. From anywhere in your workspace:

```sh theme={null}
aspect wrapper install
```

This downloads the wrapper and its reference doc at a pinned release tag (not `main`), writes `tools/bazel` (executable) and `tools/bazel.md`, and prints the optional shell snippets below. Pin a specific version with `--version=<tag>`. Re-running is idempotent: an up-to-date copy is left untouched, a newer release is offered as an upgrade. In CI, `aspect wrapper install --check` exits non-zero when `tools/bazel` is missing or stale so you can gate on it. `aspect wrapper uninstall` removes the files again.

Or drop it in by hand:

```sh theme={null}
mkdir -p tools
base=https://raw.githubusercontent.com/aspect-build/aspect-cli/main/tools
curl -fsSL "$base/bazel" -o tools/bazel
curl -fsSL "$base/bazel.md" -o tools/bazel.md
chmod +x tools/bazel
git add tools/bazel tools/bazel.md
```

Bazel-native flags (`--keep_going`, `--config=ci`, `-c opt`, etc.) are transparently rewritten as `--bazel-flag=<flag>` so `aspect` forwards them through to Bazel, your existing muscle memory keeps working. Developers who prefer raw `bazel` for a shell session can set `ASPECT_WRAPPER_SKIP=1` to bypass routing entirely.

### Customize the verb routing

One list at the top of `tools/bazel` controls which verbs route through `aspect` with bazel-flag rewriting:

```sh theme={null}
ASPECT_VERBS_WITH_BAZEL_FLAGS="build buildifier delivery format gazelle lint test"
```

Two common edits:

* **Send `build` / `test` to vanilla `bazel` instead.** Remove them from the list and they'll fall through to the real `bazel` untouched (`query`, `info`, `clean`, etc. were already going there). Keep the aspect-only verbs (`lint`, `format`, `delivery`, `gazelle`) in the list so `bazel lint` and friends still reach `aspect`. Useful if your team wants `bazel build` to stay pure-Bazel but still pick up `aspect` for the verbs Bazel doesn't have.
* **Add custom AXL tasks that accept Bazel flags.** Custom tasks (any verb not in the Bazel verb list) already route to `aspect` verbatim, but their flags are forwarded unchanged. If your custom task accepts `--bazel-flag=` / `--bazel-startup-flag=` (e.g. it shells out to Bazel internally), add its name to `ASPECT_VERBS_WITH_BAZEL_FLAGS` so the wrapper rewrites `--keep_going` and friends into `--bazel-flag=--keep_going` for it the same way it does for built-ins.

```sh theme={null}
# Example: route bazel build/test to vanilla bazel, add a custom "release" task
ASPECT_VERBS_WITH_BAZEL_FLAGS="buildifier delivery format gazelle lint release"
```

The full reference (routing rules, flag-classification details, every escape hatch, refreshing the embedded Bazel-flag lists when Bazel adds flags) lives next to the script: [`tools/bazel.md`](https://github.com/aspect-build/aspect-cli/blob/main/tools/bazel.md).
