Install pluggy, scaffold a Paper plugin, add a dependency, and run it on a live server. Eight minutes start to finish, assuming you already have a JDK.
- A Java Development Kit, major version 21 for modern Paper (1.20.5 or newer). Older MC versions need older JDKs — see the JDK matrix in the IDE docs for specifics.
- An internet connection for the first run. pluggy caches downloads under
~/Library/Caches/pluggyon macOS,$XDG_CACHE_HOME/pluggyon Linux, and%LOCALAPPDATA%\pluggy\cacheon Windows.
pluggy ships as a native binary. Bun is only required if you want to build pluggy itself from source.
curl -fsSL https://github.com/ch99q/pluggy/releases/latest/download/install.sh | bashThe script downloads the binary for your OS and architecture into
~/.pluggy/bin/pluggy and adds that directory to your PATH via your
shell profile (~/.zshrc, ~/.bashrc, ~/.bash_profile,
~/.profile, ~/.config/fish/config.fish — whichever exist). No
sudo required.
Override the install location with PLUGGY_HOME:
PLUGGY_HOME=/opt/pluggy curl -fsSL https://github.com/ch99q/pluggy/releases/latest/download/install.sh | bashOpen a new shell or source the updated profile to pick up the new
PATH in your current session.
irm https://github.com/ch99q/pluggy/releases/latest/download/install.ps1 | iexThe script installs pluggy.exe to %LOCALAPPDATA%\Programs\pluggy and
appends that directory to your user PATH. No administrator privileges
required. Restart your terminal before using the command.
$ pluggy -V
0.1.0
mkdir my-plugin && cd my-plugin
pluggy init --yes --name my_plugin --main com.example.myplugin.Maininit writes three files:
project.json— the only config file pluggy reads.src/com/example/myplugin/Main.java— a BukkitJavaPluginwith stubbedonEnable/onDisablemethods.src/config.yml— a resources file with${project.name}placeholders rendered at build time.
The project name must match [a-zA-Z0-9_-]+ (alphanumeric, underscores,
and hyphens). The --main value must be a dotted Java class path,
minimum package + class.
Without --yes pluggy prompts interactively; confirmations are skipped when
the target directory is empty or when --json is set.
Inspect what you got:
$ cat project.json
{
"name": "my_plugin",
"version": "1.0.0",
"description": "A simple Minecraft plugin",
"main": "com.example.myplugin.Main",
"compatibility": {
"versions": ["1.21.8"],
"platforms": ["paper"]
}
}
The compatibility.versions[0] entry is picked up from the Paper upstream
at init time — it's the highest release available on every selected
platform. Pin this by passing --mc-version 1.21.8 to init if you
need a specific version. (--version sets the plugin's own
project.version — they're separate knobs.)
Install a plugin from Modrinth.
$ pluggy install worldedit
Installed worldedit into my_plugin (1 resolved).
pluggy rewrites project.json to add the dep in long form:
"dependencies": {
"worldedit": {
"source": "modrinth:worldedit",
"version": "7.3.15"
}
}It also writes pluggy.lock at the project root with the resolved version,
its SHA-256 integrity, and the full transitive closure (empty for Modrinth
plugins; populated for Maven artifacts).
The dep identifier grammar is documented in Dependency sources. In short:
worldedit— latest stable from Modrinth.worldedit@7.3.15— a specific Modrinth version../libs/my-lib.jar— a local file. pluggy content-addresses it.maven:net.kyori:adventure-api@4.17.0— a Maven artifact. Requires at least one entry inregistries(see below).
$ pluggy dev
dev: starting my_plugin
pluggy dev runs a full build, downloads the Paper server jar for the
version in compatibility.versions[0], stages a dev/ directory next to
your project, writes eula.txt accepting Mojang's EULA on your behalf
(suppressed with PLUGGY_DEV_NO_EULA=1), and spawns java -jar server.jar
with your plugin and any runtime plugin deps hardlinked into dev/plugins/.
When you save a .java file, pluggy debounces the event for 200ms,
rebuilds, sends stop\n to the server's stdin, waits for it to exit, swaps
in the new jar, and spawns a fresh server. Pass --reload to use Bukkit's
/reload confirm instead of a full restart — faster, but Bukkit's own docs
warn that /reload is unreliable for stateful plugins.
Press Ctrl+C once for graceful shutdown (30 seconds grace). A second Ctrl+C within 2 seconds sends SIGKILL.
$ pluggy build
build my_plugin
✔ my_plugin: /Users/you/my-plugin/bin/my_plugin-1.0.0.jar (142.4 KB, 3821ms)
The output jar lives at <workspace>/bin/<name>-<version>.jar by default.
Override with --output path/to/out.jar.
- Resolved
compatibility.platforms[0](paper) against the platform registry. Each platform exposes a Maven API spec — for Paper, that'sio.papermc.paper:paper-apifrom the PaperMC maven repo. - Downloaded the
paper-apijar and put it on the compile classpath. - Resolved every
dependencies[]entry, downloading jars into~/Library/Caches/pluggy/dependencies/<kind>/.... Maven deps also had their POM parsed for transitives. - Ran
javac -encoding UTF-8 -d <staging> -cp <classpath> <sources>. - Copied
src/config.ymlthrough the${project.x}templater and wrote it toconfig.ymlinside the staging dir. - Generated
plugin.ymlfromproject.name,version,main,description, and the derivedapi-version("1.21"for1.21.8). - Zipped the staging dir into the output jar.
Each step lives in a dedicated module under src/build/ — see
Build pipeline for the full walkthrough.
- Make the dev loop faster:
pluggy dev. - Add JUnit tests:
pluggy test. - Split into a monorepo: Workspaces.
- Ship a jar that bundles a third-party library: Shading.
- Set up IDE integration: IDE integration.
- Wire up CI without installing pluggy globally: CI recipe.