Reference

The whole surface of jpx is one target and a handful of flags:

jpx [--modular] [--java=<version>] [--docker[=<image>]] [--hash=<checksum>] [--pin] [-J<option>...] <target> [argument...]

Flags come before the target; everything after the target is passed to the launched program. The target grammar, <name>[@<version>][/<main-class>], is covered in Choosing a target.

Flag What it does
--modular Resolve purely over module descriptors, walking requires clauses like the modular layout, and place every jar on the module path. Every module must then be explicitly named; a Maven coordinate is refused.
--java=<version> Run the program on an installed JDK matching the version, as 25, 25.0.3 or 25-temurin, which names Java 25 or newer: the JDK running jpx when it matches, otherwise the newest match in the folders -Djenesis.toolchain.searchpath names, the operating system's usual JDK locations by default. Nothing is installed unless -Djenesis.toolchain.installer or the JENESIS_TOOLCHAIN_INSTALLER environment variable names an installer for when none matches. Where SDKMAN, mise or Scoop installed jpx, the jpx command names its own jpx-jdk there for the run it starts, which installs the JDK with that tool, as jenesis-jdk does for a build (see Installing a missing JDK). The version and the search path follow the build tool's rules (see The JDK a build runs on).
--docker[=<image>] Run the launched process in a container while resolution and installation stay on the host. Without an image, a minimal hardened image is built once and reused; a named image runs as is. An empty value is the same as naming no image.
--hash=<prefix> Verify the installed jars against a known digest before launching. At least 32 hex characters, with or without a leading SHA-256/.
--pin Print two commands instead of launching: the jpx command that repeats this run reproducibly - the resolved version spelled out, --hash always present at full length, --pin itself dropped - and the java command it expands to. The jars are verified before anything is printed, against --hash where one is given and against the installation's own digest otherwise.
-J<option> Pass the option to the JVM that runs the program, written as java takes it: -J-Xmx512m, -J-Xlog:gc. --pin keeps it in both commands it prints.
--help Print the usage screen and exit.

A whole invocation can live in a file: jpx @run.args stands for the arguments that file holds, one or more per line, with # a comment to the end of a line, quotes holding what would otherwise split, and @@<text> an argument that begins with an @. A file names no further file.

The jpx command reads the jenesis.* settings - the repositories, the toolchain search path, a plaintext repository allowed with jenesis.repository.insecure - as options of the JVM it starts, which it takes from JAVA_OPTS:

JAVA_OPTS="-Djenesis.module.uri=https://repo.example.com/repository/releases/<repo>/" jpx org.example.tool

A -D given after jpx is read as the target rather than as a setting, and ~/.jenesis/jenesis.properties is not read.

--modular is covered under Choosing a target; --docker and --hash under Isolation & verification; --pin under Using jpx from Java, whose pinned and command calls it prints.

Exit codes

Code When
the program's own The launched program ran; jpx returns its exit code unchanged.
0 --help, or --pin once the commands have been printed.
64 A usage error: no target, or an unknown option. The usage screen is printed to standard error.
1 Resolution failed, a checksum did not match, or the target declares no entry point - reported with the message of the underlying exception.

The API

Every flag has a counterpart in the API, which Using jpx from Java walks through:

Call What it does
new Jpx(placement) The command line's wiring: installs under ~/.jenesis/jpx; PathPlacement.MODULE_PATH is --modular, PathPlacement.INFERRED the default.
new Jpx(storage, repositories, resolvers, hashFunction, placement) The record itself: where installs land, where artifacts come from, how they are digested, and how a module name's jars are placed.
jpx.install(target) Resolve and install <name>[@<version>][/<main-class>], returning an Installation.
Jpx.Command.parse(target) / jpx.install(command) The same, with the target's three parts in hand.
jpx.latestInstalled(name) The newest install of a name already on disk, without resolving anything.
installation.folder() / .properties() The installation folder and its jpx.properties descriptor.
installation.verify(prefix) The --hash check; returns the installation, throws on a mismatch.
installation.launch(arguments) Launch the installation's own entry point and return the exit code.
installation.launch(mainClass, arguments) The same with an entry point of your choice (null for the installation's own).
installation.launch(mainClass, arguments, docker) The same inside a container; docker is a DockerizedJava, the API behind --docker.
installation.pinned(arguments) / .pinned(options, mainClass, arguments) The first line --pin prints: the jpx command that repeats the run, with the resolved version and the installation's digest filled in.
installation.command(arguments) / .command(mainClass, arguments) The second line: the same launch spelled out as a list, from the JVM to the last argument, with nothing started.
installation.home(home) The same installation launched with the JDK at home in place of the one running jpx; --java passes the home of the JDK it selected.
installation.command(mainClass, arguments, docker) The same for a containerised launch: the docker run command that would be issued.
installation.javaArguments(mainClass, arguments, file) Everything after java, spilling the long paths into file - null to keep them on the list.