jam4j is an experimental Java Artifact Manager: a small CLI that brings an npm-like workflow to Java projects. It uses a project.json manifest to declare dependencies and scripts, resolves artifacts from Maven repositories with Apache Maven Resolver, and installs resolved JARs into a local lib/ directory.
- Manage Java dependencies from a JSON manifest instead of a Maven or Gradle build file.
- Resolve Maven Central artifacts and transitive compile-scope dependencies.
- Provide familiar commands such as
install,run,build,test,clean, andpackage. - Support portable script definitions through variable substitution.
This repository is an early implementation. The CLI, manifest model, Maven Resolver integration, local installation, script execution, and basic tests are present. Broader project-generation workflows remain design goals, not complete product features.
- Java 21
- Maven 3.9 or newer
mvn test
mvn package
java -jar target/jam4j-1.0.0-SNAPSHOT.jar --help
java -jar target/jam4j-1.0.0-SNAPSHOT.jar --versionmvn package builds a shaded standalone JAR with com.strategicgains.jam4j.Jam as the entry point. The packaged CLI reports the Maven project version and build timestamp, for example jam 1.0.0-SNAPSHOT (build 2026-05-04T21:18:42Z).
CI runs on branch pushes and pull requests. It builds the shaded JAR and smoke-tests the CLI.
Versioned releases are created from Git tags. To publish a release:
-
Update the Maven version in
pom.xmlfrom a snapshot to the release version, for example1.0.0-SNAPSHOTto1.0.0. -
Verify the release build locally:
mvn clean package java -jar target/jam4j-1.0.0.jar --version
-
Commit the release version:
git add pom.xml git commit -m "release: 1.0.0" -
Create and push a matching tag:
git tag v1.0.0 git push origin main git push origin v1.0.0
You can also push the branch and all local tags together:
git push origin main --tags
The release workflow runs only for tags matching v*. It verifies that the tag version matches pom.xml, rejects *-SNAPSHOT versions, builds the package, and publishes a GitHub Release with:
jam4j-<version>.jarjam4j-<version>.jar.sha256
After publishing, bump pom.xml to the next development snapshot and commit it:
git add pom.xml
git commit -m "chore: start 1.0.1-SNAPSHOT"
git push origin mainA project manifest can declare dependencies, dev dependencies, a main class, and named scripts:
{
"name": "my-app",
"version": "1.0.0",
"main": "com.example.Main",
"dependencies": {
"com.fasterxml.jackson.core:jackson-databind": "2.17.1"
},
"devDependencies": {
"org.junit.jupiter:junit-jupiter": "5.10.2"
},
"scripts": {
"build": "javac -cp {{deps}} -d {./target/classes} src{/}*.java",
"run": "java -cp {{deps}}{:}{./target/classes} com.example.Main",
"test": "java -cp {{deps}} org.junit.platform.console.ConsoleLauncher --scan-classpath",
"clean": "rm -rf {./target/classes}"
}
}Dependency keys use group:artifact; values are versions. At runtime they are resolved as Maven coordinates such as group:artifact:version.
After building:
java -jar target/jam4j-1.0.0-SNAPSHOT.jar search jackson
java -jar target/jam4j-1.0.0-SNAPSHOT.jar install com.fasterxml.jackson.core:jackson-databind:2.17.1
java -jar target/jam4j-1.0.0-SNAPSHOT.jar path
java -jar target/jam4j-1.0.0-SNAPSHOT.jar run --list
java -jar target/jam4j-1.0.0-SNAPSHOT.jar run buildConvenience commands execute matching scripts from project.json:
java -jar target/jam4j-1.0.0-SNAPSHOT.jar build
java -jar target/jam4j-1.0.0-SNAPSHOT.jar test
java -jar target/jam4j-1.0.0-SNAPSHOT.jar clean
java -jar target/jam4j-1.0.0-SNAPSHOT.jar packageThe examples above use the shaded JAR directly. If you install or alias the JAR launcher as jam, replace java -jar target/jam4j-1.0.0-SNAPSHOT.jar with jam.
The top-level command supports:
-h, --help: show top-level help-V, --version: print the CLI version and build timestamp
Subcommands print command-specific usage when invocation fails validation, such as an unknown option or missing required argument.
Several commands share repository, cache, install-directory, and output options. Those shared options are documented in Repository and Cache Options.
Creates a scaffold project.json. If no target directory is supplied, jam writes to the current directory. The command prompts for missing project metadata and writes default build, test, run, and clean scripts.
Aliases: n
Options:
--force: overwriteproject.jsonif it already exists--name <name>: project name--version <version>: project version--main <class>: main class
Examples:
jam init
jam init --name my-app --version 0.1.0 --main com.example.Main ./my-app
jam init --forceSearches for Maven artifacts. By default, search includes Maven Central and returns up to 20 results. Multi-word queries are accepted.
Aliases: s
Options:
-i, --interactive: prompt for result numbers to install after searching-m, --max <count>: maximum number of results to return, default20--snapshots: include snapshot versions--local: include artifacts from the local Maven cache--no-central: skip Maven Central and search only the local cache or configured repositories-p, --project <file>: project file to update during interactive installs, default./project.json
Also supports the shared options: --config, -c, --cache, -d, --directory, -L, --local-only, -r, --repo, --ignore-pom-repos, -q, --quiet, and -v, --verbose.
Examples:
jam search jackson
jam search -m 5 "junit jupiter"
jam search --local --no-central assertj
jam search --interactive jackson databindResolves and installs artifacts into the local library directory. Artifacts must use Maven coordinates in group:artifact:version form. If artifacts are supplied and the project file exists, jam also records them in dependencies in project.json.
If no artifacts are supplied, jam install reads all dependencies and devDependencies from project.json and installs them.
Pass --from <pom.xml> to bootstrap from an existing Maven project. jam reads all <dependency> entries from the POM, installs the resolved JARs, and writes them into project.json — creating the file if it does not exist. Compile- and runtime-scoped dependencies are recorded under dependencies; test-, provided-, and system-scoped dependencies are recorded under devDependencies. If project.json is created from scratch, name and version are populated from the POM's artifactId and version.
Aliases: i
Options:
-f, --from <file>: read dependencies from a Mavenpom.xmland create or updateproject.json-p, --project <file>: project file to read or update, default./project.json
Also supports the shared options: --config, -c, --cache, -d, --directory, -L, --local-only, -r, --repo, --ignore-pom-repos, -q, --quiet, and -v, --verbose.
Examples:
jam install
jam install com.fasterxml.jackson.core:jackson-databind:2.17.1
jam install -d vendor/lib org.assertj:assertj-core:3.25.3
jam install --ignore-pom-repos com.hazelcast:hazelcast:5.5.0
jam install --from pom.xml
jam install -f pom.xml -d vendor/libResolves artifacts and prints a platform-specific Java classpath. If artifacts are supplied, those coordinates are resolved. If no artifacts are supplied, jam path reads all dependencies and devDependencies from project.json.
Aliases: p
Options:
-p, --project <file>: project file to read, default./project.json
Also supports the shared options: --config, -c, --cache, -d, --directory, -L, --local-only, -r, --repo, --ignore-pom-repos, -q, --quiet, and -v, --verbose.
Examples:
jam path
jam path org.junit.jupiter:junit-jupiter:5.10.2
java -cp "$(jam path):target/classes" com.example.MainExecutes one or more named scripts from project.json. Before running scripts, jam resolves all project dependencies and makes that classpath available to the {{deps}} script variable.
Aliases: r
Options:
-l, --list: list scripts defined inproject.json-p, --project <file>: project file to read, default./project.json-a, --arg <arg>: pass an argument to the preceding script. This is parsed byjam runrather than declared as a picocli option, so it appears after a script name.
Also supports the shared options: --config, -c, --cache, -d, --directory, -L, --local-only, -r, --repo, --ignore-pom-repos, -q, --quiet, and -v, --verbose.
Examples:
jam run --list
jam run build
jam run build -a --release -a 21
jam run clean build testWhen several script names are supplied, jam runs them in order. Arguments following a script are passed to that script until another known script name is encountered.
Runs the build script from project.json. This is a convenience command equivalent to jam run build, with any supplied arguments forwarded to the script.
Options:
-p, --project <file>: project file to read, default./project.json
Also supports the shared options: --config, -c, --cache, -d, --directory, -L, --local-only, -r, --repo, --ignore-pom-repos, -q, --quiet, and -v, --verbose.
Example:
jam build -- --release 21Use -- before script arguments that begin with - so picocli does not parse them as jam build options.
Runs the test script from project.json. This is a convenience command equivalent to jam run test, with any supplied arguments forwarded to the script.
Options:
-p, --project <file>: project file to read, default./project.json
Also supports the shared options: --config, -c, --cache, -d, --directory, -L, --local-only, -r, --repo, --ignore-pom-repos, -q, --quiet, and -v, --verbose.
Example:
jam test smokeUse -- before script arguments that begin with - so picocli does not parse them as jam test options.
Runs the clean script from project.json. This is a convenience command equivalent to jam run clean, with any supplied arguments forwarded to the script.
Options:
-p, --project <file>: project file to read, default./project.json
Also supports the shared options: --config, -c, --cache, -d, --directory, -L, --local-only, -r, --repo, --ignore-pom-repos, -q, --quiet, and -v, --verbose.
Example:
jam cleanUse -- before script arguments that begin with - so picocli does not parse them as jam clean options.
Runs the package script from project.json. This is a convenience command equivalent to jam run package, with any supplied arguments forwarded to the script.
Options:
-p, --project <file>: project file to read, default./project.json
Also supports the shared options: --config, -c, --cache, -d, --directory, -L, --local-only, -r, --repo, --ignore-pom-repos, -q, --quiet, and -v, --verbose.
Example:
jam packageUse -- before script arguments that begin with - so picocli does not parse them as jam package options.
Scripts support cross-platform substitutions:
{{deps}}: resolved dependency classpath{/}: platform file separator{:}: platform path separator{~}: user home directory{./path}: project-relative path using platform separators
Arguments can be passed to scripts with -a or --arg:
java -jar target/jam4j-1.0.0-SNAPSHOT.jar run build -a --verbose test -a smokeCommon options are available on search, install, path, run, build, test, clean, and package:
--config <file>: user configuration file, defaulting toJAM_CONFIG,~/.jam/config.json, or~/.jamcfg.json-c, --cache <dir>: local Maven repository cache, defaulting toJAM_CACHEor~/.m2/repository-d, --directory <dir>: install directory, defaulting to./lib-L, --local-only: copy JARs instead of creating symlinks-r, --repo <url|name=url>: add a repository--ignore-pom-repos: strict mode; ignore repositories declared by dependency POMs and resolve only from Maven Central plus--reporepositories-q, --quietand-v, --verbose: control output
For named repositories, credentials can be supplied with JAM_REPO_<NAME>_USER and JAM_REPO_<NAME>_PASSWORD.
By default, artifact resolution follows Maven behavior and may use repositories declared in dependency POMs. Use --ignore-pom-repos when you want reproducible strict resolution from only Maven Central and repositories you explicitly declare:
jam install --ignore-pom-repos --repo internal=https://repo.example.com/maven2 com.example:tool:1.0.0
jam path --ignore-pom-repos com.hazelcast:hazelcast:5.5.0src/main/java/com/strategicgains/jam4j/Jam.java: CLI entry pointsrc/main/java/com/strategicgains/jam4j/command: picocli commandssrc/main/java/com/strategicgains/jam4j/resolver: Maven artifact resolution and searchsrc/main/java/com/strategicgains/jam4j/model:project.jsonmodelsrc/main/java/com/strategicgains/jam4j/script: script execution and substitutionssrc/test/java: JUnit 5 and AssertJ tests
See LICENSE.