Example projects demonstrating plugin development with Plugwerk and the PF4J plugin framework.
| Example | Description |
|---|---|
| plugwerk-java-cli-example | Standalone Java CLI application with dynamically loadable command plugins |
| plugwerk-springboot-thymeleaf-example | Spring Boot + Thymeleaf web application with dynamically loadable page plugins |
Each example is a self-contained Gradle build. The repository root also provides a Gradle composite build that drives both examples at once. See each example's own README.md for in-depth details.
- Java 21 or later
- Docker and Docker Compose (optional, for running a local Plugwerk server)
- GitHub Personal Access Token with
read:packagesscope — only required to resolve Plugwerk SNAPSHOT artifacts from GitHub Packages for Maven (see Resolving Plugwerk dependencies)
docker compose up -dStarts the Plugwerk server (SNAPSHOT image from GHCR) and PostgreSQL. Available at http://localhost:8080 with credentials admin / admin.
The container image ghcr.io/plugwerk/plugwerk-server:snapshot is publicly pullable — no docker login required.
Health check:
curl http://localhost:8080/actuator/health→{"status":"UP"}. The server has no web frontend under/; use the REST API under/api/v1/...or OpenAPI under/v3/api-docs(auth required).
A fresh server has no namespaces, so the very first run needs to create one. Read-only catalog access works anonymously on namespaces with publicCatalog=true; uploads, approvals and access-key management always require an admin JWT.
The Spring example installs and uninstalls plugins through its own controllers, so it expects an X-Api-Key even against a public namespace — the snippet below mints one for both examples to share.
Requires jq (Homebrew: brew install jq).
# 1. Log in as the bootstrap admin and capture a JWT (one-shot, used only for setup)
JWT=$(curl -s -X POST http://localhost:8080/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin"}' | jq -r .accessToken)
# 2. Create the `default` namespace as a public catalog (idempotent: HTTP 409 means it already exists).
# publicCatalog=true lets `list` / `search` / download work without an API key;
# set it to false here if you'd rather force key-auth from the start.
curl -sS -o /dev/null -X POST http://localhost:8080/api/v1/namespaces \
-H "Authorization: Bearer $JWT" \
-H 'Content-Type: application/json' \
-d '{"slug":"default","name":"Default","publicCatalog":true,"autoApproveReleases":true}' \
|| true
# 3. Mint a fresh access key — the plain-text value is shown only once
export PLUGWERK_API_KEY=$(curl -s -X POST http://localhost:8080/api/v1/namespaces/default/access-keys \
-H "Authorization: Bearer $JWT" \
-H 'Content-Type: application/json' \
-d '{"name":"local-dev","expiresAt":null}' | jq -r .key)
echo "$PLUGWERK_API_KEY" # pwk_…Both examples honour the PLUGWERK_API_KEY environment variable; the CLI also accepts an inline --api-key=… flag. See the per-example README for invocation details.
From the repository root:
./gradlew build # Build both examples with tests
./gradlew clean # Clean both examples
./gradlew check # Run checks in both examplesPer-example tasks remain reachable via path, e.g.:
./gradlew :plugwerk-springboot-thymeleaf-example:bootRunEach example is also a fully standalone Gradle build:
cd plugwerk-java-cli-example
./gradlew buildPlugwerk ships artifacts from two registries:
| Artifact type | Registry | Auth required |
|---|---|---|
Releases (e.g. 1.0.0) |
Maven Central | No |
SNAPSHOTs (e.g. 1.0.0-SNAPSHOT) |
GitHub Packages for Maven | Yes — read:packages token |
The examples currently consume SNAPSHOT artifacts during active development, so a token is needed for ./gradlew build in the current setup.
Why is a token needed even though the source repo is public? GitHub Packages for Maven requires authentication for downloads regardless of package visibility — a long-standing limitation that only GHCR (container registry) has fixed. Once Plugwerk switches to release coordinates from Maven Central, no token will be required.
No configuration needed — the built-in GITHUB_TOKEN already has read:packages scope.
-
Create a Classic Personal Access Token at https://github.com/settings/tokens with the
read:packagesscope. -
Add it to
~/.gradle/gradle.properties:gpr.user=your-github-username gpr.key=ghp_your-personal-access-token
Alternatively, set GITHUB_ACTOR and GITHUB_TOKEN environment variables — the build scripts fall back to those.
See the Plugwerk Development Guide for details.
Apache-2.0 — see LICENSE.