Getting Started

This walks through installing kwenza and building your first project. For the full field-by-field manifest schema, see Manifest Reference; for every command and flag, see Commands.

Prerequisites

  • A JDK, not just a JRE (kwenza compiles in-process via javax.tools.JavaCompiler, which needs a full JDK).

  • JDK 21 or newer to run kwenza itself. kwenza’s own kwenza.toml targets java-version = "21", and its own compiled classes require a JDK at least that new to load at all.

Projects you build with kwenza can target an older java-version than the JDK running kwenza — the constraint is only that the running JDK must be at least as new as whatever java-version is requested. See Architecture for why.

Installing kwenza

kwenza is self-hosting — once it exists, it rebuilds itself using itself. That means the very first jar has to come from somewhere else: a small bootstrap.sh script using plain javac/jar.

git clone https://github.com/kwenza-build/kwenza.git && cd kwenza
./bootstrap.sh

This produces .bootstrap/kwenza-bootstrap.jar — deliberately outside target/, so a later kwenza clean on this repo never deletes it. From here on, use kwenza to rebuild itself instead of re-running bootstrap.sh:

bin/kwenza package

bootstrap.sh only exists for this first build (or disaster recovery) — day-to-day, bin/kwenza package is how kwenza’s own source changes get rebuilt. bin/kwenza prefers the self-hosted target/kwenza-<version>.jar and only falls back to the bootstrap jar when that’s missing (e.g. right after kwenza clean), so you should never need to run bootstrap.sh a second time on the same checkout.

Put it on your PATH

echo 'export PATH="$PWD/bin:$PATH"' >> ~/.zshrc   # or wherever your shell profile lives

Restart your shell (or source the file), and kwenza is now just a command, usable from any project directory.

Your first project

Create a new directory with a kwenza.toml:

mkdir hello && cd hello
mkdir -p src/main/java/com/example
# kwenza.toml
[package]
name = "hello"
group = "com.example"
version = "0.1.0"
main-class = "com.example.Main"

[dependencies]
guava = { module = "com.google.guava:guava", version = "33.2.1-jre" }

See Manifest Reference for every field and its default.

// src/main/java/com/example/Main.java
package com.example;

import com.google.common.collect.ImmutableList;

public final class Main {
    public static void main(String[] args) {
        ImmutableList<String> items = ImmutableList.of("hello", "from", "kwenza");
        System.out.println(String.join(" ", items));
    }
}

Then:

kwenza run

The first run resolves guava and its transitive dependencies from Maven Central, caches them at ~/.m2/repository, writes kwenza.lock, compiles, and executes com.example.Main. Every subsequent kwenza run/build/package reuses the lock — no network access — until `kwenza.toml’s dependencies actually change.

To produce a runnable jar instead of just executing in place:

kwenza package
java -jar target/hello-0.1.0.jar

Where to go next

  • A complete, working example (this same walkthrough, already set up) lives at examples/hello-world.

  • Manifest Reference covers every kwenza.toml field and the kwenza.lock format.

  • Commands has a page for every command, and kwenza(1) covers what they share: chaining, global flags and environment variables.

  • Architecture explains how resolution, compilation, and packaging work under the hood.