{"id":147864,"date":"2026-06-09T00:03:45","date_gmt":"2026-06-08T21:03:45","guid":{"rendered":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/"},"modified":"2026-06-09T00:03:45","modified_gmt":"2026-06-08T21:03:45","slug":"staffchat-fabric","status":"publish","type":"mod","link":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/","title":{"rendered":"StaffChat"},"content":{"rendered":"<p># StaffChat<\/p>\n<p>**A private chat channel for your server&#8217;s staff team.** One command, one permission node, zero noise. Toggle into staff mode to keep the next conversation off public chat \u2014 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.<\/p>\n<p>> **StaffChat 1.0.0** \u2014 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.<\/p>\n<p>&#8212;<\/p>\n<p>## What it does<\/p>\n<p>Three ways to send to the staff channel, all gated by a single permission `staffchat.true`:<\/p>\n<p>&#8211; **`\/staffchat`** alone toggles &#8220;staff chat mode&#8221; \u2014 every regular chat line you type now goes to staff only until you toggle off. A title pulse + a persistent `\u25cf Staff Chat Mode` actionbar reminds you you&#8217;re in stealth mode so you never accidentally leak to global.<br \/>\n&#8211; **`\/staffchat <message>`** (or `\/sc <message>`) sends a one-off without changing your toggle state. Good for a quick reply mid-game.<br \/>\n&#8211; **`@<message>` quick prefix** in normal chat \u2014 type `@need help at spawn` and the message routes to staff only. The prefix character is configurable in case `@` clashes with your mention syntax.<\/p>\n<p>Staff who *aren&#8217;t* in toggle mode still **receive** every staff message. Toggle is purely a sending convenience \u2014 it doesn&#8217;t gate reception.<\/p>\n<p>## Mention pings<\/p>\n<p>Inside any staff message, drop `@<playername>` to ping that staff member:<br \/>\n&#8211; Their actionbar flashes `\u2605 Mentioned by <you>`<br \/>\n&#8211; A configurable chime plays (default: experience-orb pickup)<br \/>\n&#8211; Self-mentions skipped, offline \/ non-staff names skipped<\/p>\n<p>Sound id, volume, pitch, and actionbar template are all in the config.<\/p>\n<p>## Built for privacy<\/p>\n<p>This is a staff channel \u2014 leaks would be embarrassing. The mod is architected so:<\/p>\n<p>&#8211; **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.<br \/>\n&#8211; **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.<br \/>\n&#8211; **The only intended Discord mirror is the built-in webhook.** Off by default. Set `discord.enabled = true` and a webhook URL when you actually want staff mirrored to a specific Discord channel \u2014 at which point YOU control which channel sees it.<br \/>\n&#8211; The webhook posts with `allowed_mentions.parse = []` so a staff member typing `@everyone` doesn&#8217;t actually ping the Discord server.<\/p>\n<p>## Built-in Discord webhook (opt-in)<\/p>\n<p>Optional. Off by default. Set:<br \/>\n&#8220;`hocon<br \/>\ndiscord {<br \/>\n    enabled = true<br \/>\n    webhook-url = &#8220;https:\/\/discord.com\/api\/webhooks\/&#8230;\/&#8230;&#8221;<br \/>\n    username-format = &#8220;{sender}&#8221;<br \/>\n    avatar-url-format = &#8220;https:\/\/mc-heads.net\/avatar\/{uuid}&#8221;<br \/>\n    retries = 1<br \/>\n}<br \/>\n&#8220;`<br \/>\nAsync POST via Java 21&#8217;s `HttpClient` on a dedicated single-thread pool \u2014 never blocks the server tick. Failures retried up to `retries` times; misconfigured webhooks (4xx) auto-suppress for 5 minutes so a stale token doesn&#8217;t spam your console.<\/p>\n<p>## LuckPerms metadata prefixes (soft-dep)<\/p>\n<p>If LuckPerms is present, each sender&#8217;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:<\/p>\n<p>&#8220;`hocon<br \/>\nprefixes {<br \/>\n    owner = &#8220;&#038;c[Owner] &#8221;<br \/>\n    admin = &#8220;&#038;4[Admin] &#8221;<br \/>\n    mod   = &#8220;&#038;9[Mod] &#8221;<br \/>\n}<br \/>\n&#8220;`<\/p>\n<p>A player&#8217;s prefix is the first matching `staffchat.rank.<id>` they hold, in declaration order. Final fallback: blank.<\/p>\n<p>## Defensive design<\/p>\n<p>Same paranoid security patterns as our other server mods:<\/p>\n<p>&#8211; **Permission re-checked on every message send** \u2014 a staff member demoted between two messages silently drops off the recipient list with no leaking error.<br \/>\n&#8211; **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 &#8220;all formatting, no content&#8221; payloads.<br \/>\n&#8211; **Rate limit** \u2014 sliding 30-second window, default 10 messages per window, configurable. Sender gets a &#8220;slow down&#8221; reply, message dropped server-side, audit log records the rate-limit event.<br \/>\n&#8211; **`staffchat.bypass.rate-limit`** uses explicit-only permission resolution \u2014 OPs don&#8217;t auto-bypass unless LuckPerms specifically grants it.<br \/>\n&#8211; **Audit log** \u2014 every staff send appends to `logs\/staffchat-audit.log` with 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.<\/p>\n<p>## Permissions<\/p>\n<p>| Node | Default | Purpose |<br \/>\n|&#8212;|&#8212;|&#8212;|<br \/>\n| `staffchat.true` | OP 4 fallback | Send + receive in the staff channel |<br \/>\n| `staffchat.bypass.rate-limit` | **false** (explicit only) | Ignore the rate limit |<br \/>\n| `staffchat.admin.reload` | OP 3 | `\/staffchat reload` |<br \/>\n| `staffchat.admin.list` | OP 3 | `\/staffchat list` |<br \/>\n| `staffchat.rank.<id>` | \u2014 | Fallback prefix tier when LuckPerms is absent |<\/p>\n<p>Without a permissions plugin: `\/op <name>` is enough \u2014 OP 4 satisfies the `staffchat.true` fallback.<\/p>\n<p>With LuckPerms: `lp group default permission set staffchat.true false` then grant per-rank.<\/p>\n<p>## Commands<\/p>\n<p>&#8220;`<br \/>\n\/staffchat              Toggle staff chat mode              (staffchat.true)<br \/>\n\/staffchat <message>    One-off send (no toggle change)     (staffchat.true)<br \/>\n\/staffchat reload       Reload config from disk             (staffchat.admin.reload)<br \/>\n\/staffchat list         List currently-online staff         (staffchat.admin.list)<br \/>\n\/sc                     Alias for \/staffchat toggle<br \/>\n\/sc <message>           Alias for \/staffchat <message><br \/>\n&#8220;`<\/p>\n<p>## Configuration<\/p>\n<p>`config\/staffchat\/config.conf` is HOCON. Notable knobs:<\/p>\n<p>&#8220;`hocon<br \/>\nstaffchat {<br \/>\n    chat {<br \/>\n        format            = &#8220;&#038;8[&#038;cSTAFF&#038;8] &#038;f{prefix}&#038;7{sender}&#038;8: &#038;f{message}&#8221;<br \/>\n        quick-prefix      = &#8220;@&#8221;        # set to &#8220;&#8221; to disable<br \/>\n        max-length        = 256<br \/>\n        toggle-indicator  = &#8220;&#038;c\u25cf Staff Chat Mode&#8221;<br \/>\n        toggle-on-title   = &#8220;&#038;c&#038;lStaff Chat ON&#8221;<br \/>\n        toggle-off-title  = &#8220;&#038;7&#038;lStaff Chat OFF&#8221;<br \/>\n    }<br \/>\n    mentions {<br \/>\n        enabled         = true<br \/>\n        sound-id        = &#8220;minecraft:entity.experience_orb.pickup&#8221;<br \/>\n        sound-volume    = 0.7<br \/>\n        sound-pitch     = 1.2<br \/>\n        actionbar-text  = &#8220;&#038;e\u2605 Mentioned by {sender}&#8221;<br \/>\n    }<br \/>\n    discord {<br \/>\n        enabled            = false<br \/>\n        webhook-url        = &#8220;&#8221;<br \/>\n        username-format    = &#8220;{sender}&#8221;<br \/>\n        avatar-url-format  = &#8220;https:\/\/mc-heads.net\/avatar\/{uuid}&#8221;<br \/>\n        retries            = 1<br \/>\n    }<br \/>\n    prefixes { &#8230; }<br \/>\n    security {<br \/>\n        rate-limit-per-30s = 10<br \/>\n        log-to-file        = true<br \/>\n        log-file           = &#8220;logs\/staffchat-audit.log&#8221;<br \/>\n        log-to-console     = false<br \/>\n    }<br \/>\n    persist-toggled-state = true<br \/>\n    message-locale        = &#8220;auto&#8221;<br \/>\n    messages {}<br \/>\n}<br \/>\n&#8220;`<\/p>\n<p>Edit by hand and `\/staffchat reload`, or hot-reload to pick up edits live without bouncing the server.<\/p>\n<p>## i18n<\/p>\n<p>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.<\/p>\n<p>## Requirements<\/p>\n<p>Hard dependencies:<br \/>\n&#8211; **Minecraft 1.21.1**<br \/>\n&#8211; **Fabric Loader \u2265 0.16.0**<br \/>\n&#8211; **Fabric API**<br \/>\n&#8211; **Java 21**<\/p>\n<p>Bundled inside the jar \u2014 no extra installs:<br \/>\n&#8211; Fabric Permissions API<br \/>\n&#8211; SpongePowered Configurate HOCON<br \/>\n&#8211; Typesafe Config<\/p>\n<p>Optional soft dependency:<br \/>\n&#8211; **LuckPerms** \u2014 for `[Prefix]` metadata in staff messages.<\/p>\n<p>## What it intentionally is *not*<\/p>\n<p>&#8211; **Not a chat-bridge mod** \u2014 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.<br \/>\n&#8211; **Not a moderation tool** \u2014 no \/mute, \/kick, \/ban. Use vanilla or a moderation mod.<br \/>\n&#8211; **Not multi-channel** \u2014 one staff channel. If you want admin \/ mod \/ builder split channels, that&#8217;s planned for v1.1.<br \/>\n&#8211; **Not client-side** \u2014 runs server-side only, players need nothing installed.<\/p>\n<p>## Target audience<\/p>\n<p>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&#8217;t need. Drop the jar in `mods\/`, op yourself, type `\/staffchat` \u2014 done.<\/p>\n<p>&#8212;<\/p>\n<p>**License:** MIT<br \/>\n**Author:** souljagger<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A private chat channel for your server&#8217;s staff team.<\/p>\n","protected":false},"featured_media":147865,"template":"","meta":{"_minecraft_slug":"staffchat-fabric","_minecraft_project_id":"wYn2zpCf","_minecraft_author":"souljagger","_minecraft_license":"MIT","_minecraft_downloads":16,"_minecraft_follows":0,"_minecraft_client_side":"unsupported","_minecraft_server_side":"required","_minecraft_storage_type":"zip","_minecraft_archive_name":"staffchat-fabric.zip","_minecraft_size_bytes":1899257,"_minecraft_version_count":3,"_minecraft_updated_at":"2026-05-16T14:22:14.215963Z","_minecraft_date_created":"2026-05-01T06:36:35.151546Z","_minecraft_date_modified":"2026-04-16T17:08:18.317002Z","_minecraft_project_url":"https:\/\/modrinth.com\/mod\/staffchat-fabric","_minecraft_icon_attachment_id":147865,"_minecraft_imported_at":"2026-06-08T21:03:46+00:00","_minecraft_import_hash":"68fc420a58201385036363dcb98c2707","_minecraft_versions":"","_minecraft_links":"","_minecraft_gallery":"","_minecraft_api_metadata":""},"mod_category":[97,126,867,92],"mod_loader":[99],"minecraft_version":[37],"class_list":["post-147864","mod","type-mod","status-publish","has-post-thumbnail","hentry","mod_category-fabric","mod_category-management","mod_category-social","mod_category-utility","mod_loader-fabric","minecraft_version-1-21-1"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>StaffChat - Minecraft<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"StaffChat - Minecraft\" \/>\n<meta property=\"og:description\" content=\"A private chat channel for your server&#039;s staff team.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/\" \/>\n<meta property=\"og:site_name\" content=\"Minecraft\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/staffchat-fabric\\\/\",\"url\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/staffchat-fabric\\\/\",\"name\":\"StaffChat - Minecraft\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/staffchat-fabric\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/staffchat-fabric\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/staffchat-fabric-icon-98ba7d6179acb1017c10e0f29a38469a2ffb71ba_96.webp\",\"datePublished\":\"2026-06-08T21:03:45+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/staffchat-fabric\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/staffchat-fabric\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/staffchat-fabric\\\/#primaryimage\",\"url\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/staffchat-fabric-icon-98ba7d6179acb1017c10e0f29a38469a2ffb71ba_96.webp\",\"contentUrl\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/staffchat-fabric-icon-98ba7d6179acb1017c10e0f29a38469a2ffb71ba_96.webp\",\"width\":96,\"height\":96},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/staffchat-fabric\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Mods\",\"item\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"StaffChat\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/#website\",\"url\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/\",\"name\":\"Minecraft\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"StaffChat - Minecraft","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/","og_locale":"en_US","og_type":"article","og_title":"StaffChat - Minecraft","og_description":"A private chat channel for your server's staff team.","og_url":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/","og_site_name":"Minecraft","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/","url":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/","name":"StaffChat - Minecraft","isPartOf":{"@id":"https:\/\/vpesports.com\/minecraft\/#website"},"primaryImageOfPage":{"@id":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/#primaryimage"},"image":{"@id":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/#primaryimage"},"thumbnailUrl":"https:\/\/vpesports.com\/minecraft\/wp-content\/uploads\/2026\/06\/staffchat-fabric-icon-98ba7d6179acb1017c10e0f29a38469a2ffb71ba_96.webp","datePublished":"2026-06-08T21:03:45+00:00","breadcrumb":{"@id":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/#primaryimage","url":"https:\/\/vpesports.com\/minecraft\/wp-content\/uploads\/2026\/06\/staffchat-fabric-icon-98ba7d6179acb1017c10e0f29a38469a2ffb71ba_96.webp","contentUrl":"https:\/\/vpesports.com\/minecraft\/wp-content\/uploads\/2026\/06\/staffchat-fabric-icon-98ba7d6179acb1017c10e0f29a38469a2ffb71ba_96.webp","width":96,"height":96},{"@type":"BreadcrumbList","@id":"https:\/\/vpesports.com\/minecraft\/mods\/staffchat-fabric\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/vpesports.com\/minecraft\/"},{"@type":"ListItem","position":2,"name":"Mods","item":"https:\/\/vpesports.com\/minecraft\/mods\/"},{"@type":"ListItem","position":3,"name":"StaffChat"}]},{"@type":"WebSite","@id":"https:\/\/vpesports.com\/minecraft\/#website","url":"https:\/\/vpesports.com\/minecraft\/","name":"Minecraft","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/vpesports.com\/minecraft\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"}]}},"_links":{"self":[{"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/mod\/147864","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/mod"}],"about":[{"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/types\/mod"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/media\/147865"}],"wp:attachment":[{"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/media?parent=147864"}],"wp:term":[{"taxonomy":"mod_category","embeddable":true,"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/mod_category?post=147864"},{"taxonomy":"mod_loader","embeddable":true,"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/mod_loader?post=147864"},{"taxonomy":"minecraft_version","embeddable":true,"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/minecraft_version?post=147864"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}