Moderation on one ledger
Warn, timeout, kick, ban, unban, untimeout and note each write a numbered
case. Numbers are never reused, so “case 42” stays a reference a member can
appeal against.
Automatic and human actions write to the same ledger — a warning
issued this morning counts toward the escalation this afternoon. A case
records whether a rule fired or a person acted and refuses to blur the two.
Notes and reversals are recorded but do not count as strikes, so nobody is
escalated for being forgiven.
Auto-moderation that remembers
Discord’s own rules run server-side and cost nothing per message. On top of
that a client-side engine exists for one reason: Discord blocks a message
but never notices it is the member’s fourth today. The ledger drives an
escalation ladder with per-role ceilings, exempt roles and channels, and a
strike-expiry window.
When the engine acts it deletes the message and, by default, keeps the first
400 characters of it on the case — often the only copy left anywhere. It is
kept so the record a member appeals against does not describe evidence that
no longer exists. Switchable off per server.
How that data is handled →
A door guard for raids
Screens arriving accounts on signals already in the join event, with no extra
API call — because a raid is exactly when the rate limit is worst. Account
age, default avatar, machine-shaped usernames, unverified apps, members
wearing another server’s tag. Match any or all, with an exempt list.
For cleanup after one gets through, sweep:preview and
sweep:act share a selection, so the list you read is the list
that gets acted on.
Roles that survive a restart
Self-assign panels of buttons and select menus. Temporary roles whose expiry
is an absolute timestamp swept by a background job, so a restart cannot lose
a pending revocation. Sticky roles hand a returning member back what they
left with. roles:sync back-fills across an existing membership,
writes its progress down, and resumes where it stopped.
Every grant passes one privilege-escalation guard, re-checked against Discord
rather than trusted from a session.
Onboarding, feeds and the rest
Welcome cards with alternate wordings, a hold-before-posting delay and an
auto-delete-after. A click-to-verify gate that is a button rather than a
reaction — idempotent, answered privately, and it survives a rejoin.
Feeds poll releases and any RSS or Atom URL; channel feeds resolve from a
handle, a video URL or an id, with no API key. Signed inbound webhooks
deduplicate and deliver durably with bounded retry and rotatable secrets.
Experience per message on a cooldown, so rank measures presence rather than
volume. Custom answers published as real guild slash commands.