Skip to main content
Bazel is famously extensible, and almost all of that extensibility points inward, at defining new rules. BUILD files and .bzl files are Starlark, so the build graph itself is programmable. But a large part of your build that engineers touch every day sits outside it: the CLI they type, the scripts that wrap it, and the plumbing that decides what they see when something breaks. None of that is rules, and Starlark doesn’t reach it. The wrappers are Bash and Make, the pipelines are YAML, and the only way to generate BUILD files programmatically is a Gazelle extension in Go. AXL, the Aspect Extension Language, is a Starlark dialect built into the open-source Aspect CLI. It’s how you program that outside layer. Same language as your .bzl files, with types, records and enums on top. No Go plugin to compile, no new YAML schema.

How this course works

You read AXL that already works. Typing it out is optional — every section starts with a git checkout, so the code arrives written and running. You read the diff, run the commands, change one thing, and watch what moves.
No time goes on transcription, so the course runs the same on your own or in a live session, and covers more ground in the time you have. Every step’s diff is one file, with two exceptions: the Gazelle step, which generates BUILD files as its output, and the policy step, which also brings the patch its exercise applies. Every file is short enough to read in full: changed.axl is 49 lines, policy.axl 62, observe.axl 56. The Gazelle extension in the Gazelle step is the longest at 128, and that section walks through its two halves rather than the whole file.

A theme worth naming

Bazel publishes an event for everything it does, and will write the stream to a file for anyone who asks. No service required. What it needs is a program to read it, and standing one up is enough friction that the work usually ends up somewhere else: a BES endpoint, a CI job, a future dashboard. AXL puts that processing in the tool that ran the build, on the machine that ran it, while it is still running. Logic that may otherwise be specific to your CI — or to a script you maintain by hand — is programmable in Starlark, and can be run locally or on CI with the same command. That is what this course is about: programmable control at the point where Bazel is executed, on CI and on a developer’s machine. Giving agents fast, structured, programmable feedback on builds is one of many applications of that control.

What you’ll have built

  • aspect changed — what you’re touching, computed from your uncommitted working tree
  • aspect policy — an architecture rule that exits non-zero, so CI can gate on it
  • aspect observe — a task that runs Bazel and reads its event stream
  • The same events attached to aspect test, a command you did not write
  • A Gazelle extension in Starlark that generates deployment targets from your own convention
  • A container image, pushed with a delivery command

Prerequisites

  • macOS or Linux. The Aspect CLI does not currently support Windows — contact us if you need it.
  • Git and a terminal.
  • Bazelisk, so .bazelversion is honored. See installing Bazelisk.
  • The Aspect CLI — the first section installs it. One line, no account.
  • Admin rights on the machine. The install script finishes with sudo mv into /usr/local/bin, and the first Bazel command writes to your home cache.
  • jq — required, not optional. brew install jq, or your package manager. Several steps use jq to compute the answer the prose quotes, not just to pretty-print it, so without it the transcripts don’t line up.
Comfort with BUILD files and labels helps. Prior Starlark experience is not required, and the places AXL differs from Bazel’s dialect are flagged as they come up.

Course contents

Install the CLI

The launcher, the CLI it fetches, and pinning a version for a repository.

Setting up the course repository

Clone it, confirm the pinned CLI runs, then start the Go monorepo’s build warming.

Your first command

Fifty lines of AXL, typed arguments, and which stream a command’s contract lives on.

A rule you can actually enforce

Layering rules as data, typed query results, and a non-zero exit code.

Watch Bazel work

Spawn Bazel yourself and read both structured streams, live and complete.

You won't ship that

Attach the same analysis to the commands you already run, without rewriting them.

Generate it, then ship it

A Gazelle extension in Starlark for your own convention, and a container pushed with a delivery command.

Hand it to an agent

An agent discovers everything you wrote, with no manifest and no network.