Skip to content

Categories and policy

Each rule belongs to one or more categories. A category defines a default severity (1–5), a disposition, and a set of effects.

CategorySeverityDispositionEffects
swearing2Censorwarn, log
nsfw4Blockwarn, alert, log
hate5Blockwarn, alert, log
harassment4Blockwarn, alert, log
safety-risk5Blockwarn, alert, log
grooming4Monitoralert, log
self-harm4Monitoralert, log
links2Blockwarn, log
spam2Blockwarn, log
personal-info3Monitoralert, log
contextual2Monitoralert, log
unsafe-language2Censorwarn, log
gamersafer-unclassified2Censorwarn, log

Tune these in categories.yml. A category a rule names but categories.yml does not define is left entirely alone — the rule keeps its own severity, disposition, and actions. gamersafer-unclassified is a fallback policy for imported third-party rows; no shipped filter pack uses it.

A category only fills in what a rule left unsaid. What counts as “unsaid” is precise, and it is the one thing to get right before you edit categories.yml:

Where the value came fromCan category policy change it?
Written on the rule entry itself in a filter packNo. What you typed on the rule wins.
Inherited from that pack’s defaults: blockYes. Pack defaults stay soft.
Not set anywhereYes — the category supplies it.

That split is what lets you relax a whole category without editing every rule in it. Set links to MONITOR and every link rule that took its disposition from the pack default starts reporting advertising instead of blocking it — while a single rule someone deliberately wrote disposition: BLOCK on keeps blocking.

Three further rules apply, whatever the category says:

  • Severity is a floor, never a downgrade. Where a category does supply the severity, it can only raise a rule, never lower it — a rule that ships higher keeps its own. Severity ≥ 4 bypasses the staff-alert grouping cooldown, so a category default must not be able to quietly group away a rule that was reviewed as more serious.
  • enabled: false on a category switches off every rule in it, whatever the rules say. That is how you suppress a whole category; the alternative is disabling the individual rule.
  • When a rule belongs to several categories, the strongest disposition among them applies (BLOCK > CENSOR > MONITOR > ALLOW) and the effects are the union of theirs.

See filters.md for the full order the final policy is decided in.

DaisyFilter ships rules aimed at protecting younger players. They live in filters/00-child-safety.yml, filters/10-personal-info.yml, and filters/45-safety-risk.yml, so you can read and edit them like any other pack — but read the comments in those files first:

  • personal-info — age, address/school, phone, email, and social-handle solicitation or sharing (e.g. “how old are you”, “what’s your snap”, “add me on discord”, “my snap is …”). Default monitor + staff alert: it never disrupts normal chat, it just flags every hit for review.
  • grooming — predatory conversational patterns. Ambiguous signals (“are you home alone”, “can we meet in person”, “send me a pic”, “let’s talk on snapchat”, “I’ll give you free robux”, “you’re mature for your age”) are monitor + alert, while unambiguous predatory language — real-world meetups (“send me your address”), cover-ups (“delete these messages”), secrecy (“don’t tell your parents”), and sextortion (“send pics or I’ll leak”) — is also tagged safety-risk and blocked.
  • self-harm — a player expressing suicidal or self-harm intent (“I want to die”, “kms”, “I feel suicidal”). Never blocked — silencing a child reaching out is harmful. The message is flagged to staff and the player is sent a private, supportive message with a crisis line (messages.ymlself-harm-response). Telling another player to self-harm (“kys”) is separate: it is harassment and blocked.

For a strict child server you can raise personal-info (and grooming) to CENSOR or BLOCK in categories.yml so the information is hidden from chat, not just reported. Note that this only moves the rules that took their disposition from the pack default; a rule written disposition: MONITOR on the entry itself stays where it is. Add server-specific phrases in filters/90-custom.yml.

Beyond the English packs, filters/50-multilingual.yml ships profanity, slurs, and grooming patterns for Spanish, Portuguese, French, and German (the most common non-English languages on MC servers). Patterns tolerate dropped accents, so a player typing without an accented keyboard is still matched. Ordinary profanity censors, severe slurs map to hate and block, and age/photo solicitation maps to personal-info and alerts staff. Add more languages or terms in filters/90-custom.yml.

DaisyFilter separates the disposition (what happens to the content) from the effects (side actions), so configuration can never request contradictory outcomes.

  • Dispositions: ALLOW, MONITOR, CENSOR, BLOCK.
  • Effects: WARN, ALERT_STAFF, LOG, TEMP_MUTE, KICK, RUN_COMMAND.

That is policy for a single rule. Separately, when several rules or heuristics match the same message:

BLOCK > CENSOR > MONITOR > ALLOW
  • The result severity is the highest matched severity.
  • The result score sums distinct category/heuristic weights up to a cap, so repeated matches in one message cannot inflate escalation without bound.

Global monitor-only mode forces every non-allow result to MONITOR, suppressing punishment actions while keeping logging and alerts.

To keep false positives low in production, DaisyFilter does not act on a raw match — it computes a confidence (probability the message is a genuine violation) and gates the disposition by it.

Each match scores higher when:

  • the matched term is longer (short fragments are riskier),
  • it is a whole-word match rather than a substring,
  • it appears in a less-transformed normalized form.

Independent matches combine with a noisy-OR, so several weak signals can still add up while repetition of one signal cannot. The combined probability then caps the disposition (config.ymlconfidence):

Combined probabilityStrongest action
block-threshold (0.80)the rule’s disposition, up to Block
censor-threshold (0.55)capped at Censor
monitor-threshold (0.30)capped at Monitor (logged/alerted, never punished)
below monitor-thresholdAllow (ignored)

Matches below noise-floor (0.30) are dropped entirely as coincidental noise. Lower the thresholds to catch more (and risk more false flags); raise them to act only on near-certain violations. /daisyfilter test <message> shows the resulting confidence so you can tune against real examples. This pairs with whole-word matching and the allowlist, which remove the classic substring false positives.