aspect binary you install is a thin launcher: it provisions and execs the real aspect-cli for your project. The launcher decides which CLI version to run by reading a single file in your repository:
aspect-cli, regardless of how recently they installed the launcher.
Pin a version
Create.aspect/version.axl at your repository root, alongside MODULE.bazel (or MODULE.aspect):
v2026.41.50 directly from the Aspect CLI GitHub Releases the first time it’s needed and caches the binary locally. A pinned version never falls back to a different release.
How the launcher finds the pin
The launcher walks up from the working directory to find the project root:- The nearest directory containing
MODULE.aspector.aspect/version.axl, not counting your home directory. - Otherwise, the nearest directory containing a Bazel boundary file such as
MODULE.bazelorREPO.bazel. - Otherwise, the working directory.
.aspect/version.axlin the project root.- User-level pin:
~/.aspect/version.axl, same syntax. It sets a default CLI version for any project root without its own pin, including a Bazel workspace that has no.aspect/version.axl. - Floating mode: the launcher queries the GitHub releases API for the latest release and downloads that. The resolved tag is cached for 24 hours.
A project-level
.aspect/version.axl always wins over ~/.aspect/version.axl.aspect-cli version. Pin a version (per project, or per user via ~/.aspect/version.axl) for any project where reproducibility matters.
Custom sources
The optionalsources list overrides where the launcher looks for the CLI binary. Sources are tried in order; the first one that succeeds wins.
sources is omitted, the launcher tries the GitHub release first, then Aspect’s CDN mirror of the same assets.
local(path)
Use a binary at a path relative to the repository root. Useful when developing the CLI locally:
github(org, repo, tag?, artifact?)
Download from a GitHub release:
tag and artifact are omitted the launcher derives defaults:
tagdefaults tov{version}(e.g.v2026.41.50)artifactdefaults to{repo}-{target}(e.g.aspect-cli-aarch64-apple-darwin)
http(url)
Download from an arbitrary URL, for example an internal mirror:
http() doesn’t support custom request headers.
Template variables
tag, artifact, and url strings support these placeholders, replaced at runtime:
These are the only supported placeholders.
version.axl is parsed as Starlark syntax but not evaluated: only string literals and function-call structure are extracted, so expressions, variables, and conditionals aren’t available.
Caching
Downloaded binaries are cached under the system cache directory:- macOS:
~/Library/Caches/aspect/launcher/downloader/ - Linux:
~/.cache/aspect/launcher/downloader/
ASPECT_LAUNCHER_CACHE to a root directory; binaries go under <root>/downloader/.
Set ASPECT_DEBUG=1 to log the launcher’s download and cache resolution.
Debug build of the CLI
Releases can also publish a debug build of the CLI: unstripped and built with debug assertions, so a crash report resolves to function and line. It’s larger and slower. Request it withdebug = True:
ASPECT_DEBUG_CLI environment variable set to any non-empty value. When a release has no debug asset, the launcher falls back to the primary binary. A source with an explicit artifact always gets that artifact.
CI considerations
CI runners share the same launcher behavior as developer machines, so a committed.aspect/version.axl pins the CLI version everywhere at once.
- Aspect Workflows CI runners ship with the launcher pre-installed.
- GitHub Actions / other CI: see Install the Aspect CLI for installing the launcher in your CI image. Once installed, the launcher reads the same
.aspect/version.axlfrom the checkout.

