> ## Documentation Index
> Fetch the complete documentation index at: https://aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Extend Bazel with AXL, the Aspect Extension Language

> Write Bazel tasks in AXL, a Starlark dialect, and run the same command locally and on CI. Free with the Aspect CLI, with built-in format, lint, and delivery tasks.

export const MarketingPage = () => <div className="marketing-page-marker" style={{
  display: "none"
}} />;

export const CTA = ({title, subtitle, primaryCta, primaryHref = "#", secondaryCta, secondaryHref = "#"}) => <section className="w-full flex justify-center px-4 py-16 md:py-20">
    <div className="w-full rounded-2xl text-white flex flex-col md:flex-row items-center justify-center gap-10 md:gap-16 p-8 md:p-12 text-center md:text-left" style={{
  maxWidth: "1140px",
  background: "linear-gradient(135deg, #1a3a5c 0%, #176ACC 100%)"
}}>
      <div>
        <h2 className="text-2xl md:text-3xl font-semibold tracking-tight">{title}</h2>
        {subtitle && <div className="mt-3 text-blue-100 text-base">{subtitle}</div>}
      </div>
      <div className="flex flex-wrap gap-3 shrink-0 justify-center">
        {primaryCta && <a href={primaryHref} className="inline-flex items-center px-6 py-3 rounded-lg bg-white text-blue-700 font-semibold hover:bg-blue-50 transition whitespace-nowrap shadow-sm">
            {primaryCta}
          </a>}
        {secondaryCta && <a href={secondaryHref} className={`inline-flex items-center px-6 py-3 rounded-lg border border-blue-300/50 text-white font-semibold hover:bg-blue-700/30 transition whitespace-nowrap ${secondaryHref === "/request-demo" ? "demo-gradient-btn" : ""}`}>
            {secondaryCta}
          </a>}
      </div>
    </div>
  </section>;

export const FeatureCard = ({title, description, href, children}) => {
  const Tag = href ? "a" : "div";
  const tagProps = href ? {
    href
  } : {};
  return <Tag {...tagProps} className={`group flex flex-col p-6 rounded-xl border border-zinc-200 dark:border-zinc-700/60 bg-white dark:bg-zinc-800/50 ${href ? "hover:shadow-md hover:border-blue-200 dark:hover:border-blue-700 transition-all duration-200" : ""}`}>
      {children && <div className="feature-card-icon mb-5 flex items-center justify-center rounded-xl bg-blue-50 dark:bg-blue-900/20 border border-blue-100 dark:border-blue-800/30" style={{
    width: "4rem",
    height: "4rem"
  }}>
          {children}
        </div>}
      <h3 className={`text-lg font-semibold text-zinc-900 dark:text-white ${href ? "group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors" : ""}`}>
        {title}
      </h3>
      {description && <p className="feature-card-desc text-sm text-zinc-500 dark:text-zinc-400 leading-relaxed">{description}</p>}
    </Tag>;
};

export const FeatureGrid3 = ({children}) => <div className="marketing-grid-3">{children}</div>;

export const SectionHeader = ({title, subtitle, centered = true, label}) => <div className={`mb-12 ${centered ? "text-center" : ""}`}>
    {label && <p className="text-xs font-semibold tracking-widest text-blue-600 dark:text-blue-400 uppercase mb-3">
        {label}
      </p>}
    <h2 className="text-3xl md:text-5xl font-semibold text-zinc-900 dark:text-white tracking-tight">{title}</h2>
    {subtitle && <div className={`subtitle-gap text-lg md:text-xl text-zinc-500 dark:text-zinc-300 leading-relaxed ${centered ? "mx-auto" : ""}`} style={{
  marginTop: "1rem",
  maxWidth: centered ? "700px" : "none"
}}>
        {subtitle}
      </div>}
  </div>;

export const Section = ({children, className = "", gray = false, dark = false, id}) => <section id={id} className={`w-full flex justify-center px-4 py-16 md:py-24 ${gray ? "bg-gray-50 dark:bg-zinc-900" : dark ? "bg-zinc-900 dark:bg-zinc-950" : ""} ${className}`}>
    <div className="w-full" style={{
  maxWidth: "1140px"
}}>
      {children}
    </div>
  </section>;

export const Hero = ({title, subtitle, badge, eyebrow, heroImageClassName = "", primaryCta, primaryHref = "#", secondaryCta, secondaryHref = "#", note, centered = true, children}) => <section className="w-full flex justify-center px-4 pt-16 pb-16 md:pt-24 md:pb-24" style={{
  background: "linear-gradient(180deg, var(--hero-gradient-start, #f8fafc) 0%, var(--hero-gradient-end, #ffffff) 100%)"
}}>
    <div className="w-full" style={{
  maxWidth: "1140px"
}}>
      {centered && !children ? <div className="flex flex-col items-center text-center">
          {badge && <div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-700 text-blue-700 dark:text-blue-300 text-sm font-medium mb-6">
              {badge}
            </div>}
          {eyebrow && <div className="text-xs font-semibold tracking-widest uppercase text-blue-600 dark:text-blue-400 mb-4">
              {eyebrow}
            </div>}
          <h1 className="text-4xl md:text-5xl font-semibold text-zinc-900 dark:text-white leading-tight tracking-tight" style={{
  maxWidth: "820px"
}}>
            {String(title).split(/\\n|\n/).map((line, i) => i ? [<br key={i} />, line] : line)}
          </h1>
          {subtitle && <div className="subtitle-gap text-lg md:text-xl text-zinc-500 dark:text-zinc-300 leading-relaxed" style={{
  marginTop: "1rem",
  maxWidth: "600px"
}}>
              {subtitle}
            </div>}
          {(primaryCta || secondaryCta) && <div className="flex flex-wrap gap-3 mt-10 justify-center">
            {primaryCta && <a href={primaryHref} className="inline-flex items-center px-6 py-3 rounded-lg bg-blue-600 text-white font-semibold hover:bg-blue-700 transition shadow-sm">
                {primaryCta}
              </a>}
            {secondaryCta && <a href={secondaryHref} className={`inline-flex items-center px-6 py-3 rounded-lg border border-zinc-300 dark:border-zinc-600 text-zinc-700 dark:text-zinc-200 font-semibold hover:bg-zinc-50 dark:hover:bg-zinc-800 transition ${secondaryHref === "/request-demo" ? "demo-gradient-btn" : ""}`}>
                {secondaryCta}
              </a>}
          </div>}
          {note && <div className="mt-4 text-sm text-center text-zinc-500 dark:text-zinc-400">{note}</div>}
        </div> : <div className="flex flex-col md:flex-row items-center gap-10 md:gap-16">
          <div className="flex-1 min-w-0">
            {badge && <div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-700 text-blue-700 dark:text-blue-300 text-sm font-medium mb-6">
                {badge}
              </div>}
            {eyebrow && <div className="text-xs font-semibold tracking-widest uppercase text-blue-600 dark:text-blue-400 mb-4">
                {eyebrow}
              </div>}
            <h1 className="text-4xl md:text-5xl font-semibold text-zinc-900 dark:text-white leading-tight tracking-tight">
            {String(title).split(/\\n|\n/).map((line, i) => i ? [<br key={i} />, line] : line)}
          </h1>
            {subtitle && <div className="subtitle-gap text-lg md:text-xl text-zinc-500 dark:text-zinc-300 leading-relaxed" style={{
  marginTop: "1rem"
}}>
                {subtitle}
              </div>}
            <div className="flex flex-wrap gap-3 mt-8">
              {primaryCta && <a href={primaryHref} className="inline-flex items-center px-6 py-3 rounded-lg bg-blue-600 text-white font-semibold hover:bg-blue-700 transition shadow-sm">
                  {primaryCta}
                </a>}
              {secondaryCta && <a href={secondaryHref} className={`inline-flex items-center px-6 py-3 rounded-lg border border-zinc-300 dark:border-zinc-600 text-zinc-700 dark:text-zinc-200 font-semibold hover:bg-zinc-50 dark:hover:bg-zinc-800 transition ${secondaryHref === "/request-demo" ? "demo-gradient-btn" : ""}`}>
                  {secondaryCta}
                </a>}
            </div>
            {note && <div className="mt-4 text-sm text-zinc-500 dark:text-zinc-400">{note}</div>}
          </div>
          {children && <div className={`flex-1 min-w-0 hero-image ${heroImageClassName}`}>
              {children}
            </div>}
        </div>}
    </div>
  </section>;

<MarketingPage />

<Hero eyebrow="Aspect Extension Language" title={"Make Bazel work\nthe way your team does."} subtitle="Write your repo's tasks in Starlark: real commands with flags and help that drive Bazel's build and events." primaryCta="Install the CLI" primaryHref="/docs/cli/install" secondaryCta="Read the docs" secondaryHref="/docs/cli/guides/basic" centered={false}>
  <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/marketing/product/axl-img.avif?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=1ba18616087f5f7414073fc3bbc50ceb" alt="Aspect Extension Language" width="1292" height="720" data-path="images/marketing/product/axl-img.avif" />
</Hero>

<Section>
  <div className="flex flex-col md:flex-row-reverse items-center gap-12" style={{ columnGap: "5rem" }}>
    <div className="flex-1">
      <h2 className="text-3xl md:text-4xl font-semibold text-zinc-900 dark:text-white">Write your own in minutes</h2>

      <p className="mt-4 text-lg text-zinc-600 dark:text-zinc-300">
        A custom task is a Starlark function. Drop an <code>.axl</code> file into your repo's <code>.aspect/</code> directory and it auto-registers as a real CLI command, listed in <code>aspect help</code> next to the built-ins.
      </p>

      <p className="mt-4 text-lg text-zinc-600 dark:text-zinc-300">
        Tasks get typed arguments, Bazel's build and query engines, build event streams, and a standard library. No wrapper scripts, no YAML contortions.
      </p>

      <div className="mt-8 flex flex-col gap-3">
        <a href="/docs/cli/guides/basic" className="text-blue-600 dark:text-blue-400 font-semibold hover:underline">Write your first task →</a>
        <a href="/docs/cli/guides/module" className="text-blue-600 dark:text-blue-400 font-semibold hover:underline">Share tasks across repos with MODULE.aspect →</a>
        <a href="/docs/cli/guides/build-events" className="text-blue-600 dark:text-blue-400 font-semibold hover:underline">React to build events →</a>
        <a href="/docs/cli/guides/delivery-manifest" className="text-blue-600 dark:text-blue-400 font-semibold hover:underline">Hook the delivery manifest →</a>
      </div>
    </div>

    <div className="w-full min-w-0" style={{ flex: "1.5 1 0%" }}>
      ```python title=".aspect/mycmd.axl" theme={null}
      def impl(ctx: TaskContext) -> int:
          events = bazel.build_events.iterator()
          build = ctx.bazel.build(
              build_events = [events],
              *ctx.args.target_pattern,
          )

          for event in events:
              if event.kind == "named_set_of_files":
                  for f in event.payload.files:
                      ctx.std.io.stdout.write("Built {}\n".format(f.name))

          return build.wait().code

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

      <p className="mt-3 text-sm text-zinc-500 dark:text-zinc-400 text-center font-mono">\$ aspect mycmd //services/...</p>
    </div>
  </div>
</Section>

<Section gray>
  <SectionHeader title="Why AXL" />

  <div className="max-w-2xl mx-auto text-center space-y-4 mb-12">
    <p className="text-lg font-semibold text-zinc-700 dark:text-zinc-300">
      Bazel is fast, scalable, and battle-tested in the enterprise.
    </p>

    <p className="text-lg text-zinc-600 dark:text-zinc-300">
      But anyone who's used it knows: some important workflows are missing, awkward, or just not adapted to your organization. So teams bury them in shell scripts and Makefiles that drift, break, and behave differently on every machine.
    </p>

    <p className="text-lg font-semibold text-zinc-700 dark:text-zinc-300">
      The usual suspects:
    </p>
  </div>

  <FeatureGrid3>
    <FeatureCard title="Formatting" description="One command that formats every language in the repo, the same way on every machine." href="/docs/cli/tasks/format">
      <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/marketing/icons/Formatting.svg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=e5951ee7e92fe23b8eb79b0d2c96af93" alt="" width="48" height="48" data-path="images/marketing/icons/Formatting.svg" />
    </FeatureCard>

    <FeatureCard title="Linting" description="Run every configured linter across the build graph, with machine-applicable fixes." href="/docs/cli/tasks/lint">
      <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/marketing/icons/Linting.svg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=3bfc20666b4b77e26bb1027a52d6075c" alt="" width="48" height="48" data-path="images/marketing/icons/Linting.svg" />
    </FeatureCard>

    <FeatureCard title="Release automation" description="Stamp artifacts and push them to your registries and buckets. Scripted release trains become one task." href="/docs/cli/tasks/delivery">
      <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/marketing/icons/Release-automation.svg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=fe6347df8f3a3ea7edf4ddff8d6716fc" alt="" width="48" height="48" data-path="images/marketing/icons/Release-automation.svg" />
    </FeatureCard>

    <FeatureCard title="Test reporting" description="Live status checks, annotations and uploaded test logs in CI instead of scrolling raw logs." href="/docs/cli/tasks-ci">
      <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/marketing/icons/Test-reporting.svg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=645b8801b1504d458c831a6ec036ec59" alt="" width="48" height="48" data-path="images/marketing/icons/Test-reporting.svg" />
    </FeatureCard>

    <FeatureCard title="Coverage" description="Collect coverage across languages and publish it where your team actually looks." href="/docs/cli/guides/coverage">
      <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/marketing/icons/Coverage.svg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=306ae317088aaa2ae5630a60ec44bdba" alt="" width="48" height="48" data-path="images/marketing/icons/Coverage.svg" />
    </FeatureCard>

    <FeatureCard title="BUILD file generation" description="Keep BUILD files in sync with the source, and write your own generators in Starlark instead of Go." href="/docs/cli/guides/gazelle">
      <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/marketing/icons/Build_1.svg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=21cbc19b2d6e86104cc5db65b8f643df" alt="" width="32" height="32" data-path="images/marketing/icons/Build_1.svg" />
    </FeatureCard>
  </FeatureGrid3>

  <div className="max-w-2xl mx-auto text-center space-y-4 mt-12">
    <p className="text-lg text-zinc-600 dark:text-zinc-300">
      AXL replaces that scripting layer with tasks: first-class, programmable commands that ship with the <a href="/tools/cli" className="text-blue-600 dark:text-blue-400 font-semibold hover:underline">Aspect CLI</a> or are written by your team, in one language, with Bazel's APIs at hand.
    </p>
  </div>
</Section>

<Section>
  <SectionHeader title="A dialect of Starlark" subtitle="AXL is the same language Bazel itself is configured in. That means extensions are:" />

  <FeatureGrid3>
    <FeatureCard title="Familiar" description="If you've ever read a BUILD file or a Bazel rule, AXL is readable on day one. No new language to learn, no plugin SDK to master." />

    <FeatureCard title="Typed and configurable" description="Tasks declare typed arguments, and the repo sets their defaults in .aspect/config.axl, so nobody has to remember the right flags." />

    <FeatureCard title="Composable" description="Tasks drive Bazel's build, test, and query APIs directly, and share code across repositories as versioned AXL modules." />
  </FeatureGrid3>

  <div className="max-w-2xl mx-auto text-center mt-10">
    <a href="/tools/cli" className="text-blue-600 dark:text-blue-400 font-semibold hover:underline">
      The Aspect CLI's built-in tasks run on the same AXL machinery. See them →
    </a>
  </div>
</Section>

<Section gray>
  <SectionHeader title="The same task, everywhere" subtitle="Run the same command locally and on CI. No CI-specific wrappers to maintain." />

  <FeatureGrid3>
    <FeatureCard title="Any CI system" description="Invoke tasks from plain CI YAML on GitHub Actions, CircleCI, GitLab, or Buildkite. The CLI detects the CI environment and adapts." href="/docs/cli/tasks-ci" />

    <FeatureCard title="CI-aware by default" description="Set one API token to unlock GitHub status checks, Buildkite annotations, and GitLab job annotations. Without it, tasks still run normally." href="/docs/cli/tasks-ci" />

    <FeatureCard title="Supercharged on Workflows" description="Aspect Workflows runners back your builds with remote caching, remote execution, and pre-warmed NVMe output bases, applied to vanilla bazel and aspect tasks alike. Tasks auto-detect the environment for zero-config setup. On Aspect Cloud, aspect build --remote uses the shared cache." href="/platform/ci-runners" />
  </FeatureGrid3>
</Section>

<CTA title="Extend Bazel with AXL" subtitle="AXL ships with the Aspect CLI, free for every developer." primaryCta="Install the CLI" primaryHref="/docs/cli/install" secondaryCta="Cache your builds free on Aspect Cloud" secondaryHref="https://signup.aspect.build/" />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.