Skip to main content
An Aspect Enterprise deployment runs on its own hostnames, so something in the job has to name them. What that is depends on where the job runs.

On Aspect Workflows runners

The runner is inside the deployment. Its environment already carries the cache, build event service and results URL, and it holds its own credential, so nothing in your pipeline names an endpoint or handles a token for the build itself. Aspect CLI tasks need nothing. aspect build and aspect test build against the runner’s services without being asked. They refuse --remote: the flag names a configured deployment, which would route the build off the runner’s own services. Vanilla bazel needs an rc, which the setup step writes. Commands that don’t call Bazel need nothing. Scripts, Docker builds and other tools run on a Workflows runner as on any other; target the runner group and skip the setup step. The runner image puts aspect and bazel on PATH: aspect is the Aspect CLI launcher, and bazel is the legacy Aspect CLI unless the deployment is configured to install upstream Bazelisk as bazel instead. A job can tell the two apart by ASPECT_WORKFLOWS_RUNNER_NO_LEGACY_CLI=1, which is set only in the Bazelisk case.

The setup step

Recommended for every job that calls bazel directly. Add your CI host’s setup integration before the first bazel call. On a Workflows runner it:
  1. Runs aspect ci runner-health-check, which confirms the runner is ready for the job.
  2. Signs in, when given an Aspect API token. Tasks that post to pull requests (status checks, lint comments, suggested fixes) reach the GitHub or GitLab App with it; the build itself doesn’t need it. Pass it as aspect-api-token on GitHub Actions, or as ASPECT_API_TOKEN in the environment on the others.
  3. Runs aspect setup bazelrc, which writes ~/.aspect/bazelrc, imported from ~/.bazelrc. It names the runner’s remote cache and build event service and puts Bazel’s output base on the runner’s NVMe, and it’s what a vanilla bazel call picks up.
The launcher and bazel come with the runner image, so there’s nothing to install. Your CI host’s pipeline page has a complete pipeline.
On GitLab CI, a job with its own before_script replaces the template’s, and the setup doesn’t run. List the template’s first, with !reference:
Without an integration, run the same steps in the job yourself:
GitHub Actions
Drop the aspect auth login line if the job doesn’t post to pull requests. Runner groups covers which group a job lands on.

What the rc sets

The rc points bazel at the runner’s remote cache and build event service and puts the output base on the runner’s NVMe. Where the runner’s cache doesn’t accept compressed blobs, it sets --noremote_cache_compression, because Bazel errors when a repository asks for compression from a cache that lacks it. Remote execution is offered but not switched on. Each flag the rc sets can be dropped with --omit-bazel-flag, except endpoints, credentials, the --config chains and the runner’s paths. --bes_backend and --bes_results_url can be dropped, so a repository that streams build events somewhere else keeps doing that. See aspect setup bazelrc.

Where each integration lives

The versions above were current when this page was written. Each publishes on its own schedule, so take the latest from its own listing: Buildkite’s shorthand resolves aspect-build/setup-aspect to the full repository name, which is why the plugin reference looks shorter than the repository it comes from.
The GitHub and Buildkite examples pin a commit; the CircleCI and GitLab ones pin a version. An Action reference and a Buildkite plugin reference are git refs, so a commit is the tighter pin. A CircleCI orb resolves from the orb registry and a GitLab component from the CI/CD Catalog, where an immutable published version is the pin. The trailing comment gives the version each commit corresponds to.

Tuning the setup step

The integrations take the same inputs for the rc. Each is passed to aspect setup bazelrc, and an unset input leaves that flag off the command line, so the CLI applies its own default: Each CI host passes them its own way:
On a Workflows runner the GitHub Action also ignores its install, cache and bazelrc inputs, since the runner image and its rc supply those.

On runners you manage

A runner you manage needs the launcher, a credential for the deployment, and an rc naming the deployment’s endpoints. The setup integrations don’t cover it: they take no deployment host and read only ASPECT_API_TOKEN, so run the steps below in the job. Which hostname depends on where the runner sits. Inside the deployment’s VPC, or a network peered with it, it reaches the private endpoint; anywhere else, the external one. The setup is the same either way, and your Aspect contact or your Terraform outputs say which host applies.
On a persistent runner, pass —force to aspect setup bazelrc. The home directory outlives the job, so an rc written by the first job on that machine is still there for the next, and the command keeps an existing rc rather than overwriting it. An ephemeral runner starts clean, so this changes nothing there.

Record the deployment, then log in

The same path a developer takes, so the CI job and a laptop agree on what the deployment is called. The CLI recognizes GitHub Actions, Buildkite, CircleCI and GitLab CI by their own variables, and treats any other host as CI when CI is set. Jenkins and TeamCity don’t set it, so the snippet does; without it, aspect setup bazelrc would treat the job as a developer’s machine and turn nothing on. Set it in the job’s environment too, so later aspect tasks treat the job as CI.
The install script moves the binary into place with sudo, so the job needs it. The launcher version is separate from the CLI version, which .aspect/version.axl pins. The API token is per deployment: one minted for one deployment isn’t accepted by any other, or by Aspect Cloud. Your Aspect contact or the deployment’s admin issues it. Store it as a CI secret named ASPECT_API_TOKEN_<NAME>, the deployment name uppercased with every non-alphanumeric character replaced by _, which is the variable the CLI reads for that deployment. A deployment named gcp.acme reads ASPECT_API_TOKEN_GCP_ACME. --with-api-token exchanges the token for a short-lived session and stores it where a developer’s login goes: the OS keyring when the CLI can open one (on Linux, the kernel keyring), otherwise a 0600 file at ~/.aspect/credentials.json. Later steps in the same job reuse it. Set ASPECT_CREDENTIALS_FILE to store it in a file at that path instead.

Or name the endpoints outright

Set the endpoints in the job’s environment and the CLI takes them from there, with no auth configure step and nothing written to ~/.aspect/config.json: Your Aspect contact gives you these; on a self-hosted deployment they’re Terraform outputs.
This path writes no credential helper. Use it for endpoints the job reaches without an Aspect credential, or pair it with a credential helper you supply.
Setting ASPECT_WORKFLOWS_REMOTE_CACHE, ASPECT_WORKFLOWS_BES_BACKEND or ASPECT_WORKFLOWS_REMOTE_EXECUTOR tells the CLI which deployment this machine is on, as ASPECT_WORKFLOWS_RUNNER does on a Workflows runner. aspect setup bazelrc then takes its endpoints from the environment and writes no per-deployment sections, and an Aspect CLI task refuses —remote.
Which to use:
  • auth configure when the job also runs Aspect CLI tasks, or you want the deployment named the same way everywhere.
  • Environment variables when the endpoints need no Aspect credential from the job, or authenticate through a credential helper you supply, and you’d rather the pipeline say what it points at than depend on state in a home directory.

If the deployment uses your own identity provider

There’s no Aspect API token to issue, because Aspect doesn’t operate the directory that would issue it. CI authenticates with a JWT from your identity provider, fetched by a Bazel credential helper you supply: a client-credentials grant, a workload identity federation exchange, or whatever your organization already uses for machine-to-machine auth. Point Bazel at it with --credential_helper. One helper serves the cache, build event and remote execution endpoints.

Label your builds

A vanilla bazel call reaches the build event service with no commit, branch or pull request attached, so it arrives in the UI anonymous. aspect setup workspace-data supplies them as Bazel’s workspace status command:
Bazel takes one --workspace_status_command, so a repository that already has a status script calls the task from inside it. See composing with an existing script.

--remote on CI

You rarely pass it. A task’s --remote defaults to auto, which means bare --remote on CI, and nothing off it. On a runner you manage, a task reaches the default deployment’s cache and build events without the flag. auto steps aside wherever an explicit flag would fail: Bazel treats a credential helper that can’t produce a token as fatal, which is why auto won’t wire an endpoint it can’t authenticate to.

Remote execution

Never turned on for you: a deployment may run an executor while most jobs still want their actions local. How a job asks for it depends on how the job names the deployment: Which worker pool an action lands on is decided by its Bazel platform; see Targeting remote execution worker pools.
  • Local setup: the same deployment from a developer’s machine.
  • : connect Workflows runners to your CI provider.
  • Build metadata: label vanilla bazel builds with their commit and branch.