Module Authoring
Package game server templates as signed, versioned OCI artifacts with metadata, config schema, and capabilities.
A module is a reusable, versioned game-server blueprint distributed as an OCI artifact. Gameplane hosts modules in registries (official or self-hosted) and lets operators install them into the cluster as GameTemplate resources, so game servers on the platform inherit their console protocol, configuration schema, and operational capabilities — backup quiesce, player moderation, and lifecycle management — without any platform-code changes.
Source layout
A module lives on disk as a directory holding four files:
| File | Required | Purpose |
|---|---|---|
template.yaml |
yes | GameTemplate spec (Kubernetes resource) |
module.yaml |
yes | Module metadata (name, version, display info) |
README.md |
no | Operator documentation, rendered in the catalog |
icon.png |
no | 256×256 PNG for the dashboard catalog tile |
The official modules live in the standalone GameplanePanel/module repository, checked out as the modules/ submodule of the main Gameplane repo.
Module metadata (module.yaml)
Every module declares its identity and display properties in module.yaml:
apiVersion: gameplane.local/module/v1
name: minecraft-java # required, DNS-1123 label
displayName: Minecraft (Java Edition) # required
version: 1.0.0 # required, semver, must match OCI tag
game: minecraft-java # required, free-form game family
categories: [Sandbox, Survival, Modded] # optional, catalog grouping
summary: Paper / Forge / Fabric / Vanilla # required, one-line description
homepage: https://minecraft.net # optional
license: MIT # optional, SPDX identifier
gameplaneMinVersion: 0.2.0 # optional, operator version gate
icon: icon.png # optional, filename in the bundle
Key rules:
nameis the canonical module identifier within a source. Two modules with the same name in the same source are rejected.versionmust exactly match the OCI tag the bundle is pushed under — drift is an error.gameis a free-form identifier grouping templates with the same upstream game, used for versioning schemes (e.g.,minecraft-java,minecraft-bedrock).categoriesappears as filter chips in the dashboard Modules catalog. Use official values (Sandbox, Survival, Shooter, etc.) or define your own — the dashboard auto-discovers new chips.gameplaneMinVersiongates installation on operator version; a module that requires v0.3.0+ will refuse install on v0.2.0.
Bundling and distribution
Modules are distributed as OCI artifacts — the same registries that hold your game-server images also hold module metadata. A bundle is a single artifact with typed layers.
| Layer | Media type | Notes |
|---|---|---|
module.yaml |
application/vnd.gameplane.module.metadata.v1+yaml |
Metadata, required |
template.yaml |
application/vnd.gameplane.module.template.v1+yaml |
Template spec, required |
README.md |
application/vnd.gameplane.module.readme.v1+md |
Operator docs, optional |
icon.png |
image/png |
Dashboard tile icon, optional |
The artifact manifest is tagged as:
mediaType: application/vnd.oci.image.manifest.v1+json
artifactType: application/vnd.gameplane.module.v1+json
Each layer carries an org.opencontainers.image.title annotation with its filename so the puller can identify layers by name.
Pushing a bundle
Install oras (>= 1.2.0):
brew install oras # macOS
# or download from https://oras.land/docs/installation
Then push a bundle from a module directory:
PUSHING A BUNDLEoras push \
--artifact-type application/vnd.gameplane.module.v1+json \
ghcr.io/gameplanepanel/gameplane-modules/minecraft-java:1.0.0 \
module.yaml:application/vnd.gameplane.module.metadata.v1+yaml \
template.yaml:application/vnd.gameplane.module.template.v1+yaml \
README.md:application/vnd.gameplane.module.readme.v1+md \
icon.png:image/png
Or use the Makefile target:
make modules-push REGISTRY=ghcr.io/gameplanepanel/gameplane-modules
For private registries, log in once with oras login <registry>. The cluster uses a kubernetes.io/dockerconfigjson secret (ModuleSource.spec.oci.pullSecretRef) — the same credential format kubelet uses for private images.
Bundle format
A module bundle is a single OCI artifact with named layers, tagged application/vnd.gameplane.module.v1+json.
Module sources
Once a module is pushed to a registry, operators register it by creating a ModuleSource resource that tells Gameplane where to fetch modules:
apiVersion: gameplane.local/v1alpha1
kind: ModuleSource
metadata: { name: community }
spec:
type: oci # oci | git | http | local | upload
oci:
url: ghcr.io/gameplanepanel/gameplane-modules
modules: [{ name: minecraft-java }] # explicit list
verify: # optional, supply-chain security
key: { name: cosign-pub } # signed with cosign ECDSA key
refreshInterval: 30m
ModuleSource types:
| Type | Location | Versioning | Use case |
|---|---|---|---|
oci |
OCI registry | Semantic version tags | Official bundles, curated registries |
git |
GitHub/GitLab repo | One stream: version field in module.yaml | Community contributions, gitops-style |
http |
HTTP tar.gz/zip URL | One stream: content hash | Binary archives, air-gapped sources |
local |
Pod mount path | One stream: content hash | On-cluster module directory |
upload |
ConfigMaps in operator ns | One stream: content hash | Web dashboard uploads, manual entries |
Supply-chain security
Two mechanisms protect modules from tampering:
Digest pinning — Module.spec.digest pins the bundle to an exact OCI manifest digest:
spec:
name: minecraft-java
version: 1.0.0
digest: sha256:abc123… # install fails if the manifest changes
Signature verification (OCI sources only) — ModuleSource.spec.verify requires every bundle to carry a valid cosign signature:
verify:
key: { name: cosign-pub } # offline-verified ECDSA signature
requireTransparencyLog: false # require Sigstore Rekor entry (optional)
The official Gameplane modules are signed with an ECDSA P-256 key and recorded in the public Sigstore Rekor transparency log. Keyed verification is offline — no network required — so air-gapped clusters can verify signed bundles without sigstore connectivity.
Always pin digests and enable signature verification for production-critical modules. This prevents a compromised registry tag or mirror from pushing unexpected code into your cluster.
Installation and template materialization
Modules appear in the Modules page of the dashboard once a source is configured. Click Install to create a Module resource:
apiVersion: gameplane.local/v1alpha1
kind: Module
metadata: { name: minecraft-java }
spec:
source: { name: default } # ModuleSource name
name: minecraft-java # module name within the source
version: 1.0.0 # omit to track the source's latest
digest: sha256:abc123… # optional, enforce exact bundle
The operator pulls the artifact, parses module.yaml + template.yaml, and creates a GameTemplate owned by this Module. The template then appears in the “Create server” wizard. Deleting the Module deletes the GameTemplate, but the operator refuses deletion while servers still reference it.
If a module fails to upgrade (pull error, bad signature, incompatible operator), the previous template keeps running unchanged; the Module.status.previousVersion field records the last-known-good version for safe rollback.
Next steps
- Module Authoring Quickstart — scaffold and author your first module using
gp-moduleand the web dashboard. - GameTemplate Schema — detailed reference for
template.yamlfields: console protocols, config schema, capabilities, and mods. - Runtime Capabilities & Actions — add player moderation, backup quiesce, and operator buttons via template metadata.
- Test, Publish & Sign Modules — validate, package, and sign bundles for secure distribution.
- Modules & Sources (Hub) — operator-side view of module registries and installation.