Actions, warnings, and punishments
Player feedback
Section titled “Player feedback”When a message is censored or blocked, the player can receive a chat message
(configurable per surface in messages.yml). Warnings are rate-limited per player
so a burst of violations does not spam them.
Staff alerts
Section titled “Staff alerts”Alerts are permission-gated (daisyfilter.alerts) and include a masked preview plus
an Inspect button linked to the exact incident. Staff with daisyfilter.view.raw
can hover for exact encrypted evidence; other staff never receive it. Severe incidents
are never hidden by grouping cooldowns. Each staff member can mute alerts with
/daisyfilter alerts off.
Webhook logging
Section titled “Webhook logging”webhook.yml can mirror incidents to a Discord webhook for off-server visibility.
It is disabled until you set a URL, and only ever sends privacy-safe metadata —
player, surface, action, severity, categories, the masked preview, and the record id
— never raw content. Posts are asynchronous and best-effort, rate-limited
(max-per-minute) to respect Discord, and gated by min-severity and enforced-only.
All Discord mention parsing is disabled, so a crafted name can never ping the server.
Punishment profiles
Section titled “Punishment profiles”DaisyFilter does not implement its own ban/mute system — it hands sanctions to the
punishment plugin you already run. Each profile in actions.yml dispatches one of two
ways:
- Typed
kind(recommended, default): setkindtoMUTE,BAN,KICK, orWARNand DaisyFilter routes the action through PunishBridge, which auto-detects the installed provider (LiteBans or the vanilla ban/kick fallback) and applies it with the correct semantics. No command syntax to maintain. The shippedwarn,mute,kick,tempban, andbanprofiles use this. - Raw
commands(custom): leavekindblank and list console commands instead, for server-specific actions PunishBridge doesn’t model. These run as allowlisted, safe-templated console commands.
Both paths support durations, confirmation screens, per-profile permissions, and an
audit row. Command placeholders are {player}, {uuid}, {staff}, {duration},
{reason}, {record_id}, {category}, {severity}; raw evidence is deliberately
unavailable. Namespaced command roots must be listed exactly in allowed-command-roots.
A rejected request, missing permission, invalid duration, or failed dispatch is audited.
PunishBridge is shaded into the plugin; only the Apache-2.0 LiteBans provider is bundled, so DaisyFilter ships LiteBans + vanilla support out of the box.
Command-based presets (for the custom commands path)
Section titled “Command-based presets (for the custom commands path)”If you prefer raw commands (or run a provider PunishBridge doesn’t cover), clear kind
and copy the block for your plugin into actions.yml.
LiteBans (recommended):
punishments: allowed-command-roots: [warn, mute, tempmute, kick, ban, tempban] profiles: warn: { display-name: "Warn", permission: daisyfilter.punish.warn, confirmation: false, commands: ["warn {player} {reason}"] } mute: { display-name: "Mute", permission: daisyfilter.punish.mute, durations: ["10m","1h","1d","7d"], commands: ["mute {player} {duration} {reason}"] } kick: { display-name: "Kick", permission: daisyfilter.punish.kick, commands: ["kick {player} {reason}"] } tempban: { display-name: "Temp Ban", enabled: false, permission: daisyfilter.punish.ban, durations: ["1d","7d","30d"], commands: ["tempban {player} {duration} {reason}"] } ban: { display-name: "Ban", enabled: false, permission: daisyfilter.punish.ban, commands: ["ban {player} {reason}"] }EssentialsX (no /warn; mute is permanent unless a duration is given):
punishments: allowed-command-roots: [mute, kick, ban, tempban] profiles: mute: { display-name: "Mute", permission: daisyfilter.punish.mute, durations: ["10m","1h","1d"], commands: ["mute {player} {duration} {reason}"] } kick: { display-name: "Kick", permission: daisyfilter.punish.kick, commands: ["kick {player} {reason}"] } tempban: { display-name: "Temp Ban", enabled: false, permission: daisyfilter.punish.ban, durations: ["1d","7d","30d"], commands: ["tempban {player} {duration} {reason}"] } ban: { display-name: "Ban", enabled: false, permission: daisyfilter.punish.ban, commands: ["ban {player} {reason}"] }AdvancedBan:
punishments: allowed-command-roots: [warn, mute, tempmute, kick, ban, tempban] profiles: warn: { display-name: "Warn", permission: daisyfilter.punish.warn, confirmation: false, commands: ["warn {player} {reason}"] } mute: { display-name: "Temp Mute", permission: daisyfilter.punish.mute, durations: ["10m","1h","1d"], commands: ["tempmute {player} {duration} {reason}"] } kick: { display-name: "Kick", permission: daisyfilter.punish.kick, commands: ["kick {player} {reason}"] } tempban: { display-name: "Temp Ban", enabled: false, permission: daisyfilter.punish.ban, durations: ["1d","7d","30d"], commands: ["tempban {player} {duration} {reason}"] } ban: { display-name: "Ban", enabled: false, permission: daisyfilter.punish.ban, commands: ["ban {player} {reason}"] }LibertyBans (%DURATION% style uses the same flat syntax; namespaced fallback shown):
punishments: allowed-command-roots: [warn, mute, kick, ban, libertybans] profiles: mute: { display-name: "Mute", permission: daisyfilter.punish.mute, durations: ["10m","1h","1d"], commands: ["mute {player} {duration} {reason}"] } kick: { display-name: "Kick", permission: daisyfilter.punish.kick, commands: ["kick {player} {reason}"] } ban: { display-name: "Ban", enabled: false, permission: daisyfilter.punish.ban, durations: ["1d","7d","perm"], commands: ["ban {player} {duration} {reason}"] }CMI (namespaced root cmi):
punishments: allowed-command-roots: [cmi] profiles: mute: { display-name: "Mute", permission: daisyfilter.punish.mute, durations: ["10m","1h","1d"], commands: ["cmi mute {player} {duration} {reason}"] } kick: { display-name: "Kick", permission: daisyfilter.punish.kick, commands: ["cmi kick {player} {reason}"] } ban: { display-name: "Ban", enabled: false, permission: daisyfilter.punish.ban, commands: ["cmi ban {player} {reason}"] }Vanilla (no mute command — use the built-in fallback mute for muting):
punishments: allowed-command-roots: [kick, ban] profiles: kick: { display-name: "Kick", permission: daisyfilter.punish.kick, commands: ["kick {player} {reason}"] } ban: { display-name: "Ban", enabled: false, permission: daisyfilter.punish.ban, commands: ["ban {player} {reason}"] }For any other plugin: add its exact command root to allowed-command-roots and write a
profile using only the supported placeholders. Use essentials:/litebans: namespaced
roots if two plugins both register /mute or /ban and you need a specific one.
Severity escalation (opt-in)
Section titled “Severity escalation (opt-in)”Configured in escalation.yml and disabled by default. When enabled,
DaisyFilter accumulates severity points per player within a rolling window and
fires each threshold once as it is crossed. A threshold re-arms after the points
decay below it.
enabled: falsewindow-seconds: 600thresholds: - { points: 8, action: WARN } - { points: 16, action: TEMP_MUTE, duration-seconds: 300 } - { points: 30, action: KICK }Actions:
WARN— sends a stronger notice.TEMP_MUTE— mutes the player. Routed through PunishBridge to your punishment plugin (e.g. LiteBans); if no provider can mute (vanilla), it falls back to the built-in mute, which is persisted and managed with/daisyfilter mutes,/unmute,/extend, and the opt-in player/appealcommand.KICK— removes the player with a configurable message.RUN_COMMAND— runs an allowlisted console command template, for anything PunishBridge does not cover.
Command templates
Section titled “Command templates”RUN_COMMAND only runs templates listed in escalation.command-allowlist. The
{player} placeholder is replaced with a sanitized name (letters, digits, and
underscores only). No command text is ever derived from player input, and
everything runs from the console.