jbx.json
jbx.json is the project descriptor for publishing or installing a Java artifact with jbx. Keep it small: put durable artifact metadata here, and keep command-specific experiments on the command line.
JSON Schema: /schemas/jbx-json/v1.json
Minimal descriptor
Use this when you only need local install/serve workflows or when Git metadata can fill in Maven Central metadata later:
{
"$schema": "https://jbx.telegraphic.dev/schemas/jbx-json/v1.json",
"main": "HelloTool.java",
"group": "dev.telegraphic.demo",
"id": "hello-tool",
"version": "1.0.0",
"java": "25",
"dependencies": ["info.picocli:picocli:4.7.7"],
"runtimeDependencies": ["org.slf4j:slf4j-nop:2.0.17"]
}
Try it locally before publishing:
jbx publish --file jbx.json --dry-run
jbx publish --file jbx.json --serve 0
jbx install --file jbx.json --destination build/local-m2
Maven Central-ready descriptor
Real publishing needs normal Maven metadata: project URL, license, developer, and SCM. jbx can infer some values from GitHub, but explicit metadata is better for repeatable releases.
{
"$schema": "https://jbx.telegraphic.dev/schemas/jbx-json/v1.json",
"main": "dev.telegraphic.demo.HelloTool",
"group": "dev.telegraphic.demo",
"id": "hello-tool",
"version": "1.0.0",
"name": "Hello Tool",
"description": "Small CLI published with jbx.",
"url": "https://github.com/telegraphic-dev/hello-tool",
"licenses": [
{
"name": "Apache-2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
}
],
"developers": [
{
"name": "Telegraphic",
"organization": "Telegraphic",
"organizationUrl": "https://telegraphic.dev"
}
],
"scm": {
"connection": "scm:git:https://github.com/telegraphic-dev/hello-tool.git",
"developerConnection": "scm:git:ssh://git@github.com/telegraphic-dev/hello-tool.git",
"url": "https://github.com/telegraphic-dev/hello-tool"
},
"sources": ["HelloTool.java"],
"repositories": ["snapshots=https://repo.example.test/maven"]
}
Run a dry run first. Real publishing still needs Central Portal and signing credentials configured in the environment or command options.
jbx publish --file jbx.json --dry-run
jbx publish --file jbx.json --publish
Fields
$schema— optional editor hint. Usehttps://jbx.telegraphic.dev/schemas/jbx-json/v1.json.jbxignores unknown fields, so this is safe.main— main Java source. Relative paths resolve from the descriptor directory. Existing paths win; otherwisejbxalso checks.java,.jsh,.jav, and Java FQN matches under the descriptor directory.group— MavengroupId. Required for publish/install unless//GAVsupplies it.id— MavenartifactId. Required for publish/install unless//GAVsupplies it.version— artifact version. Maven Central publishing rejects-SNAPSHOT.--versioncan override it for one command.package— Java package override used when staging compact or unpackaged sources for publishing.name— human-readable POM name. Defaults togroup:id.description— POM description. Falls back to//DESCRIPTIONor a generated description.url— project URL. Required for Maven Central dry-run/publish.licenses— license objects with requirednameandurl. Required for Maven Central dry-run/publish.developers— developer objects with requirednameand optionalemail,organization,organizationUrl. Required for Maven Central dry-run/publish.scm— SCM object with requiredconnectionandurl, optionaldeveloperConnection. Required for Maven Central dry-run/publish.java— requested Java version, equivalent to//JAVA.dependencies— compile-time/public Maven coordinates, equivalent to//DEPS. Rendered as normal Maven dependencies.runtimeDependencies— runtime-only Maven coordinates, equivalent to//RUNTIME. Rendered with Mavenruntimescope and not required on the compile classpath.sources— additional source files to include. Omit the field to letjbxauto-discover local Java sources; set it explicitly when you need a controlled source list.repositories— extra Maven repositories for resolution. Entries can be bare URLs orid=url.
Real-life patterns
Publish a small CLI with Picocli
{
"$schema": "https://jbx.telegraphic.dev/schemas/jbx-json/v1.json",
"main": "CleanImports.java",
"group": "com.acme.tools",
"id": "clean-imports",
"version": "0.3.0",
"dependencies": ["info.picocli:picocli:4.7.7"]
}
jbx publish --file jbx.json --dry-run
Keep parser/logging providers runtime-only
Use runtimeDependencies for implementation libraries needed when the tool runs but not when callers compile against the artifact:
{
"$schema": "https://jbx.telegraphic.dev/schemas/jbx-json/v1.json",
"main": "dev.acme.RewriteTool",
"group": "dev.acme",
"id": "rewrite-tool",
"version": "1.2.0",
"dependencies": ["org.openrewrite:rewrite-java:8.56.1"],
"runtimeDependencies": [
"org.openrewrite:rewrite-java-21:8.56.1",
"org.slf4j:slf4j-nop:2.0.17"
]
}
Pin the published source set
If the repository has helpers, examples, or generated files you do not want in the artifact, set sources explicitly:
{
"$schema": "https://jbx.telegraphic.dev/schemas/jbx-json/v1.json",
"main": "App.java",
"group": "dev.acme",
"id": "app",
"version": "1.0.0",
"sources": [
"App.java",
"AppSupport.java"
]
}
Publish helper artifacts from GitHub Actions
telegraphic-dev/jbx-utils is a good shape for a real repository: one repo, several small helper artifacts, each with its own descriptor. The jbx-rewrite/jbx.json descriptor keeps shared Maven metadata explicit and only names the source and dependencies for that artifact:
{
"$schema": "https://jbx.telegraphic.dev/schemas/jbx-json/v1.json",
"group": "dev.telegraphic.jbx",
"version": "0.1.0",
"package": "dev.telegraphic.jbx",
"url": "https://github.com/telegraphic-dev/jbx-utils",
"licenses": [
{ "name": "MIT License", "url": "https://opensource.org/licenses/MIT" }
],
"developers": [
{ "name": "Telegraphic", "organizationUrl": "https://github.com/telegraphic-dev" }
],
"scm": {
"connection": "scm:git:https://github.com/telegraphic-dev/jbx-utils.git",
"developerConnection": "scm:git:ssh://git@github.com/telegraphic-dev/jbx-utils.git",
"url": "https://github.com/telegraphic-dev/jbx-utils"
},
"java": "21",
"main": "src/JbxRewrite.java",
"id": "jbx-rewrite",
"name": "jbx-rewrite",
"description": "OpenRewrite runner and recipe-discovery helper used by jbx rewrite",
"dependencies": [
"org.openrewrite:rewrite-core:8.56.1",
"org.openrewrite:rewrite-java:8.56.1"
]
}
Use CI to prove the bundle layout before release. jbx-utils runs dry-run publishing without signing for every helper artifact:
name: CI
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '25'
- uses: dtolnay/rust-toolchain@stable
- name: Install jbx
run: cargo install --git https://github.com/telegraphic-dev/jbx.git --locked jbx
- name: Verify publish bundle
run: scripts/verify-publish-bundle.sh
Then keep real Maven Central uploads in a separate release/manual workflow. The workflow needs these GitHub secrets: CENTRAL_TOKEN_USERNAME, CENTRAL_TOKEN_PASSWORD, GPG_PRIVATE_KEY, GPG_PASSPHRASE, and GPG_KEY_ID.
name: Publish to Maven Central
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: Maven artifact version to publish, e.g. 0.1.0
required: true
permissions:
contents: read
jobs:
publish:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
project: [jbx-check, jbx-graph, jbx-rewrite]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '25'
- uses: dtolnay/rust-toolchain@stable
- name: Install jbx
run: cargo install --git https://github.com/telegraphic-dev/jbx.git --locked jbx
- name: Import GPG signing key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
- name: Publish ${{ matrix.project }}
env:
CENTRAL_TOKEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }}
CENTRAL_TOKEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
run: |
VERSION="${{ github.event.inputs.version }}"
if [ -z "$VERSION" ]; then
VERSION="${GITHUB_REF_NAME#v}"
fi
jbx publish \
--publish \
--file "${{ matrix.project }}/jbx.json" \
--version "$VERSION" \
--gpg-key "$GPG_KEY_ID" \
--output "target/${{ matrix.project }}-central-bundle.zip" \
--target-dir "target/publish/${{ matrix.project }}" \
--cache-dir .jbx-cache
Two details matter:
- The PR workflow runs
--dry-run --skip-signingthrough a script so contributors can verify jars, POMs, sources, javadocs, docs sidecars, and bundle layout without secrets. - Only the release/manual workflow imports the signing key and runs
--publish; publishing from ordinary PR CI would be reckless and noisy.
Descriptor and directives
Descriptor fields override or replace matching source directives where both exist:
group,id,versionreplace//GAV.descriptionreplaces//DESCRIPTION.javareplaces//JAVA.dependenciesreplaces//DEPSwhen non-empty.runtimeDependenciesreplaces//RUNTIMEwhen non-empty.sourcesreplaces//SOURCESwhen non-empty.repositoriesreplaces//REPOSwhen non-empty.
That keeps a library release reproducible without forcing all metadata into the Java file.
Verification checklist
mainresolves from the descriptor directory.group,id, andversionproduce the intended Maven coordinate.- Compile-time libraries are in
dependencies; runtime-only providers are inruntimeDependencies. jbx publish --file jbx.json --dry-runsucceeds before any real publish.- For local-only checks,
jbx install --file jbx.json --destination build/local-m2writes the expected Maven layout.
