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.

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.

your-first-kotlin-project
$schema: https://raw.githubusercontent.com/oyvindberg/bleep/master/schema.json
$version: 1.0.0-M9
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:5.8.0
- org.junit.jupiter:junit-jupiter:5.10.1
dependsOn: myapp
extends: template-common
isTestProject: true
templates:
template-common:
kotlin:
jvmTarget: '25'
version: 2.3.0
platform:
name: jvm
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. The inner loop stops being something you wait for.

Load everything in milliseconds

Native CLI binary. Reads bleep.yaml, resolves dependencies through Coursier’s local cache, builds the full project model. Done. No JVM startup, 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. The save-to-result loop stays tight.

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.

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
Tests

A test runner that shows its work.

Failures show up the moment they happen. Suites compile and run in parallel across every CPU, the terminal stays live, and the summary at the end is short enough to act on. No two-minute pause. No fifty-thousand-line transcript.

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

When the run ends, you get exact suite and test names, pass/fail counts per project, and the diff against the previous run, not a wall of stdout you have to grep through. JUnit XML is one flag away (--junit-report).

Tooling for the future

Built for the agents.

Claude Code, Cursor, and the next generation of dev tools talk to bleep through MCP, the Model Context Protocol. One command (bleep setup-mcp-server) and an agent can compile, test, run, and inspect your build through 18 structured tool calls. The design assumptions are blunt: more than one agent will be running at once, tokens are scarce, and any tool that takes seconds blocks every agent attached to it.

Performance

Four parallel agents on the same build mean four parallel tool calls. If the build tool is slow, every one of them stalls, aggregate latency multiplies. Bleep’s MCP server runs in-process against the BSP daemon. Every call is sub-second after warmup, sub-100ms once warm.

Ease

bleep setup-mcp-server writes.mcp.json in your build root. Any MCP client picks it up automatically. No adapter to configure, no protocol to translate, bleep speaks MCP natively.

Structured output

Every tool returns a compact JSON summary by default : error counts, failure suites, the diff against the previous run. Full diagnostics are one extra call away. Per-project errors stream as MCP notifications the instant a project finishes, not at the end. Latency floor for surfacing a real problem: milliseconds.

Already have a project?

Import Maven and sbt. One command.

Bleep reads your existing build and writes the equivalent bleep.yaml. Project graph derived, dependencies preserved, common configuration lifted into templates. You should have a compiling, testing build after one command.

One command in

bleep import for sbt projects, bleep import-maven for Maven. Both load your existing build, derive the project graph, infer templates from repeated configuration, and write bleep.yaml. Compile and test run immediately.

Codegen carries over as a stub

Import takes the generated files it finds on disk and freezes them as static sourcegen output. Compile works on day one. But once your schemas, grammars, or templates change, the frozen output is stale; you write a real sourcegen script then, calling the generator (protoc, antlr, openapi-generator, JAXB) directly. Typically tens of lines.

Coming from Gradle? Gradle import may come later; hand-porting is the path today.

Stop fighting your build

One line. One file. Get on with your day.

Bleep is open source under Apache 2.0. Java, Kotlin, and Scala on the JVM. Cross-build to JS and Native if you want. Or don’t.

$curl -fsSL https://bleep.build/install | sh