build, test, lint, format, gazelle, delivery) emit two kinds of follow-up suggestions when something noteworthy happens:
- Repro commands — “how do I reproduce this failure?” Rendered with a
🔁 Reproduce:header. - Fix commands — “how do I apply the suggested fix?” Rendered with a
🛠️ Fix:header.
TaskLifecycleTrait.repro_fix_suggestion lets your .aspect/config.axl accept, reject, or rewrite each suggestion before any surface renders it. Common uses:
- Rewrite suggested
aspect …commands to your team’s preferred form — for examplebazel …via thetools/bazelwrapper, or your repo’s own custom developer CLI (e.g.mycorp build …instead ofaspect build …) when you’ve wrapped Bazel/Aspect behind a company-branded entry point. - Drop the vanilla-
bazelalternate suggestion that built-ins tack on by default — useful when your team always has the Aspect CLI on PATH. - Add a description to a suggestion that ships without one, so the rendered line carries a
# <label>above the command explaining what it does.
Hook signature
.aspect/config.axl
Verdicts
Return one of three values from your hook:
A
replace with both command and description left as None is a no-op (equivalent to accept).
ReproFixInfo fields
The single info argument carries everything a hook typically needs to decide:
Suggestion slug catalogue
Every suggestion carries a stable kebab-caseslug so hooks scope by suggestion identity instead of parsing the command string. The full catalogue:
Convention: every vanilla-
bazel alternate suggestion ends in -vanilla-bazel, so a single hook can suffix-match to scope across all producers without listing each slug.
Examples
Three production-grade examples, all currently shipping in theaspect-build/aspect-cli repo’s own .aspect/config.axl.
Rewrite aspect … to bazel … for one task
Useful when your repo has a tools/bazel wrapper and you want suggestions to use the bazel form so new contributors copy-paste a command that goes through the checked-in Bazel version.
.aspect/config.axl
Drop the vanilla-bazel alternate everywhere except one task
Built-in tasks tack on a vanillabazel run <target> suggestion next to their aspect … repros/fixes — a fallback for environments where the Aspect CLI isn’t on PATH. If your team always has aspect (or a tools/bazel wrapper that routes through it), those alternates are noise.
.aspect/config.axl
endswith("-vanilla-bazel") suffix match catches every current producer (format, gazelle, build, test) and any new ones added later.
Rewrite a description without touching the command
repro_fix_replace takes either field independently — passing only description keeps the existing command unchanged.
.aspect/config.axl
Order matters
Hooks run in registration order, and eachreplace verdict feeds the next hook in the chain. So if you register a rewrite hook and a reject hook, register the rewrite first — otherwise the reject may match on the original slug and short-circuit before the rewrite runs (or worse, on a rewritten slug the next hook can no longer recognize).
The slug is preserved across replace verdicts (hooks rewrite commands and descriptions, not suggestion identity), so slug-scoped hooks downstream of a replace still match correctly. But the rewritten command / description is what downstream hooks see.
How it fits into the lifecycle
apply_repro_fix_hooks runs automatically on every surface emit via the framework’s dispatch_task_update — no surface (CLI printer, Buildkite annotation, GitHub Status Check body, PR-comment rollup) ever renders an un-hooked entry. An idempotence flag on each ReproFixCommand makes repeated dispatches safe; each entry runs through the chain at most once even though every emit dispatches.
Hooks see the same suggestions every consumer sees, in the same order, so a rewrite or rejection flows through to every surface in lock-step.
See also
- How to run and define tasks — task fundamentals and the
task()definition surface. - Aspect Extension Language overview — what AXL is and why it’s typed Starlark.
tools/bazelwrapper — pairs naturally with the rewrite-to-bazelhook in the first example.

