The 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:
<repo-root>/.aspect/version.axl
Pinning a version here means every developer and every CI runner in the project executes the same aspect-cli, regardless of how recently they installed the launcher.
Because AXL-powered tasks (aspect build, aspect test, aspect lint, aspect delivery) ship with the CLI, bumping the version in .aspect/version.axl pulls in newer task behavior independent of any Aspect Workflows CI runner upgrade.
Pin a version
Create .aspect/version.axl at your repository root, alongside MODULE.bazel (or MODULE.aspect):
The launcher downloads v2026.22.39 directly from the Aspect CLI GitHub Releases the first time it’s needed and caches the binary locally. If the download fails, the launcher reports an error — a pinned version never silently falls back to a different release.
No version.axl (floating mode)
If .aspect/version.axl does not exist, the launcher queries the GitHub releases API for the most recent non-prerelease and downloads that. The resolved tag is cached for 24 hours so subsequent runs do not hit the API.
This is convenient for one-off use, but every contributor and CI runner can end up on a different aspect-cli version. Pin a version for any project where reproducibility matters.
Custom sources
The optional sources list overrides where the launcher looks for the CLI binary. Sources are tried in order; the first one that succeeds wins.
version(
"2026.22.39",
sources = [
local("bazel-bin/cli/aspect"),
github(
org = "aspect-build",
repo = "aspect-cli",
),
],
)
When sources is omitted, it defaults to [github(org = "aspect-build", repo = "aspect-cli")].
local(path)
Use a binary at a path relative to the repository root. Useful when developing the CLI locally:
local("bazel-bin/cli/aspect")
The file is copied into the launcher cache on each invocation so that build-system clean operations don’t break a running CLI.
github(org, repo, tag?, artifact?)
Download from a GitHub release:
github(
org = "aspect-build",
repo = "aspect-cli",
)
When tag and artifact are omitted the launcher derives defaults:
tag defaults to v{version} (e.g. v2026.22.39)
artifact defaults to {repo}-{target} (e.g. aspect-cli-aarch64-apple-darwin)
Override either with explicit strings if you publish releases under a different convention:
github(
org = "my-org",
repo = "aspect-cli-fork",
tag = "release-{version}",
artifact = "aspect-cli-{os}-{arch}",
)
Download from an arbitrary URL — for example, an internal mirror:
http(
url = "https://cdn.example.com/aspect-cli/{version}/aspect-cli-{target}",
)
Pass custom headers for authenticated endpoints:
http(
url = "https://internal.example.com/aspect-cli/{version}/aspect-cli-{target}",
headers = {
"Authorization": "Bearer <token>",
},
)
Template variables
tag, artifact, and url strings support {variable} placeholders the launcher replaces at runtime:
| Variable | Example | Description |
|---|
{version} | 2026.22.39 | The version from the version() call |
{os} | darwin, linux | Operating-system kernel name |
{arch} | aarch64, x86_64 | CPU architecture (Bazel naming) |
{target} | aarch64-apple-darwin, x86_64-unknown-linux-musl | LLVM target triple |
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 are not available.
Caching
Downloaded binaries are cached under the system cache directory:
- macOS:
~/Library/Caches/aspect/launcher/
- Linux:
~/.cache/aspect/launcher/
The cache path is derived from a SHA-256 hash of the tool name and source URL, so different versions coexist without conflict. Override the location with the ASPECT_CLI_DOWNLOADER_CACHE environment variable.
Set ASPECT_DEBUG=1 to log the download and cache resolution flow if you need to debug what the launcher is doing.
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; pinning a version updates both developer machines and runners with a single PR.
- GitHub Actions / other CI — see How to install the Aspect CLI for installing the launcher in your CI image. Once installed, the launcher reads the same
.aspect/version.axl from the checkout.