Build and Features

TKeeper has two build-time selectors:

  • features: product surface such as authorities, ECIES, UI, and seal providers
  • platforms: cryptographic algorithms and protocols

A usable production artifact must include at least one platform.

Build default production modules

./gradlew build -Pkeeper.features=all -Pkeeper.platforms=all

build runs the root and SDK tests plus the unit tests of every selected feature and platform module before producing the artifact.

The root build task runs the normal verification lifecycle and produces the deployable fat jar through shadowJar.

Equivalent:

./gradlew :build -Pkeeper.features.all=true -Pkeeper.platforms.all=true

The jar lands under:

build/libs/tkeeper-2.5.0.jar

TKeeper requires Java 25.

Build a smaller artifact

Example: EVM signing, ECIES, and the UI:

./gradlew :build -Pkeeper.features=evm,ecies,ui -Pkeeper.platforms=ecc

Example: ML-DSA only:

./gradlew :build -Pkeeper.platforms=pqc

Feature names match child project names. :features:digital-assets:evm is selected with evm. Use digital-assets for Bitcoin, EVM, Tron, XRP, and Solana, and agentic-payments for both AP2 and MC VI:

./gradlew :build -Pkeeper.features=agentic-payments,digital-assets -Pkeeper.platforms=ecc

The earlier authority-bitcoin and authority-evm selectors remain accepted.

Select a native OS/CPU target

keeper.platforms selects cryptographic modules (ecc and pqc). The separate target property selects native libraries packaged into the production fat jar. By default, target=all keeps native binaries for every bundled OS/CPU combination and produces build/libs/tkeeper-2.5.0.jar.

Build the complete feature set for a Linux amd64 host with a smaller jar:

./gradlew shadowJar -Pkeeper.features=all -Pkeeper.platforms=all -Ptarget=linux-amd64

The output is build/libs/tkeeper-2.5.0-linux-amd64.jar. To keep every bundled native variant, use -Ptarget=all or omit target:

./gradlew shadowJar -Pkeeper.features=all -Pkeeper.platforms=all -Ptarget=all
target Output classifier
all (default) none
linux-amd64 linux-amd64
linux-arm64 linux-arm64
macos-amd64 macos-amd64
macos-aarch64 macos-aarch64
windows-amd64 windows-amd64

Targeted jars keep only the matching RocksDB, Netty, gRPC Netty, Conscrypt, Zstd, Jansi, GMP, secp256k1, and libsodium native files that are bundled by the dependencies. Java classes and selected features remain the same. The integration and production test jars always retain their full native set, regardless of target.

On Linux arm64 and macOS amd64, GMP and libsodium are loaded from the system; secp256k1 is also loaded when ecc is selected. At startup Keeper tries the bundled libraries first, then calls System.loadLibrary for any that are absent. Install these shared libraries where the JVM can find them (for example via -Djava.library.path). The production Dockerfile builds all three for Linux and sets the JVM library path; a standalone jar does not install system libraries. Linux targets use glibc binaries. For musl-based distributions, use target=all and verify the remaining native dependencies. A targeted jar is specific to its OS/CPU.

shadowJar checks the finished targeted archive: it requires the selected RocksDB binary and runtime classes, requires bundled GMP, secp256k1, and libsodium when the target has them, and rejects native files for other targets. This check also runs during a cross build. It verifies archive contents, not whether the libraries can load on the target machine.

On the target host, load the native libraries from the built jar with:

./gradlew smokeTargetJar -Pkeeper.features=all -Pkeeper.platforms=all -Ptarget=linux-amd64

This checks the JVM OS/CPU against target, then loads RocksDB, GMP, libsodium, and secp256k1 when ecc is selected. It fails if a required library cannot load. For Linux arm64 or macOS amd64, provide these system libraries in the JVM library path. For example, set JAVA_TOOL_OPTIONS=-Djava.library.path=/path/to/libs for a standalone run. A cross build needs this smoke command run on the target OS/CPU; it cannot validate native loading on the build host.

Feature and platform matrix

Need Feature selector Platform selector
EVM transaction authority evm or digital-assets ecc
Bitcoin transaction authority bitcoin or digital-assets ecc
Tron transaction authority tron or digital-assets ecc
XRP transaction authority xrp or digital-assets ecc
Solana transaction authority solana or digital-assets ecc
AP2 payment authority ap2 or agentic-payments ecc
MC VI payment authority mc-vi or agentic-payments ecc
X.509 certificate authority authority-x509 ecc
ECIES ecies ecc
Peer share recovery recovery (explicit opt-in) ecc, pqc, or both
Control-plane UI ui any required crypto platform
AWS KMS seal provider seal-aws any required crypto platform
Google Cloud KMS seal provider seal-gcloud any required crypto platform
Developer token authentication auth-dev (explicit opt-in, excluded from all) any required crypto platform
Authority policy dry run dry-run (explicit opt-in, excluded from all) any required crypto platform
MCP discovery, utilities, signing, and composition mcp (explicit opt-in, excluded from all) any required crypto platform
ML-DSA identities none pqc
Default production set all all

Features with platform dependencies require the matching platform. The build should fail early instead of producing an artifact with a missing runtime provider.

Recovery is an explicit artifact capability. Selecting it adds the base recovery API and the recovery module for each selected platform:

./gradlew :build -Pkeeper.features=recovery -Pkeeper.platforms=ecc
./gradlew :build -Pkeeper.features=recovery -Pkeeper.platforms=pqc
./gradlew :build -Pkeeper.features=recovery -Pkeeper.platforms=ecc,pqc

The first command includes :features:recovery and :features:recovery:ecc; the second includes :features:recovery and :features:recovery:pqc; the third includes all three. The platform modules are not selected separately. Recovery, auth-dev, dry-run, and mcp are excluded from keeper.features=all and must be requested explicitly.

Treat this as a maintenance artifact. After recovery, rebuild and redeploy the normal production artifact without the recovery selector; setting keeper.recovery=false alone leaves the recovery code and routes in the artifact.

auth-dev is deliberately excluded from all, but it may be included in any deployable artifact by requesting it explicitly:

./gradlew :build -Pkeeper.features=auth-dev -Pkeeper.platforms=ecc

Build the dry-run endpoint explicitly in the same way:

./gradlew :build -Pkeeper.features=dry-run -Pkeeper.platforms=ecc

Build the MCP endpoint into the same public Keeper server:

./gradlew :build -Pkeeper.features=mcp,digital-assets -Pkeeper.platforms=ecc

The endpoint is POST /mcp and uses the configured Keeper authentication provider. See MCP connection and tools for setup and request format.

Selection properties

Scope Features Platforms
Runtime jar keeper.features keeper.platforms
Docker build keeper.docker.features keeper.docker.platforms
Select all keeper.features.all=true keeper.platforms.all=true

Comma-separated selectors accept short names such as ecies, ecc, and pqc. all selects every default production module in that category. Explicit features such as recovery, auth-dev, dry-run, and mcp are not included.

target is independent of these selectors. Invalid target names fail the Gradle build instead of silently producing a jar with mismatched native libraries.

Docker

Build the production Docker image:

./gradlew dockerBuild -Pkeeper.features=all -Pkeeper.platforms=all

For a Linux amd64 or arm64 image, pass -Ptarget=linux-amd64 or -Ptarget=linux-arm64. The Docker build uses the matching --platform and the matching production jar. target=all preserves the existing Docker build with the multi-target native jar. macOS and Windows targets cannot be used with dockerBuild because the Dockerfile produces Linux images.

dockerBuild also loads the jar's native libraries inside the target image before finishing. For linux-arm64 on an amd64 host, Docker must be able to execute arm64 build steps (for example through an arm64 builder or emulation).

Build a recovery image with both platform implementations:

./gradlew dockerBuild \
  -Pkeeper.docker.features=recovery \
  -Pkeeper.docker.platforms=ecc,pqc

Production image tags:

exploit/tkeeper:2.5.0
exploit/tkeeper:latest

The Dockerfile adds the JVM flag required by the FFI Java API:

--enable-native-access=ALL-UNNAMED

Run the image:

docker run --rm \
  -p 8080:8080 \
  -p 9090:9090 \
  -v "$PWD/config:/etc/tkeeper:ro" \
  -v "$PWD/data:/var/lib/tkeeper" \
  -e KEEPER_CONFIG_LOCATION=/etc/tkeeper \
  exploit/tkeeper:2.5.0

Integration image

Run the complete release verification with:

./gradlew releaseGate

This includes every module's unit tests, artifact isolation, both test-container builds, and the functional integration suite. Performance benchmarks are separate.

Build both images used by functional integration tests with:

./gradlew buildTestContainers

The test task reuses these images. Re-run the build after changing application code, dependencies, or Dockerfiles.

Do not pass keeper.features or keeper.platforms to this task. The development integration image uses a dedicated classpath containing every default production feature, the explicit auth-dev, dry-run, and recovery features, both recovery platform modules, every platform, and the test-only failure-injection module.

Never deploy either test image as production runtime.

Common failures

Feature endpoint returns 404

The feature was not included in the artifact.

Rebuild with the required feature and platform.

For recovery, select the base feature and the required platforms:

./gradlew :build -Pkeeper.features=recovery -Pkeeper.platforms=ecc,pqc

No provider for algorithm

The platform was not included in the artifact.

Rebuild with the required platform, for example:

./gradlew :build -Pkeeper.features=evm -Pkeeper.platforms=ecc

Native access warning

Add:

--enable-native-access=ALL-UNNAMED

The Docker image already does this.