A vibecoded version of the rust plobot. Since it's 100% AI-generated, it is not recommended to use, reference, host, maintain or fork this.
  • Rust 98.6%
  • JavaScript 1.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-23 18:03:33 +02:00
data another vibecoded commit 2026-09-23 18:03:33 +02:00
helper initial (and probably last) commit 2026-09-23 17:35:09 +02:00
src another vibecoded commit 2026-09-23 18:03:33 +02:00
.gitignore another vibecoded commit 2026-09-23 18:03:33 +02:00
Cargo.lock initial (and probably last) commit 2026-09-23 17:35:09 +02:00
Cargo.toml initial (and probably last) commit 2026-09-23 17:35:09 +02:00
README.md another vibecoded commit 2026-09-23 18:03:33 +02:00
rust-toolchain.toml initial (and probably last) commit 2026-09-23 17:35:09 +02:00

Plobot (Rust)

A Rust rewrite of Plobot, the Minecraft bot for Kaboom clones, built on azalea and tokio. It targets Minecraft 26.2.

It keeps the JavaScript version's behaviour: the same commands, help texts, data files and command-block-based output. Every plugin is ported except sh.

Requirements

  • Nightly Rust. azalea needs it; rust-toolchain.toml selects it automatically when you use rustup.
  • Linux on x86_64 or aarch64 for the Scheme plugin's sandbox (see below). Everything else runs anywhere azalea does.
  • Optional external programs, only needed by the plugins that use them: git (about), inxi (diag), ruby and bwrap (bubblewrap) (gs), and fizmo-console (zork).

Building and running

cd rustver
cargo build --release
./target/release/plobot [host] [port] [username] [prefix]

Defaults: kaboom.hcesaropz.dev, port 25565, username _dat, prefix ;. On the default port the bot looks up the server's _minecraft._tcp SRV record, like mineflayer. It then tries each of the server's addresses until one accepts a connection, so it still works on machines without IPv6.

Accounts are offline-mode.

Files

Plugin data lives in data/<plugin>/, relative to the working directory. Set PLOBOT_DATA to use another directory. For example, PLOBOT_DATA=../plugins reuses the JavaScript bot's existing files. Files the bot creates itself when they're missing:

File Plugin
alias/aliases.json alias
paste/pastes.json paste
onjoin/list.json onjoin
hangman/numberOfGuesses hangman
scheme/init.scm scheme
lastBotMentionReg.json "I'm a bot" reminders

Files you provide:

File Plugin
daily/*.txt (included), daily/words motd, wotd
hangman/words hangman
chess/game.pgn (optional; a new game starts if missing) chess
aotd/<lang>wiki-*.gz (Wikipedia title lists) aotd
message/message message
golfscript/golfscript.rb (download; not redistributable) gs
zork/zork1-r119-s880429.z3 zork

These stay in the working directory, like the JavaScript version:

  • spam_quota: how many times someone must say stop to stop the bot. If the file is missing, the limit is unlimited.
  • .die_requested is created when the bot is stopped from chat.
  • <host>_<port> (e.g. kaboom.hcesaropz.dev_25565) is checked every 10 seconds. Each line is queued as a command-block command, then the file is deleted. The JavaScript version evaled this file as JavaScript instead.

Scheme sandbox

User Scheme code runs in steel, in a separate worker process (the bot binary started with --scheme-worker). steel's own sandboxed engine still lets code require-builtin its filesystem and process modules. The real boundary is the operating system, not the interpreter. The worker:

  • gets an empty environment and / as its working directory,
  • talks to the bot over private pipes; its stdin, stdout and stderr are /dev/null,
  • is limited to 1 GiB of memory, no child processes and no core dumps,
  • installs a seccomp allowlist before running any user code. Only syscalls for computing and for using the pipes it already has are allowed. Opening files, reading file metadata, exec, sockets, threads and signalling other processes all fail with EPERM. If the filter can't be installed, the worker exits rather than run unsandboxed,
  • is killed after 3 seconds of evaluation, and when the bot exits.

The worker restarts automatically after a timeout or crash. It re-runs the default proc and init.scm, but loses anything user code defined at run time.

GolfScript sandbox

gs runs the reference interpreter, golfscript.rb, which builds string literals with Ruby's eval. That makes "#{...}" a real Ruby escape hatch. It's allowed, but Ruby runs inside bubblewrap:

  • read-only /usr and an empty private /tmp; nothing else from the host, including your home directory,
  • no network, and its own process, IPC and hostname namespaces,
  • an empty environment and a 1 GiB memory limit,
  • killed after 5 seconds, or when the bot exits.

Output is capped at 16 KiB. Without bwrap the command fails instead of running unsandboxed.

Architecture

  • src/main.rs: startup, azalea events, chat processing (one message at a time, in order), the emergency stop, and the periodic tasks.
  • src/chat.rs: works out who sent a chat line and what they said, using the same Kaboom-specific rules as the JavaScript version.
  • src/runner.rs: runs queued commands through a repeating command block. It uses the response-time curve from the main README (75 + (3000 - 75)(1 - e^(-αx)) ms), and places a new command block when none is within 16 blocks.
  • src/help.rs: help and its translations.
  • src/plugins/: one module per plugin, implementing the Plugin trait:
    • init registers help topics, creates files and starts background tasks.
    • preprocess rewrites a message's words before handlers see them.
    • handle responds to a message.
    • on_spawn, on_whisper and on_packet react to those events.

Adding a plugin: create src/plugins/<name>.rs, implement Plugin, and add it to plugins::all().

Testing

cargo test

helper/helper.js is a small mineflayer bot for testing on a live server. It joins as claude-helper and only adds a number if that name is taken. It sends each line from stdin as chat (or a command, if the line starts with /) and prints everything it sees in chat:

npm install                        # in the repository root
node rustver/helper/helper.js [host] [port] [version]

It defaults to kaboom.hcesaropz.dev and protocol version 26.1, the newest mineflayer supports; the server translates. Type .quit to leave.

Differences from the JavaScript version

  • sh is not ported.
  • The <host>_<port> file holds commands, not JavaScript.
  • Errors in one plugin are logged and don't stop the other plugins from handling the same message.
  • Private messages from names mineflayer's pattern misses (like claude-helper) are recognized.
  • gs runs Ruby inside a sandbox with a time limit (see above), and each program gets its own temporary file instead of a shared /tmp/my_script.gs.
  • Scheme code is run by steel instead of BiwaScheme, so the built-in functions and error messages differ.
  • serverinfo leaves out :25565 even when the port is given on the command line.
  • Commands that crashed the JavaScript version on bad input now just do nothing: hd with no text, onjoin before anyone joined, and chess with no saved game (which now starts a new one).