Compatibility
Minecraft: Java Edition
Platforms
Supported environments
Tags
Creators
Details
StaffChat
A private chat channel for your server's staff team. One command, one permission node, zero noise. Toggle into staff mode to keep the next conversation off public chat — or quick-fire a single line with @hello without ever leaving the global channel. Built so secret conversations never leak through Discord-bridge mods that mirror public chat.
StaffChat 1.0.0 — for Minecraft 1.21.1 / Fabric. Server-side only. No hard dependencies beyond Fabric API. LuckPerms optional. Drop it in
mods/, op yourself, and it works.
What it does
Three ways to send to the staff channel, all gated by a single permission staffchat.true:
/staffchatalone toggles "staff chat mode" — every regular chat line you type now goes to staff only until you toggle off. A title pulse + a persistent● Staff Chat Modeactionbar reminds you you're in stealth mode so you never accidentally leak to global./staffchat <message>(or/sc <message>) sends a one-off without changing your toggle state. Good for a quick reply mid-game.@<message>quick prefix in normal chat — type@need help at spawnand the message routes to staff only. The prefix character is configurable in case@clashes with your mention syntax.
Staff who aren't in toggle mode still receive every staff message. Toggle is purely a sending convenience — it doesn't gate reception.
Mention pings
Inside any staff message, drop @<playername> to ping that staff member:
- Their actionbar flashes
★ Mentioned by <you> - A configurable chime plays (default: experience-orb pickup)
- Self-mentions skipped, offline / non-staff names skipped
Sound id, volume, pitch, and actionbar template are all in the config.
Built for privacy
This is a staff channel — leaks would be embarrassing. The mod is architected so:
- Staff messages NEVER reach the global chat pipeline. We suppress at
ServerMessageEvents.ALLOW_CHAT_MESSAGE(return false) before any chat broadcast happens. No/say-spam fallback, no whispered-to-self exposure. - Other Discord chat-bridge mods do NOT pick up staff messages. Bridges like Styled Chat, ServerSideUtils, simple-discord-bridge etc. hook the chat-broadcast pipeline. Because we suppress at the ALLOW phase and re-deliver as system messages (not chat messages), those bridges never observe a staff line. Your secret conversations stay secret.
- The only intended Discord mirror is the built-in webhook. Off by default. Set
discord.enabled = trueand a webhook URL when you actually want staff mirrored to a specific Discord channel — at which point YOU control which channel sees it. - The webhook posts with
allowed_mentions.parse = []so a staff member typing@everyonedoesn't actually ping the Discord server.
Built-in Discord webhook (opt-in)
Optional. Off by default. Set:
discord {
enabled = true
webhook-url = "https://discord.com/api/webhooks/.../..."
username-format = "{sender}"
avatar-url-format = "https://mc-heads.net/avatar/{uuid}"
retries = 1
}
Async POST via Java 21's HttpClient on a dedicated single-thread pool — never blocks the server tick. Failures retried up to retries times; misconfigured webhooks (4xx) auto-suppress for 5 minutes so a stale token doesn't spam your console.
LuckPerms metadata prefixes (soft-dep)
If LuckPerms is present, each sender's [Prefix] from LuckPerms metadata is automatically prepended to their name in staff chat. Without LuckPerms, fall back to a config-based map keyed by staffchat.rank.<id> permission:
prefixes {
owner = "&c[Owner] "
admin = "&4[Admin] "
mod = "&9[Mod] "
}
A player's prefix is the first matching staffchat.rank.<id> they hold, in declaration order. Final fallback: blank.
Defensive design
Same paranoid security patterns as our other server mods:
- Permission re-checked on every message send — a staff member demoted between two messages silently drops off the recipient list with no leaking error.
- Input sanitizer strips control chars and the raw section-sign so nobody injects malformed Minecraft formatting; caps message length at
chat.max-length(default 256); rejects "all formatting, no content" payloads. - Rate limit — sliding 30-second window, default 10 messages per window, configurable. Sender gets a "slow down" reply, message dropped server-side, audit log records the rate-limit event.
staffchat.bypass.rate-limituses explicit-only permission resolution — OPs don't auto-bypass unless LuckPerms specifically grants it.- Audit log — every staff send appends to
logs/staffchat-audit.logwith an 8-char base36 transaction id, timestamp, sender UUID + name, sanitized content, recipient count, and outcome (DELIVERED / RATE_LIMITED / SANITIZED / DROPPED). Atomic appends, useful for incident review.
Permissions
| Node | Default | Purpose |
|---|---|---|
staffchat.true |
OP 4 fallback | Send + receive in the staff channel |
staffchat.bypass.rate-limit |
false (explicit only) | Ignore the rate limit |
staffchat.admin.reload |
OP 3 | /staffchat reload |
staffchat.admin.list |
OP 3 | /staffchat list |
staffchat.rank.<id> |
— | Fallback prefix tier when LuckPerms is absent |
Without a permissions plugin: /op <name> is enough — OP 4 satisfies the staffchat.true fallback.
With LuckPerms: lp group default permission set staffchat.true false then grant per-rank.
Commands
/staffchat Toggle staff chat mode (staffchat.true)
/staffchat <message> One-off send (no toggle change) (staffchat.true)
/staffchat reload Reload config from disk (staffchat.admin.reload)
/staffchat list List currently-online staff (staffchat.admin.list)
/sc Alias for /staffchat toggle
/sc <message> Alias for /staffchat <message>
Configuration
config/staffchat/config.conf is HOCON. Notable knobs:
staffchat {
chat {
format = "&8[&cSTAFF&8] &f{prefix}&7{sender}&8: &f{message}"
quick-prefix = "@" # set to "" to disable
max-length = 256
toggle-indicator = "&c● Staff Chat Mode"
toggle-on-title = "&c&lStaff Chat ON"
toggle-off-title = "&7&lStaff Chat OFF"
}
mentions {
enabled = true
sound-id = "minecraft:entity.experience_orb.pickup"
sound-volume = 0.7
sound-pitch = 1.2
actionbar-text = "&e★ Mentioned by {sender}"
}
discord {
enabled = false
webhook-url = ""
username-format = "{sender}"
avatar-url-format = "https://mc-heads.net/avatar/{uuid}"
retries = 1
}
prefixes { ... }
security {
rate-limit-per-30s = 10
log-to-file = true
log-file = "logs/staffchat-audit.log"
log-to-console = false
}
persist-toggled-state = true
message-locale = "auto"
messages {}
}
Edit by hand and /staffchat reload, or hot-reload to pick up edits live without bouncing the server.
i18n
English bundled. Drop config/staffchat/lang/<locale>.json to add any other language without rebuilding the jar. Loader prefers config-dir overrides over bundled resources, with en_us as the canonical fallback.
Requirements
Hard dependencies:
- Minecraft 1.21.1
- Fabric Loader ≥ 0.16.0
- Fabric API
- Java 21
Bundled inside the jar — no extra installs:
- Fabric Permissions API
- SpongePowered Configurate HOCON
- Typesafe Config
Optional soft dependency:
- LuckPerms — for
[Prefix]metadata in staff messages.
What it intentionally is not
- Not a chat-bridge mod — the optional Discord webhook only mirrors the staff channel. It does not bridge global chat to Discord. Use a real chat-bridge mod for that.
- Not a moderation tool — no /mute, /kick, /ban. Use vanilla or a moderation mod.
- Not multi-channel — one staff channel. If you want admin / mod / builder split channels, that's planned for v1.1.
- Not client-side — runs server-side only, players need nothing installed.
Target audience
Server operators who want a quick, reliable, Discord-isolated way for their staff to talk in-game without spinning up Slack, a side voice channel, or a moderation suite they don't need. Drop the jar in mods/, op yourself, type /staffchat — done.
License: MIT Author: souljagger


