First-boot server provisioner. Named by Holly. Architecture per Gemini 4-round
consultation. Drops a provision.json in server root, mod runs once on
ServerStartedEvent: pastes spawn schematic, places TP command blocks pointing
at the original level.dat spawn, sets worldspawn, gamerules, YAWP region file,
self-destructs by renaming jar to .jar.disabled.
Files (services/bitch-bot/1.21.1/):
- build.gradle / settings.gradle / gradle.properties / gradle wrapper (mirrors rules-mod 1.21.1)
- META-INF/neoforge.mods.toml
- BitchBot.java — @Mod entry, ServerStartedEvent listener, Throwable net
- Provisioner.java — sequenced step runner, per-step try/catch, success tracking gates self-destruct
- ProvisionConfig.java — Gson POJO matching provision.json schema verbatim
- SchematicLoader.java — HTTP download + SHA-256 verify + Sponge v2 .schem parser (NbtIo + varint + BlockStateParser palette)
- CommandBlockPlacer.java — impulse command blocks with /tp @p baked into CommandBlockEntity
- SignPlacer.java — oak signs, 4-line front text via SignBlockEntity#setText
- YawpConfigWriter.java — drops region JSON to world/serverconfig/yawp/regions/{name}.json
- SelfDestruct.java — ProtectionDomain → CodeSource → jar rename, Windows fallback to deleteOnExit
Plus services/bitch-bot/CLAUDE.md (project doc) and sample-provision.json.
NOT COMPILED — no Java/Gradle on Nitro per repo CLAUDE.md. Compile on Dev Panel:
cd /opt/mod-builds/firefrost-services/services/bitch-bot/1.21.1
source use-java 21
/opt/gradle-8.8/bin/gradle build --no-daemon
Risk areas flagged in CLAUDE.md for first compile: schematic parser (untested
against real WorldEdit output), YAWP file format (best-guess schema).
4.6 KiB
4.6 KiB
Bitch Bot — First-Boot Server Provisioner
Named by: Holly (The Catalyst)
Architecture: Locked via 4-round Gemini consultation — see firefrost-operations-manual/docs/consultations/gemini-modpack-installer-followup-2026-04-15.md
REQ: docs/code-bridge/archive/REQ-2026-04-15-bitch-bot.md
Status: Source scaffold complete on Nitro. Compile on Dev Panel.
Project Structure
1.21.1/— NeoForge (Java 21, Gradle 8.8, moddev 2.0.141) — primary target- (1.20.1/Forge port can be added later if needed)
What Bitch Bot Does
On ServerStartedEvent, if provision.json exists in the server root:
- Reads original spawn coords from
level.datvialevel.getSharedSpawnPos() - Downloads the schematic from
schematic_url, verifies SHA-256 againstschematic_hash - Pastes Sponge Schematic v2 (
.schem) atspawn_coords(centered ifpaste_origin == "center") - Places impulse command blocks at every position in
command_blocks[]with/tp @p [orig_x] [orig_y] [orig_z]baked into NBT - Places oak signs at every entry in
rules_signs[]with up to 4 lines each - Sets worldspawn to
spawn_coords + worldspawn_offset - Sets gamerule
doFireTick false - Writes a YAWP region config to
world/serverconfig/yawp/regions/{name}.json - If
self_destruct_on_success: trueAND every step succeeded: renamesBitchBot-1.0.0-neoforge-1.21.1.jar→.jar.disabled - Renames
provision.json→provision.json.appliedso it doesn't re-trigger
Failure Behavior
- Every step is independently try/catch'd. A failure logs and moves on.
- If ANY step fails, self-destruct does NOT fire — admin can fix the issue and reboot for retry.
- The server is NEVER crashed by Bitch Bot. The outermost handler in
BitchBot.onServerStartedis aThrowablenet.
Source Files
src/main/java/com/firefrostgaming/bitchbot/
├── BitchBot.java # @Mod entry, ServerStartedEvent listener
├── Provisioner.java # Sequenced step runner + success tracking
├── ProvisionConfig.java # Gson POJO for provision.json
├── SchematicLoader.java # HTTP download + SHA-256 + Sponge v2 NBT parser + paste
├── CommandBlockPlacer.java # Impulse command blocks with TP NBT
├── SignPlacer.java # Oak signs with 4 lines of front text
├── YawpConfigWriter.java # Drops YAWP region JSON to world/serverconfig/yawp/regions/
└── SelfDestruct.java # Locates own jar via ProtectionDomain, renames to .jar.disabled
Building (Dev Panel only — no Java/Gradle on Nitro)
cd /opt/mod-builds/firefrost-services/services/bitch-bot/1.21.1
source use-java 21
/opt/gradle-8.8/bin/gradle build --no-daemon
# Output: build/libs/BitchBot-1.0.0-neoforge-1.21.1.jar
Provisioning a New Server
- Drop the jar into the server's
mods/folder - Drop a populated
provision.json(seesample-provision.json) into the server root (next toserver.properties) - Boot the server
- Watch the log — Bitch Bot prints every step to
[BitchBot]lines - Once provisioning is reported successful, the jar renames itself to
.jar.disabledand provision.json renames to.applied
Architectural Notes from Gemini
- Do NOT write to .mca region files from Node.js — corruption-prone on 1.20+. The whole reason Bitch Bot exists as a real mod and not Node-side region manipulation.
- Do NOT rely on RCON or WorldEdit console — everything is in-process via the Forge API.
- YAWP config is written as a dropped file in
world/serverconfig/yawp/regions/{name}.json. If the on-disk format diverges from what YAWP expects, fixYawpConfigWriter.java— it's the only file that touches the format. - BlockEntities and Entities tags in the .schem are ignored. Spawn buildings should be vanilla blocks only. (If we later need item frames or armor stands, extend
SchematicLoader.pasteAt.)
Risk Areas to Test on First Real Run
- Schematic parsing — only tested against the Sponge v2 spec, not against real WorldEdit
.schemoutput. If parsing fails, palette key strings or varint stream encoding may need tweaks. - Command block NBT —
cbe.getCommandBlock().setCommand(...)should persist, but verify the command actually fires when a player presses the button on top. - Self-destruct on Linux — every Firefrost server is Linux, so
Files.moveshould work in-place. Windows fallback usesdeleteOnExit. - YAWP file format —
YawpConfigWriterwrites a reasonable JSON shape but the actual YAWP mod schema may need adjustment. Watch for "region not loaded" warnings on second boot.