Build from source
Most users should download a release. This page is for contributors, custom artifacts, and unreleased changes.
Get the source and build the application
Section titled “Get the source and build the application”Install JDK 25, then:
git clone https://github.com/bloxbean/yano.gitcd yano./gradlew :app:quarkusBuild -PskipSigning=truecd app./yano.sh start:devnetChoose the branch or tag containing the changes you want before building. For current namespace examples, use a checkout containing org.yanoproject; pre12 predates that rename.
The remaining commands build release-style distributions from the checked-out source tree.
Run commands from the repository root.
Prerequisites
Section titled “Prerequisites”- JDK 25.
- Docker with the Compose plugin for Docker distributions and container native builds.
- GraalVM 25 with
native-imagesupport for host native builds.
Use -PskipSigning=true for local builds that do not publish artifacts.
Artifact API Prefix
Section titled “Artifact API Prefix”The public REST prefix is fixed during Quarkus augmentation. The sole supported
build input is -PyanoApiPrefix=<path>; omitting it uses /api/v1. The value
is at most 256 characters and must be / or a canonical absolute path made of
unescaped [A-Za-z0-9._~-]+ segments, with no empty, . or .. segment or
trailing slash.
For example, build a JVM distribution whose API is rooted at /bf:
./gradlew :app:yanoDistZip -PyanoApiPrefix=/bf -PskipSigning=trueThe build generates literal REST configuration, reserves
quarkus.http.root-path=/, and emits both the raw
META-INF/yano-api-prefix-v1 marker and immutable
/ui/plugins/api-prefix.json from that value. Do not change
yano.api-prefix, quarkus.resteasy.path, or quarkus.http.root-path in
launch configuration. Runtime-style system properties or environment
variables for those keys are rejected during a build, and launch-time drift
aborts before node or plugin initialization. Changing the prefix always means
building a new JVM, native, or container artifact.
The packaged contract gate must pass independently for the default, a custom prefix, and the canonical root:
./gradlew :app:packagedApiPrefixContractSmoke -PskipSigning=true./gradlew :app:packagedApiPrefixContractSmoke -PyanoApiPrefix=/bf \ -PskipSigning=true./gradlew :app:packagedApiPrefixContractSmoke -PyanoApiPrefix=/ \ -PskipSigning=trueEach invocation builds and tests the matching artifact. The gate verifies its raw marker, dashboard discovery JSON, positive route, and fail-fast behavior for launch-time drift in either prefix property and the reserved HTTP root.
JVM Zip Distribution
Section titled “JVM Zip Distribution”Build the JVM zip:
./gradlew :app:yanoDistZip -PskipSigning=trueOutput:
app/build/distributions/yano-<version>.zipThe zip contains yano.jar, yano.sh, config files, network genesis files,
plugin directory scaffolding, and the JVM-only offline plugin catalog tool under
tools/yano-plugins/. It also contains the repository LICENSE and a normalized
CycloneDX 1.6 inventory at sbom/yano.cdx.json; packaging fails if an external
Maven component lacks license metadata.
After extracting the zip, start a network with the optional history archive by
composing the bundled projection profile after the network profile:
./yano.sh start:preprod,projection# or./yano.sh start:mainnet,projectionThe profile writes to DuckLake. The archive is fresh-sync only: it is built from genesis and there is no partial-coverage mode, so it needs an empty storage directory rather than an existing node’s. History is not supported by the native-image distribution.
After extracting the JVM zip, validate or inspect one or more plugin JARs without loading provider code:
./tools/yano-plugins/bin/yano-plugins validate plugins/example.jar./tools/yano-plugins/bin/yano-plugins inspect --format table plugins/example.jar./tools/yano-plugins/bin/yano-plugins inspect --format json plugins/example.jar# Windows: tools\yano-plugins\bin\yano-plugins.bat validate plugins\example.jarThe CLI is also available as a standalone application distribution:
./gradlew :plugin-catalog:distZip -PskipSigning=trueunzip plugin-catalog/build/distributions/yano-plugins-<version>.zip \ -d /tmp/yano-plugins/tmp/yano-plugins/yano-plugins-<version>/bin/yano-plugins validate plugin.jarSee plugin-catalog/README.md for policy options
and stable exit codes, and PLUGIN_OPERATIONS.md for
deployment authentication, health, metrics, and dashboard guidance.
Verify the final uber-JAR, its merged catalog/manifests, and JVM directory loading with the build-only conformance bundle:
./gradlew :app:packagedJvmPluginCatalogSmoke -PskipSigning=trueThis task intentionally uses the default
includeNativePluginConformanceFixture=false: the fixture must be absent from
the application index so startup can prove it was selected from the external
plugin directory. The task starts an isolated one-member app chain and asserts
all ten catalog contribution kinds (NodePlugin plus nine typed SPIs),
protected operations REST, the plugin health group, Prometheus metrics, and
dashboard assets. The fixture’s adversarial TCCL handoff also proves plugin
callbacks crossed catalog facades.
Native Zip Distribution
Section titled “Native Zip Distribution”Build a native zip for the current host platform:
./gradlew :app:yanoNativeDistZip \ -Dquarkus.native.enabled=true \ -Dquarkus.package.jar.enabled=false \ -PskipSigning=trueOutput:
app/build/distributions/yano-native-<version>-<platform>.zipExamples:
yano-native-0.1.0-pre4-macos-arm64.zipyano-native-0.1.0-pre4-linux-x64.zipyano-native-0.1.0-pre4-linux-arm64.zipThe zip contains the native yano executable, yano.sh, config files, and
network genesis files, plus the same LICENSE and release SBOM. It deliberately
has no plugin directory or
yano-plugins JVM runtime: native images cannot load JARs dynamically. Run the
standalone JVM CLI on a JDK 25 operator/build host when offline validation is
needed. Native Yano embeds only retained core providers. Optional Yano X state
machines, connectors, and products are supported by the JVM distribution, not
by augmenting the native build.
After the native zip task finishes, verify the final executable that it copied into the distribution:
./gradlew :app:nativePluginCatalogSmoke -PskipSigning=trueThe smoke task regenerates the current packaged-JVM index and compares both its
byte SHA-256 and selected-catalog fingerprint with the native executable’s
startup provenance record. This makes an executable built with different
plugin catalog inputs fail even if it starts and reports healthy; it is not a
digest of unrelated application code. The same rule applies to
-PyanoApiPrefix: pass the identical value to the
native build, distribution, and smoke commands. A native prefix cannot be
changed after image generation.
Use -PyanoNativeBinary=<path> only to verify another executable built from
the same catalog inputs. Release workflows always package first, smoke the
resulting app/build/yano (or yano.exe), and only then upload the zip; this
prevents a distribution-triggered native rebuild from replacing an executable
that was already tested.
Maintainers can additionally exercise native reachability for every typed app-chain plugin SPI with the non-published conformance fixture:
./gradlew :app:quarkusBuild \ -PincludeNativePluginConformanceFixture=true \ -Dquarkus.native.enabled=true \ -Dquarkus.package.jar.enabled=false \ -PskipSigning=true
./gradlew :app:nativePluginCatalogSmoke \ -PincludeNativePluginConformanceFixture=true \ -PskipSigning=trueThis property is a verification-only build input. Do not use the resulting
binary as a release artifact; the dedicated CI job neither publishes nor
packages it. The smoke starts an isolated one-member, no-peer app chain and
asserts all ten catalog contribution kinds (NodePlugin plus nine typed SPIs)
through structured status, protected operations REST, the plugin health group,
Prometheus metrics, and dashboard assets. It also retains the
catalog-provenance and ignored-directory-JAR checks.
Linux Native Zip From macOS
Section titled “Linux Native Zip From macOS”For a Linux native binary from macOS, use Quarkus container native build. This is useful when preparing a Linux Docker native context locally:
./gradlew :app:yanoNativeDistZip \ -Dquarkus.native.enabled=true \ -Dquarkus.package.jar.enabled=false \ -Dquarkus.native.container-build=true \ -Dquarkus.native.builder-image=container-registry.oracle.com/graalvm/native-image:25i3 \ -PskipSigning=trueWhen Oracle’s native-image builder is selected, Gradle adds --gc=G1 and sets the container workdir to /project.
Docker Compose Zip Distribution
Section titled “Docker Compose Zip Distribution”Build the Docker compose zip:
./gradlew :app:yanoDockerDistZip \ -PyanoDockerReleaseVersion=0.1.0-pre4 \ -PyanoDockerImageTag=0.1.0-pre4 \ -PskipSigning=trueOutput:
app/build/distributions/yano-docker-0.1.0-pre4.zipFor local Docker image testing, use a local image tag:
./gradlew :app:yanoDockerDistZip \ -PyanoDockerReleaseVersion=0.1.0-pre4 \ -PyanoDockerImageTag=local \ -PskipSigning=trueThe compose zip contains yano.sh, yano.bat, compose files, editable config/application.yml, editable config/network, logs, and plugins. Network-specific chainstate directories are created by the launcher on start or restart.
Docker Images
Section titled “Docker Images”Docker images are built from Gradle-prepared artifact contexts:
./gradlew :app:prepareYanoDockerJvmContext -PskipSigning=true./gradlew :app:prepareYanoDockerNativeContext \ -Dquarkus.native.enabled=true \ -Dquarkus.package.jar.enabled=false \ -Dquarkus.native.container-build=true \ -Dquarkus.native.builder-image=container-registry.oracle.com/graalvm/native-image:25 \ -PskipSigning=trueSee docker/BUILD_FROM_SOURCE.md for full Docker image build and smoke-test commands.
Smoke Tests
Section titled “Smoke Tests”Check zip contents:
unzip -l app/build/distributions/yano-*.zip | headunzip -l app/build/distributions/yano-native-*.zip | headunzip -l app/build/distributions/yano-docker-*.zip | headRun JVM distribution:
unzip app/build/distributions/yano-<version>.zip -d /tmp/yano-jvmcd /tmp/yano-jvm/yano-<version>YANO_AUTO_SYNC_START=false ./yano.sh startRun native distribution:
unzip app/build/distributions/yano-native-<version>-<platform>.zip -d /tmp/yano-nativecd /tmp/yano-native/yano-native-<version>-<platform>YANO_AUTO_SYNC_START=false ./yano.sh startRun Docker compose distribution with local images:
unzip app/build/distributions/yano-docker-<version>.zip -d /tmp/yano-dockercd /tmp/yano-docker/yano-docker-<version>./yano.sh config./yano.sh startcurl -fsS http://localhost:7070/q/health/ready./yano.sh stopStandalone console artifact
Section titled “Standalone console artifact”The normal node distribution includes its own UI where supported by the release. For a separately hosted console built from current source:
./gradlew :console-ui:consoleZipExtract console-ui/build/distributions/yano-console-ui-<version>.zip under the static server’s /ui path. See console hosting for API routing and CORS.