README.MD
GlassFrame Protocol
A layered, self-contained security engine for discord.js v14 bots. Four independently-toggleable layers - AntiRaid, AntiNuke, Basic Security, and Groq-powered AI Moderation - share one threat-scoring and punishment pipeline instead of each reacting on its own, so the same member never gets hit by four different modules for one incident, and a single soft flag never turns into an auto-ban.
Everything is per-server: one bot process can run GlassFrame across many Discord servers, each with its own independent set of active layers and its own whitelist, persisted across restarts. See docs/STATE.md.
No slash commands - prefix commands only. No legacy EmbedBuilder - every
log message renders through Discord's Components V2 system. No emoji
anywhere in code or output.
Install
GlassFrame Protocol is published on npm. From your bot project:
npm install glassframe-protocol
discord.js is a listed dependency and installs automatically alongside
it. If your project doesn't already have its own copy, install it
explicitly too:
npm install glassframe-protocol discord.js
Requires discord.js v14.16+ (Components V2 support and the
guildAuditLogEntryCreate event) and Node.js 18+ (global fetch, used only
by the optional AI layer). New to Node/npm? See Getting Started, Step 1.
Required intents
const { Client, GatewayIntentBits } = require("discord.js");
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildModeration
]
});
Required bot permissions
Manage Roles, Kick Members, Ban Members, Manage Channels, Manage Webhooks,
View Audit Log, Moderate Members (timeout), Manage Messages. GlassFrame's
own role must sit above any role/member it needs to act on -
RoleAnalyzer checks this before every action instead of attempting and
failing.
Usage
const GlassFrame = require("glassframe-protocol");
client.once("ready", () => {
const frame = new GlassFrame(client, {
getLogChannel: async (guild) =>
guild.channels.cache.find((c) => c.name === "security-logs") ?? null,
whitelist: ["123456789012345678"], // trusted everywhere, seeded into every guild on first run
autoStart: ["basicSecurity"], // starting layers for every guild - not a global on/off
config: {
antiRaid: { joinThreshold: 8 },
aiModeration: { apiKeys: [process.env.GROQ_KEY_1, process.env.GROQ_KEY_2].filter(Boolean) }
}
});
frame.on("warning", (w) => console.warn(`[GlassFrame:${w.layer}]`, w.message));
});
client.login(process.env.BOT_TOKEN);
Send !gf panel in any channel (Manage Server permission required) to get
the 5-button control panel and arm layers from there instead of in code.
The four layers
- Basic Security - spam rate, duplicate flood, mention spam, a
dedicated trust-aware @everyone/@here guard, local NLP scam/phishing/
raid-recruitment scoring (including a specific invite-link +
raid-language combo check), and link checks via
PhishingDatabase(a server-editable blocklist plus raw-IP/punycode/brand-look-alike/shortener heuristics -!gf phishing add/remove/list). - AntiRaid - join-velocity lockdown with automatic verification-level raise/restore, a composite alt-account score (account age, username entropy, missing avatar), and creation-time cluster correlation that catches a raid trickling in too slowly to trip the rate counter.
- AntiNuke - audit-log burst detection across channels, roles, bans, kicks, webhooks, emoji, and stickers per executor; a dangerous permission-grant watchdog covering both a role's own permissions changing and a member being quietly handed an already-dangerous role (with optional auto-revert); a channel permission-overwrite watchdog (catches @everyone getting locked out of, or let into, a channel without anything being deleted); a server-identity watchdog (name/icon/vanity URL changes); an invite-abuse watchdog (unrestricted invites from non-staff); and webhook-flood containment (deletes an abusive webhook and traces it back to its creator, since webhook messages carry no guild member for other layers to see).
- AI Moderation (optional, off by default) - Groq-powered second opinion
for messages the local NLP scores as "gray zone": not clean, not clearly
over threshold. Supports a pool of API keys with automatic per-key
cooldown on rate limits. See
config.aiModerationanddocs/CACHE_ARCHITECTURE.mdfor how verdicts get cached and keys rotated.
Every layer starts disabled, per guild. Nothing runs until you list it in
autoStart, call frame.enableLayer(name, guildId), or arm it from the
control panel. Add your own layer alongside these four with
frame.registerLayer() - see Extending it below.
Performance under load
Every Discord mutation PunishmentEngine performs and every outbound Groq
request go through a bounded-concurrency queue (frame.actionQueue /
frame.aiQueue) instead of firing unbounded, so a burst can't trip a rate
limit by hammering it all at once. !gf metrics shows this server's numbers
by default (open cases, flagged members, active layers), with a button on
the message to switch to bot-wide totals across every server
(frame.getMetrics() / frame.getGuildMetrics(guildId)). Full write-up in
docs/PERFORMANCE.md.
How punishment works
Layers never ban/kick/timeout directly - they report a signal
({ layer, weight, reason }) to a shared ThreatEngine, which keeps one
decaying risk score per member. PunishmentEngine turns that score into an
action, but only after RoleAnalyzer confirms the bot can actually act on
the member and checks their real trust level (a genuine admin is flagged
for human review, never auto-banned), and only if there isn't already an
open case for that member from a moment ago. Full write-up in
docs/PROTOCOL_LAYERS.md.
Extending it
frame.registerLayer(name, layerInstance)- add your own security layer to the same pipeline the built-in four use (per-guild enable/state/ persistence come free from extendingcore/Layer). Doesn't get a button on the panel automatically - the panel stays fixed at exactly 5.frame.registerAction(name, handler)- add a custom punishment action beyond ban/kick/timeout/quarantine, referenceable fromconfig.punishment.ladder.!gf prefix set <newPrefix>- each server can run its own prefix;config.prefixalways still works everywhere as a fallback.getLogChannel(guild, layerName)- route different layers to different channels, if you want; the second parameter is optional and backward compatible.!gf engine- an owner-only, bot-wide dashboard (busiest server, AI usage, live cross-server activity feed), gated separately from every other command and not listed in!gf help. Seedocs/ENGINE.md.
Docs
GETTING_STARTED.md- adding GlassFrame to a bot you already have running.docs/PROTOCOL_LAYERS.md- full architecture: containment vs. punishment, how a signal becomes an action,registerLayer/registerAction.docs/STATE.md- per-guild layer/whitelist state and how persistence across restarts works.docs/CACHE_ARCHITECTURE.md- every cache in the library, its key shape, its TTL, and how to turn on cache-level debug logging.docs/PERFORMANCE.md- the bounded-concurrency queues and internal metrics collector, and what!gf metricsshows.docs/ENGINE.md- the owner-only bot-wide dashboard: the password/lockout system and what each of its 5 pages shows.docs/COMMANDS.md- the full prefix command reference and the control panel's five buttons.CHANGELOG.md- version history.
Tuning
Every threshold lives in config.js. Start with the defaults, watch the
security log channel for a week, and adjust - a very active server needs
higher spam/mention thresholds than a quiet one, though config is one
merged object for the whole bot process rather than settable per guild.
frame.threatEngine and frame.punishmentEngine are both plain properties
on the returned instance if you want to inspect scores or open cases at
runtime - both are also EventEmitters (signal and case
respectively), alongside frame's own warning, layerToggled, and
layerRegistered events. See Events and Scope in Protocol Layers for the full
picture - layer on/off, the whitelist, and (as of v2.1.0) the per-server
command prefix are correctly per-guild; the phishing blocklist and
config itself are the two things still shared across every guild.