> ## 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.

# aspect setup workspace-data

> Attribute vanilla bazel invocations in the Build Results UI by pointing --workspace_status_command at the Aspect CLI.

`aspect setup workspace-data` prints this build's commit, branch, pull request and CI metadata as Bazel workspace status: `KEY value` lines on stdout.

```shell theme={null}
bazel build //... --workspace_status_command="aspect setup workspace-data"
```

An `aspect <task>` already sends this metadata with every invocation it streams. A vanilla `bazel` call sends none, so it arrives in the [Build Results UI](/docs/aspect-workflows/platform/features/webui) with no commit, no branch and no pull request. This command supplies them.

Bazel runs the command at the start of every invocation, so the values are always the current build's, and the flag is identical for every job, which makes it safe in a shared `~/.bazelrc`.

## Set it up

On a CI runner, put it in the machine rc that [`aspect setup bazelrc`](/docs/cli/tasks/setup_bazelrc) already writes, or in `~/.bazelrc` directly:

```bash theme={null}
build --workspace_status_command="aspect setup workspace-data"
```

A bare command name resolves on `PATH`, so no wrapper script or absolute path is needed, and arguments are accepted.

Locally it is worth the same line in your own `~/.bazelrc` if you stream developer builds, though the attribution matters most where builds are anonymous: CI.

### If you already have a workspace status script

Bazel takes one `--workspace_status_command`, so a repository that already has a script doesn't replace it; it calls this from inside. The output is `KEY value` lines on stdout, so appending them is the whole integration:

```bash title="tools/workspace_status.sh" theme={null}
#!/usr/bin/env bash
set -euo pipefail

# Your existing keys, unchanged.
echo "STABLE_RELEASE_TRAIN $(cat .release-train)"
echo "BUILD_HOST $(hostname)"

# Aspect's commit, branch and pull request attribution, appended.
# Guarded so a machine without the CLI still produces a status file rather
# than failing the build.
if command -v aspect > /dev/null 2>&1; then
  aspect setup workspace-data
fi
```

Your `.bazelrc` keeps naming your script:

```bash theme={null}
build --workspace_status_command=tools/workspace_status.sh
```

When you compose them:

* **Keep your keys and Aspect's distinct.** Aspect emits the keys listed [below](#what-it-emits); if your script already sets one of those names, rename yours rather than relying on which line Bazel keeps.

## What it emits

The keys are the ones `aspect <task>` already sends as `--build_metadata`, so the two routes reach the same fields. The UI merges both, with `--build_metadata` winning where they disagree. What is available depends on the CI host and the checkout, and empty values are dropped:

| Keys                                                                                                             | Carries                                                                                                                                                     |
| ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `COMMIT_SHA`, `COMMIT_AUTHOR`, `COMMIT_AUTHOR_NAME`, `COMMIT_AUTHOR_EMAIL`, `COMMIT_MESSAGE`, `COMMIT_TIMESTAMP` | The commit, and on a pull request the **head** commit rather than the forge's synthesized merge. `COMMIT_MESSAGE` is the subject line, cut at 80 characters |
| `BRANCH_NAME`, `TAG`                                                                                             | The branch, and the tag where there is one                                                                                                                  |
| `PR_NUMBER`, `PR_ID`, `PR_SOURCE_BRANCH_NAME`, `PR_TARGET_BRANCH_NAME`                                           | The pull or merge request and its branches                                                                                                                  |
| `VCS`, `REPO_OWNER`, `REPO_NAME`, `REPO_URL`                                                                     | The repository. `ASPECT_VCS_URL` overrides these for mirrored checkouts                                                                                     |
| `USER`                                                                                                           | The actor who triggered the build                                                                                                                           |
| `CI_HOST`, `RUN_TYPE`, `BUILD_URL`                                                                               | The CI host, the kind of run (`PULL_REQUEST`, `BRANCH_PUSH`, `TAG`, `SCHEDULED`, `MANUAL`) and the run's URL                                                |

<Note>
  The keys are written **unprefixed**, so they land in <code>volatile-status.txt</code> rather than
  <code>stable-status.txt</code>. A <code>STABLE\_</code> key invalidates every stamped action whenever it
  changes, the wrong trade for data that changes every commit.
</Note>

## Where it prints nothing

In a bare directory with no git, no `.aspect/` and no `MODULE.bazel`, the shape a sibling workspace often has, it prints nothing and exits 0.

Task narrative goes to stderr, so stdout carries only the data and Bazel's parse stays clean.

It exits non-zero when `aspect` isn't on `PATH` or the workspace's `.aspect/config.axl` fails to evaluate. Where developers may not have the CLI installed, call it from [your own status script](#if-you-already-have-a-workspace-status-script) and guard the call.

<Warning>
  It costs roughly **350ms per invocation**, on the critical path of every <code>bazel</code> call
  that uses it. That's negligible on a CI build and noticeable in a script calling
  <code>bazel</code> in a loop. Almost all of it is CLI startup rather than the <code>git</code> call.
</Warning>

## What it doesn't do

Workspace status carries attribution, not wiring. A vanilla `bazel` still needs `--remote_cache` and `--bes_backend` from somewhere; that's [`aspect setup bazelrc`](/docs/cli/tasks/setup_bazelrc)'s job.

## Related

* [`aspect setup bazelrc`](/docs/cli/tasks/setup_bazelrc): the endpoints half of the same problem.
* [Build Results UI](/docs/aspect-workflows/platform/features/webui): where the metadata shows up.
* [Aspect Cloud CI setup](/docs/aspect-workflows/cloud/ci-setup): both halves, on runners you already have.
