> ## 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 listen for build events

> Subscribe AXL extensions to Bazel's Build Event Service (BES) stream, iterating events from aspect build and aspect test inside the Aspect CLI.

Bazel emits a stream of structured events during every build — target outcomes, test results, output file paths, timing, and more. AXL tasks can subscribe to this stream and act on individual events as they arrive.

Create an iterator with `bazel.build_events.iterator()`, pass it to `ctx.bazel.build()` (or `ctx.bazel.test()`) via the `build_events` parameter, and then iterate the handle with `for event in events:`. Events are delivered synchronously (Starlark is single-threaded), so the iterator blocks until the next event is ready and unblocks when the build finishes.

Each event has a `kind` string that identifies the event type, and a `payload` whose fields depend on that kind. The full set of event kinds and payload types is defined in Bazel's Build Event Stream protocol.

<Info>
  **Build Event Stream reference**

  * Protocol definition: [build\_event\_stream.proto](https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto)
  * API documentation: [Buf Schema Registry](https://buf.build/bazel/bazel/docs/main:build_event_stream)
  * Event ordering examples: [Bazel BEP Documentation](https://bazel.build/remote/bep-examples)
  * AXL type reference: [build\_event kinds](/axl/types/bazel/build/build_event)
</Info>

## Collecting output files

A common use case is collecting the output files that Bazel produced. Files arrive in `named_set_of_files` events:

```python theme={null}
def impl(ctx: TaskContext) -> int:
    events = bazel.build_events.iterator()
    build = ctx.bazel.build(
        build_events = [events],
        *ctx.args.target_pattern,
    )

    outputs = []
    for event in events:
        if event.kind == "named_set_of_files":
            for f in event.payload.files:
                outputs.append(f.name)

    status = build.wait()
    if status.code == 0:
        for name in outputs:
            ctx.std.io.stdout.write(name + "\n")
    return status.code

list_outputs = task(
    implementation = impl,
    args = {
        "target_pattern": args.positional(default = ["..."], maximum = 512),
    },
)
```

The `File` payload exposes `name`, `digest`, `length`, and `path_prefix` directly. The URI is wrapped in a `file` oneof (`uri`, `contents`, or `symlink_target_path`) — most consumers want `name`, which is the file's logical identifier (for example `bazel-bin/path/to/target.out`).

## Filtering by event kind

To skip irrelevant events, pass `kinds=` to `iterator()`. Only the listed event kinds are delivered:

```python theme={null}
events = bazel.build_events.iterator(kinds = ["test_result", "build_finished"])
```

## Reacting to test results

`test_result` events fire once per test target. The label of the test target is on the event's `id`, and the status comes from the payload:

```python theme={null}
events = bazel.build_events.iterator(kinds = ["test_result"])
build = ctx.bazel.test(build_events = [events], "//...")

for event in events:
    label = event.id.test_result.label
    passed = event.payload.status == "PASSED"
    ctx.std.io.stdout.write("{}: {}\n".format(label, "PASS" if passed else "FAIL"))
```

See the [test\_result payload reference](/axl/types/bazel/build/build_event/test_result) for the full list of fields.
