No description
  • TypeScript 82.8%
  • Svelte 17.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-23 15:42:56 +02:00
backend feat(commands): a command line with completion, and the catalogue as reference 2026-09-23 14:37:20 +02:00
docs feat(routers): mc-router as a thing you can create, edit and apply 2026-09-23 14:37:18 +02:00
frontend fix(frontend): return early from in-flight actions so a double click sends one request 2026-09-23 15:21:38 +02:00
shared feat(versions): pick a version from a list, and move between them 2026-09-23 14:37:17 +02:00
templates fix(new): behind a router, publish no port and apply the mapping 2026-09-23 14:37:19 +02:00
.gitignore feat(logs): parse server and init logs into typed events (F2) 2026-09-23 14:37:07 +02:00
CLAUDE.md feat: scaffold minecraft module with user stories and design docs 2026-09-21 12:37:10 +02:00
opsdeck.module.json feat: scaffold minecraft module with user stories and design docs 2026-09-21 12:37:10 +02:00
README.md docs: describe what the module does, not what it will 2026-09-23 14:37:15 +02:00
tsconfig.check.json feat(servers): discover, state, players and files, read-only (M1) 2026-09-23 14:37:12 +02:00

OpsDeck module: minecraft

Tooling around itzg/minecraft-server stacks for OpsDeck — without taking the compose files away from you.

The compose file is the source of truth. The module reads it, explains it, edits it in place with your consent (diff first, docker compose up -d as a tracked task), and keeps anything of its own inside the project as an x-opsdeck-minecraft extension field. Delete the module and you have an ordinary stack.

docs/user-stories.md is the specification; docs/roadmap.md records which story each part serves and what is still missing.

What it does

Sees your servers. Every container whose image is itzg/minecraft-server, grouped by compose project, plus stacks that are defined but not running when a stacks directory is configured. A container docker run started is listed too, with editing disabled because there is no file to edit.

Knows what "up" means. ready is the server having logged Done (…)!, not the container being green: a modpack install sits in installing for ten minutes, an init script that gave up leaves a container running with no Java in it, and autopause is its own state. Every state carries the log line that decided it.

Talks to the server. An interactive console (rcon-cli over a hijacked docker exec), one-shot commands, twenty-three built-in shortcuts with typed arguments, and your own shortcuts declared in the compose file. The RCON password never reaches OpsDeck: rcon-cli reads it from the container's own environment.

Edits the stack. A change is prepared as a diff, validated by docker compose config without writing anything, and applied as a core task that writes the files and runs up -d. The previous version is a git commit when the directory is a work tree, a sibling file when it is not.

Installs things. One search over Modrinth, CurseForge, FTB, Hangar, Spiget and Vanilla Tweaks with your server's loader and version already applied; an install writes exactly the variables the image documents — and shows them to you as a diff before anything is written.

Measures. Players, CPU, memory, network, Can't keep up! events per minute, and TPS/MSPT where the server type reports them. Old logs, crash reports, disk usage per directory, a real server-list ping, playtime per player.

Keeps. Worlds with their seed, spawn, size and gamerules; mc-backup sidecars with backup now and a restore; a world download as a zip; a scheduled restart with an announcement, a skip while players are online and a gate on the backup.

Everywhere. Thirteen pages in the portable UI schema — the Android app renders them natively — and the same thirteen as Svelte pages on the web. Browsing the registries is web-only, and the schema page says so.

Pages

Page What
Servers every server, its state and player count; a dashboard card with the same
Server state and why, players, chat, ports, last start
Commands the built-in shortcuts, with the ones this server type does not have explained
Console rcon-cli in a terminal, and a one-shot line with history and completion
Install search and install packs, mods, plugins, datapacks and resource packs
Versions Mojang, Paper, Fabric, Forge and NeoForge against what this stack pins
Measurements the ping, the charts, the disk breakdown, playtime, logs and crash reports
World worlds, seed, gamerules, backups, the world download, your own shortcuts, how players connect
Stack the files, the effective config, what drifted, the git history
Settings memory against the container limit and the host, the tuning switches, one form to change a variable
server.properties each line with the variable that produces it
Pending change the diff, what compose said about it, and Apply
New server a few answers, a compose file you own, started by nobody

Configuration

Environment, prefix OPSDECK_MOD_MINECRAFT_:

Variable Meaning
STACKS_DIR host directory scanned for compose files of stacks that are not running; also where a new stack is scaffolded. Without it, only running containers are found
IMAGE_PATTERNS extra image references to treat as the server image (registry mirrors), comma-separated
CF_API_KEY CurseForge Core API key for SEARCH. Installing works without it — the image carries its own key on Java 17+
CONSOLE 0 disables the interactive console for the whole module
HEADS_URL player-head service URL template, default https://mc-heads.net/avatar/{id}/64
DISK_WARN_PCT free-space threshold for the low-disk alert, default 10

Host requirements:

  • The Docker socket configured for OpsDeck — discovery, logs, exec and the console all go through the engine API.
  • Host command execution (ctx.host) for anything that runs docker compose: editing, applying, lifecycle, drift. Without it the module is read-only and says so.
  • Write access to where your stacks live. In the container that is covered by the /host/root mount; in a bare checkout the server's --allow-write list has to include the stacks directory.

What it deliberately does not do

  • Replace compose. No abstraction layer, no generated file you do not own, no managed mode.
  • Hold your secrets. The RCON password is read by rcon-cli inside the container; the module never reads, stores or passes it. Registry keys are module configuration and are never written into a stack.
  • Accept the EULA for you. Every path that could set EULA=TRUE requires you to say so, and the scaffold writes what you answered.
  • Reimplement the docker module. Image updates, pins and container actions are linked, not duplicated.

Dev loop

deno test --allow-read --allow-write --allow-run=git,python3 --allow-env backend/
cp -r . <core>/packages/modules/minecraft && cd <core>
deno check packages/modules/minecraft/backend/mod.ts
deno run -A npm:svelte-check@^4 --workspace packages/modules/minecraft \
  --tsconfig ./tsconfig.check.json --threshold error
deno task build:modules
OPSDECK_AUTH=disabled OPSDECK_MODULES=activity,docker,minecraft \
  OPSDECK_MOD_MINECRAFT_STACKS_DIR=<your stacks> deno task start

The tests need no network and no Docker: the log fixtures under backend/logs/testdata and the API fixtures under backend/registries/testdata are recorded from real servers and real registries. LIVE=1 additionally runs one smoke test per registry against the live API.

Remove the copy from the core checkout afterwards; this repository is the source of truth.

Production: OPSDECK_EXTERNAL_MODULES=<git-url>#<sha> on the host.

Documents

File What
docs/user-stories.md the stories, grouped by epic, each with the failure it prevents
docs/roadmap.md milestones, and the status of every story with what is missing
docs/design.md how the stories map onto the module contract, including the corrections the implementation forced
docs/core-requests.md what a core change would let this module delete
docs/registries.md endpoints, auth, limits, and the env vars each install writes
docs/itzg-reference.md the image's variables the module encodes