Skip to content

Configuration

All files live under plugins/DaisyFilter/.

FilePurpose
filters/Every rule DaisyFilter matches on. Editable YAML packs, loaded at runtime (see filters.md).
config.ymlCore toggles: server label, monitor-only mode, surfaces, command profiles, filter limits, performance.
messages.ymlPlayer-facing and staff-alert messages (MiniMessage).
categories.ymlCategory severities and dispositions (see categories.md).
actions.ymlAction/effect wiring (see actions.md).
custom-rules.ymlServer-defined literals and RE2/J-safe regular expressions. Kept for compatibility; new rules belong in filters/90-custom.yml.
names.ymlScanning of usernames, nicknames, and entity name tags (see below).
spam.ymlSliding windows, duplicate/similarity, caps/punctuation/character limits.
escalation.ymlSeverity-point escalation and opt-in punishments (disabled by default).
allowlist.ymlBenign words and permitted domains that suppress matches.
discord.ymlAll Discord output (off by default): the bot, which posts incidents including what the player wrote and lets staff punish from Discord, plus the metadata-only webhook used as its fallback. See discord.md.
storage.ymlSculkData database connection.
moderation-storage.ymlEvidence privacy, retention, and write-queue settings.
gui.ymlGUI appearance.
runtime-overrides.ymlMachine-managed; written by the GUI and the monitor, alerts, allow, unallow, and rule commands. Also holds integration edits made in the Integrations menu, including the webhook URL and bot token, so protect it like discord.yml. Do not hand-edit.
exports/Generated export archives.
secrets/Generated encryption keys. Never commit or share.

DaisyFilter writes any missing file on start and never overwrites one you already have — your edits and your filters/90-custom.yml survive every update.

The first start also needs outbound network access: the database drivers are fetched by Paper’s library loader rather than shipped in the jar. See troubleshooting.md.

Run /daisyfilter reload. DaisyFilter re-reads the configuration files and every pack in filters/, recompiles the rules and allowlist off-thread, and swaps the live snapshot atomically only if compilation succeeds; a failed reload keeps the previous snapshot active.

Some settings require a restart:

  • the storage backend (storage.yml database type),
  • spam/abuse tuning (spam.yml) apart from the signals block,
  • escalation structure (escalation.yml),
  • the chat listener priority (config.ymlcompatibility.chat-priority).

runtime-overrides.yml is never destructively rewritten over your commented human-authored files — it only holds machine-managed state.

  • monitor-only: force MONITOR for everything (logs and alerts, never blocks). Toggle at runtime with /daisyfilter monitor on|off.
  • surfaces: enable/disable chat, commands, signs, books, anvils individually.
  • filter.max-input-length (default 1280): hard scan ceiling in code points for a single scan. Text longer than this is rejected rather than filtered, so keep it above the largest legitimate input — a book page holds ~1024 characters, and pages and sign lines are scanned individually. Treat it as an abuse guard against crafted oversized payloads, not a performance knob.
  • filter.max-book-scan-length (default 32768): total code points scanned across one book edit. Needed because a book is scanned page by page, so per-scan limits leave the edit as a whole unbounded — and unlike chat, book edits run on the main thread. A book over the budget is rejected unscanned. The default clears a full vanilla-typed book (~25k code points) and only bites on pages packed past what a client can type.
  • Only chat is scanned off the main thread. Commands, signs, books, and anvils are scanned inline on the server thread, which is why their input bounds matter.
  • commands.monitored-roots / recipient-roots: which commands are scanned and which skip a recipient argument.

A slur in a username or a pet’s name tag is visible to every child on the server, so names are scanned by the same rules as chat.

SettingDefaultDoes
scan-player-namestrueScan the account username when a player joins.
scan-nicknamestrueScan nicknames set in-game through the commands below.
scan-entity-namestrueScan player-set entity names, such as name tags on pets and armour stands.
deny-login-on-blockfalseRefuse the login outright when a username is blocked.
deny-login-messageMiniMessage shown on the disconnect screen when a login is refused.
nickname-commandsnick, nickname, setnickCommand roots treated as nickname changes. No leading slash.

deny-login-on-block is off on purpose. A false positive on a message censors one line; a false positive on a username locks a real player out of your server with no way to appeal in game. The default is to let them in and alert staff, who can rename, mute, or ban with a human in the loop. Only enable it if you accept that trade — a strictly whitelisted server for young children, say.

Names carry no spaces, so they are split into tokens before scanning. That is what makes a whole-word rule catch a name with digits stuck on the end.

Each spam signal has its own disposition and severity, rather than every signal forcing a block. Shouting is not the same offence as flooding chat, so the flood-style signals default to CENSOR:

SignalDefaultWhat CENSOR does
rate (all surfaces), duplicate-message, similar-message, word-floodBLOCK
caps-floodCENSORlowercases the message
character-flood, punctuation-flood, repeated-punctuationCENSORcollapses runs to two characters

Valid dispositions are BLOCK, CENSOR, MONITOR, and ALLOW (ALLOW records the signal but takes no action on the message). When several signals fire at once the strongest disposition wins.

Note that CENSOR only makes sense for a signal that has a defined repair — a spam signal has no matched span to star out, so word-flood stays on BLOCK: there is no sensible way to rewrite it, and censoring would pass the message through unchanged.

The signals block takes effect on /daisyfilter reload. The detection thresholds above it (windows, percentages, limits) still require a restart.

Staff with daisyfilter.alerts receive in-game incident notifications. By default alerting is aggressive so staff can intervene in real time:

  • alert-on-block (default true): alert on every blocked message, even if the matched rule did not explicitly request an alert.
  • censor-alert-min-severity (default 2): also alert when a message is censored at or above this severity, so censored slurs/profanity are no longer silent. Raise it (e.g. 4) for a quieter channel, or set 0 to disable censor alerts.
  • sound (default true): play a sound to alerted staff so incidents are not missed in busy chat. sound-key is used normally and urgent-sound-key for high-severity incidents (severity ≥ urgent-severity, default 4 — slurs, grooming, safety risks). High-severity alerts also bypass the grouping cooldown so they are never dropped.

Each staffer can mute their own alerts with /daisyfilter alerts off.

Chat-plugin compatibility (config.ymlcompatibility)

Section titled “Chat-plugin compatibility (config.yml → compatibility)”

DaisyFilter hooks Paper’s AsyncChatEvent and edits the message component to censor, so renderer-based formatters (EssentialsX Chat, LuckPerms/Vault formatting, etc.) display the censored text automatically.

  • chat-priority (default LOWEST): the event priority of the chat listener. Running early lets the filter block or censor a message before chat-formatting or channel plugins broadcast or log it. Valid values: LOWEST, LOW, NORMAL, HIGH, HIGHEST. Raise it only if another plugin must transform chat before the filter sees it. Takes effect on restart.

If a chat plugin cancels AsyncChatEvent and re-broadcasts through its own system (some channel plugins do), make sure DaisyFilter runs before it — keep chat-priority low. On a proxy network, run DaisyFilter on each backend server, not the proxy.

Menu layout is fixed (consistent, hand-tuned), but appearance is themable:

  • theme.pink / blue / lilac / mint: brand colours (hex) used for headings, accents, and the pink-to-blue gradient.
  • theme.border-material / filler-material: the pane materials framing menus. Unknown material names fall back to the defaults with a console warning.
  • theme.use-player-heads: show real player-face skulls on player menus (built from the stored UUID — no main-thread lookup). Disable for plain heads.
  • theme.glow-primary-actions: add a glow to primary buttons (Punish, Confirm).
  • titles.*: optional per-menu title overrides (dashboard, violations, incident, profile, history, audit, mutes, punish). Blank uses the built-in title; MiniMessage is supported. Re-apply with /daisyfilter reload.