Skip to content

pluggy build

Compile Java sources, stage resources, generate the platform descriptor, apply shading, and zip the result into a plugin jar.

Usage

pluggy build [options]
pluggy b [options]

Flags

FlagDefaultNotes
--output <path><workspace>/bin/<name>-<version>.jarOutput jar destination.
--cleanoffWipe the staging directory before building.
--skip-classpathoffDon’t regenerate .classpath and .project for this build.
--workspace <name>noneBuild only this workspace.
--workspacesoffExplicit all-workspaces build from the root.

Scope rules

LocationFlagsBuilds
Standalone projectnoneThe project.
Inside workspace XnoneX.
Repo root, workspaces declarednoneEvery workspace, topologically ordered.
Repo root, workspaces declared--workspace AJust A.
Inside workspace X--workspacesError. Only valid at the root.
Inside workspace X--workspace Y (Y ≠ X)Error. Run from the root.

Topological order is driven by workspace: dependencies. A sibling’s built jar must exist before a workspace that shades it builds. Running from the root handles this for you.

Pipeline

For each target workspace, pluggy runs the steps below in order. Every step lives in its own module under src/build/.

  1. Pick the descriptor. Check that every declared platform shares the same descriptor family. Errors with “Split them into separate workspaces, one per family.” if they don’t.
  2. Stage directory. Under <workspace>/.pluggy-build/<hash>/, where <hash> is the first 12 hex chars of sha256(name \0 version \0 rootDir). --clean wipes this first.
  3. Resolve dependencies. Every declared dep, plus the primary platform’s api() Maven coordinate. Registries are the platform’s own repos first, followed by project.registries, with order-preserving dedup.
  4. Write IDE files. Writes .classpath and .project at the project root unless --skip-classpath was passed. Failures are logged at debug but don’t abort the build.
  5. Stage resources. Copy project.resources into the staging dir, and run .yml, .yaml, .json, .properties, .txt, and .md files through the ${project.x} template substitution.
  6. Generate the descriptor. Unless a resource entry already claims the descriptor path (plugin.yml and friends), pluggy writes the generated one to the staging dir.
  7. Compile. javac -encoding UTF-8 -d <staging> -cp <classpath> <sources>. The classpath separator is : on POSIX and ; on Windows, handled by Node’s path.delimiter.
  8. Shade. For each entry in project.shading, unzip the matching include entries from the dep jar and write them into the staging dir. exclude is subtracted after.
  9. Zip. Walk the staging dir, sort entries lexicographically, write a zip with forward-slashed entry paths.
  10. Platform compile-check. For every non-primary platform declared in compatibility.platforms (platforms[1..]), pluggy runs checkPlatformCompile: a javac invocation against that platform’s API jar with no artifacts emitted. The primary platform was already compiled in step 7, so this catches cases where your source is Paper-clean but references a symbol missing on Spigot, Folia, or a Bungee-family platform. A failing check logs a warning and sets the exit code to 1, but the primary jar still ships.

The output jar is written to <output> after the staging dir is zipped.

Output

Human, single workspace:

Building my_plugin
✓ my_plugin → /repo/bin/my_plugin-1.0.0.jar (142.4 KB, 3821ms)

Human, multi-workspace:

Building api
✓ api → /repo/api/bin/api-1.0.0.jar (42.1 KB, 1802ms)
Building impl
✓ impl → /repo/impl/bin/impl-1.0.0.jar (98.3 KB, 2103ms)
Summary
api → /repo/api/bin/api-1.0.0.jar (42.1 KB, 1802ms)
impl → /repo/impl/bin/impl-1.0.0.jar (98.3 KB, 2103ms)

JSON output

On success:

{
"status": "success",
"results": [
{
"workspace": "my_plugin",
"rootDir": "/repo",
"ok": true,
"outputPath": "/repo/bin/my_plugin-1.0.0.jar",
"sizeBytes": 145840,
"durationMs": 3821,
"platformChecks": [{ "platform": "spigot", "ok": true, "durationMs": 612 }]
}
]
}

platformChecks is omitted when compatibility.platforms has a single entry (nothing to cross-check). Each entry reports { platform, ok, durationMs }, plus error when ok is false. A failed entry sets status: "error" and exits 1 even though the primary jar was still produced.

On partial failure (multi-workspace, at least one workspace failed):

{
"status": "error",
"results": [
{ "workspace": "api", "ok": true, "outputPath": "...", "sizeBytes": 42123, "durationMs": 1802 },
{
"workspace": "impl",
"ok": false,
"durationMs": 120,
"error": "compile: javac exited with code 1 ..."
}
]
}

Success JSON goes to stdout; partial-failure JSON goes to stderr. Exit code is 0 when everything succeeds, 1 otherwise.

Single-workspace vs multi-workspace failure

Single-workspace builds rethrow the first exception. The CLI’s top-level handler prints it. Multi-workspace builds continue past a failed workspace, report everyone’s status in the summary, and exit 1 if anything failed.

Error cases

Common failure modes (see Troubleshooting for the full list):

StageMessage pattern
Descriptorbuild: project "<name>" declares platforms from different descriptor families ...
Compilecompile: javac exited with code <n> for project "<name>" (last 40 lines):\n...
Compilecompile: no .java sources found under "<dir>" for project "<name>"
Shadeshade: workspace dependency "<name>" has not been built yet, expected jar at "<path>". Build the sibling workspace first (topological order is the caller's responsibility).
Resourceresources: source path "<rel>" (key "<k>") does not exist at "<abs>"

See also