Skip to main content
A build tool for Java, Kotlin & Scala

Compile. Test. Sourcegen.
That’s the build. Everything else is code.

Two decades of Maven, Gradle, and sbt is a long time to watch build tools grow incredibly complex. We built one that won’t. Bleep does precisely what a build is for: compile, test, sourcegen, then package, link, publish what comes out. It refuses the rest. Your container build is code you write. So is your doc generation, your sidecar boot, your CI orchestration. All of it.

That simplicity turns out to matter most to the newest thing reading your build. Bleep is the best build tool for agentic development: fast enough that every agent can have its own checkout, and quiet enough that none of them drown in build output.

CLI startup10 msnative binary, no JVM
a fresh checkout, ready268 54 sbuilt from scratch, or cloned from a sibling — 5.1M lines
what an agent reads25265tokens, where mvn test spends 31,000
build files1plain YAML, whole repo
Build-as-data

The build is data, not a program.

A real bleep.yaml. Not pseudocode. Not a marketing render. Plain YAML you can read, grep, diff, and rewrite. The same model bleep itself uses. And because it’s data, your agent can read it in one pass, edit it safely, and verify the result — try that with a build script. The YAML is just the first layer: the same discipline runs through the whole tool, all the way to build runs you can diff.

your-first-kotlin-project
$schema: https://raw.githubusercontent.com/oyvindberg/bleep/master/schema.json
$version: 1.0.0-M12
jvm:
name: graalvm-community:25.0.1
projects:
myapp:
extends: template-common
platform:
mainClass: com.example.MainKt
myapp-test:
dependencies: io.kotest:kotest-runner-junit5-jvm:6.2.3
dependsOn: myapp
extends: template-common
isTestProject: true
templates:
template-common:
kotlin:
jvmTarget: '25'
version: 2.4.10
platform:
name: jvm
What's first-class today

Per-language maturity.

What works, what's partial, what's not in scope yet. Compile, test, run, publish, BSP, cross-build, scripts and sourcegen are first-class for every language.

Java

First-class: javac and ECJ, annotation processors (Lombok, MapStruct, Dagger, Immutables, …), Spring Boot via bleep-plugin-spring-boot, Maven import.
Partial: BOM / dependencyManagement not yet, every dependency declares its own version explicitly.
Not in scope: Android.

Kotlin

First-class: kotlinc 2.x, compiler plugins (allopen, jpa, spring, noarg, serialization), KSP processors (Room, Hilt, Moshi codegen, Koin KSP, kotlinx.serialization KSP variant, kotlin-inject, …), Kotlin/JS via cross:.
Partial: KSP runs from scratch each compile, per-file change tracking is a planned follow-up. Kotlin/Native targets exist but the ecosystem expects Gradle. No Gradle import yet — hand-port today.
Not in scope: KAPT (migrate to KSP), Android.

Scala

First-class: Scala 2.13 + Scala 3 cross-builds, Scala.js, Scala Native, scalafmt, scalafix, Zinc incremental, sbt import, ports of sbt-ci-release / sbt-sonatype / sbt-pgp / sbt-dynver / sbt-native-image / mdoc.
Partial: projectMatrix-style third axes, per-minor-Scala-version overrides; the cross-build model covers JVM × {2.13, 3} × {JVM, JS, Native} but not arbitrary fourth dimensions.
Not in scope: publishing as an sbt plugin artifact (consuming sbt plugins works).

The simplification

Four things we cut.

A project is a project is a project. Code is code is code. Everything explicit, everything simple. Here’s how we got there.

Simplification

No code in the build file.

A build file describes a project. It doesn’t run one. bleep.yaml is data: readable top to bottom by anyone on the team. Logic lives in your code, in your repo, where you can git blame it.

Simplification

No build plugins.

No autoplugins, no requires graphs, no Plugin<Project> registration. Bleep doesn’t have one. Code goes in your repo, where you can read it.

Simplification

No project scopes.

A test project is a project. A scripts project (your build code) is a project. Your production app is a project. Same fields, same dependency model, same bleep compile and bleep test, no second category. No Test/test/itTest/Compile scope dance grafted onto the project graph. A project is a project is a project.

Simplification

No task graph.

There’s no user-definable task DAG. The build does compile, test, sourcegen. Everything else is a script: a main class you call when you want to. Composable like programs, debuggable like programs, no special layer between you and the JVM.

What about build plugins?

Code, not build plugins.

Two integration points cover what build plugins ever did. Most of that didn’t belong in the build to begin with.

A build plugin is a black box.

Rules you don’t write, settings you can’t see, order you don’t control. Debugged with println.

Most plugin work isn’t build work.

Signing, containers, docs, CI glue: distribution. None of it runs when you save a file; none of it needs to be coupled to compile and test. Write a script, run it when you want it.

Two patterns cover the rest.

Bring a build plugin’s logic into bleep and it becomes one of two things.

  • Generates files the compiler reads → the build runs it as sourcegen before compile.
  • Operates on what compile produced → you run it after.

We verified this model three ways: by analyzing each of the top 50 Maven plugins, by implementing the hardest case (Spring Boot), and by shipping codebases of millions of lines on it.

The payoff

Built for the inner loop.

Cut the code, the build plugins, the scopes, the task graph, and the inner loop stops being something you wait for. The numbers below are measured on the repo bleep’s authors work in daily — 4.9M lines of Java and 169k of Scala across 132 projects — and we can re-measure them any day, because the build records its own runs. It matters more than ever, too: DORA’s 2025 report found AI multiplies whatever loop you already have. Fast feedback turned agents into real gains. Slow feedback got a faster way to wait.

Load everything in 10 ms

Native CLI binary. Reads bleep.yaml, resolves dependencies through Coursier’s local cache, builds the full project model — all 132 projects, done in ten milliseconds, before a JVM would have finished saying hello. No configuration phase, no “loading projects…” progress bar. The compile daemon (bleep-bsp) is the JVM-heavy bit, and it stays hot between invocations.

IDE imports & reloads

Open a project the first time. Switch a branch with a different Kotlin version and reload. In Gradle or sbt that’s a configuration phase, plugin loading, dep resolution, and IDE model rebuild: minutes on real projects. Bleep reads bleep.yaml, builds the BSP model, syncs to the IDE. Initial import: a second or two. Branch reload: milliseconds.

Incremental compile

One file changed in a 200-class module. Maven recompiles all 200, slowly. Bleep does file-level incremental compilation: one file changed, one (or two) recompiled, in milliseconds. And asking the big question — is everything still green? — costs 9 seconds across all 132 projects and 5.1 million lines. That is the whole tax for asking.

Tests

A test runner that shows its work.

Nine minutes of test work, done in one. That is bleep testing itself below — 86 suites, 439 tests, integration builds and all, green in 60 seconds. Suites compile and run in parallel across every CPU, and you watch it happen: which suite is running, which just failed, the moment it fails. No staring at a dead terminal wondering how far along it is.

Massively parallel

Test suites run in forked JVMs across every available CPU. Each test project gets its own classpath, its own JVM, its own lifecycle. The bottleneck is your hardware, not the build tool.

Live TUI

The terminal shows which suites are compiling, which are running, which finished, which failed. Failures land the instant they happen, not at the end of the run. Pass --no-tui for plain CI logs.

Precise summary

Exact suite and test names, pass/fail counts per project, and the failures written out with their assertions — short enough to act on without scrolling. --diff narrows it to what changed since your last run, and JUnit XML is one flag away.

CI

Stupidly fast CI.

The same simplification pays off again at CI scale. Build only what changed, pull the rest from cache: two commands, and your CI bill stops being a thing you complain about.

Skip what hasn’t changed

bleep build invalidated loads the build at two git refs, digests each project from config plus sources plus transitive deps, and prints the ones that differ. Both loads are instant because the build is data and dependency resolution is cached. Scope the rest of your CI run to those projects. Everything else is already green from the last build.

Pull what someone else built

bleep remote-cache push uploads compile outputs to S3, keyed by a SHA-256 over config plus sources plus transitive deps. bleep remote-cache pull fetches them on the next run. Skip the compile entirely for projects that haven’t changed.

Explicit, on purpose

No transparent freshness checks across the network. You push when you want a cache populated, you pull when you want to use it. The fail-hard error model stays clean, your CI logs stay grep-able — and agents benefit most of all: nothing degrades silently, so there’s nothing to chase.

Self-editing

Read it. Change it. Write it back.

Build-as-data has one more payoff: bleep can rewrite its own input. update-deps, project-rename,templates-reapply: each reads the file, transforms the model, writes it back. No DSL to interpret, no build plugin lifecycle to mutate, just a small library of commands operating on the same model bleep itself uses.

Inspectshow · diff · invalidated · evicted
Agentic development

The best build tool for agents.

An orchestrator, a handful of subagents, each one off in its own git worktree — that is what a working day looks like now. The build is what makes it expensive: every fresh worktree starts cold, and on a big codebase that is minutes of nothing, per agent, every time. Bleep collapses that price. A new worktree clones the parent’s compiled state and hits verified green in 54 seconds on 5.1 million lines, against 4 min 22 s cold. Spawn six agents and the sixth starts as fast as the first.

Below, two subagents go into fresh worktrees. One seeds itself, one doesn’t, and bleep times them both. The prompt is in the repo. Seeding costs 71 ms; the cold worktree’s first compile then takes 3529 ms against the seeded one’s 585 ms. The model never does that arithmetic — it asks bleep, and bleep reads both runs back out of its own history. Toy build, so it fits on camera; the same mechanism is what turns 4 min 22 s into 54 s on 5.1 million lines.

Then there is what it costs to ask. Maven and Gradle bury an agent in output so reliably that agent companies ship wrappers whose whole job is stopping build logs from shredding context. Bleep just answers in sentences.

25–265 tokensmeasured over the live MCP server: a green compile answers in 25, a failing test with its full what-changed diff in 265. A raw build log runs to tens of thousands, and every one of them costs the agent attention it could spend on your code.

And because every run is written down as a file, an agent can ask what changed instead of reading everything again. That is a loop other build tools cannot offer at any token price.

agentbreaks a test, reruns — diffBase pinned to the last green run
bleep.test { directory: ~/repo/wt/api, diffBase: 18 }{ failed: 1, diff: { summary: "1 newlyFailing", test: "PricingTest.10 percent off at 100 and above", message: "expected 216, obtained 204" } } ← the run and what changed, in one call
agentreverts, reruns
bleep.test { directory: ~/repo/wt/api, diffBase: 18 }{ passed: 14, diff: { identical: true } } ← 800ms of timing noise between the runs, zero false diffs

Forks start warm

One bleep.copy-state call clones the parent’s compiled state, safely, even mid-compile. One daemon serves every checkout, so ten worktrees don’t cost ten JVMs. Recipe and numbers.

Answers, not logs

Counts, the first errors, an id — and failures stream the moment they happen. Want the detail? history.show greps the stored run server-side and hands back the matching lines.

Ask what changed

history.diff compares any two runs — newly failing, fixed, new and resolved diagnostics — and diff-timing answers what got slower. Durations never enter the logical diff, so a busy laptop can’t invent a difference.

We build bleep this way every day: parallel agents in git worktrees, building bleep with bleep.

Getting in, getting out

The door swings both ways.

Adopting a build tool is a bet, so bleep works to make it a small one. bleep import reads an sbt build, bleep import-maven a Maven one, and writes the equivalent bleep.yaml — project graph derived, templates inferred from whatever repeats. You should be compiling and testing after one command. And when you want out, bleep export-maven walks the same model the other way and writes POMs.

One command in

bleep import for sbt, bleep import-maven for Maven. Multi-module reactors included: the project graph is derived, repeated configuration lifted into templates, and compile and test run immediately. Watch one.

One command out

bleep export-maven is a script, not a product: it walks the build model and writes POMs. Run against bleep’s own build, every module compiles and the tests pass under stock Maven — source generators included.

Worst case, you hold data

Your build is portable YAML and plain Maven coordinates. No plugin state, no tool-internal database, nothing that exists only inside bleep. Betting on a young tool should never mean betting the repo.

Neither direction is magic, and we would rather say so than have you find out on day three. Import gets you green and then leaves the parts that were always going to need a person: source generation arrives as a frozen snapshot that works immediately and goes stale the day your schemas change, so you replace it with a real sourcegen script — usually tens of lines. Coming from Gradle there is no importer at all yet; that is a hand-port. Export has its own edges: publish configuration does not translate, and the integration suites that drive bleep’s own compile server cannot run under Maven. What both directions do give you is a build that compiles and tests on the other side, which is the hard part.

Stop fighting your build

Two lines. One file. Get on with your day.

Bleep is open source under the MIT licence. Java, Kotlin, and Scala on the JVM. Cross-build to JS and Native if you want. Or don’t. The second line gives every agent on your machine a build tool that answers in 265 tokens or fewer.

$curl -fsSL https://bleep.build/install | sh
$claude mcp add --scope user bleep -- bleep mcp-server