.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 agit checkout, so the code arrives written and running. You read the diff, run the commands, change one thing, and watch what moves.
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 treeaspect policy— an architecture rule that exits non-zero, so CI can gate on itaspect 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
.bazelversionis 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 mvinto/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 usejqto compute the answer the prose quotes, not just to pretty-print it, so without it the transcripts don’t line 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.

