Skip to content

Word lists

Every word and pattern DaisyFilter matches on lives in editable YAML packs under plugins/DaisyFilter/filters/, loaded at runtime. filters.md is the guide to editing them; this page covers where the words came from and what you are allowed to do with them.

The shipped packs were built from openly-licensed sources, merged, deduplicated, and then reviewed by hand. Each pack records its own provenance in its source: field, so attribution travels with the data even if you copy a pack somewhere else:

Packsource:
00-child-safety.yml, 05-links.yml, 10-personal-info.yml, 15-core-safety.yml, 50-multilingual.ymlDaisy curation
20-swearing.yml, 30-nsfw.yml, 40-hate.yml, 45-safety-risk.yml, 60-other.ymlGamerSafer (MIT), LDNOOBW (CC-BY-4.0), bad-words (MIT), Daisy curation
90-custom.ymlThis server

Merged terms were not imported wholesale. Words with ordinary innocent meanings were removed rather than categorised, because a filter that trips on normal chat gets switched off by the owner, which protects nobody.

The bundled NOTICE file inside the jar is authoritative. It records:

SourceLicence
GamerSafer word blocklistMIT, © 2022 GamerSafer. The full licence text is reproduced in the jar’s NOTICE and must remain in every distributed copy that contains this data.
LDNOOBW (repository URL in NOTICE)CC BY 4.0 — attribution is provided in NOTICE as the licence requires.
bad-words (web-mech)MIT
Unicode confusables (UTS #39)Unicode License. Feeds the lookalike-character folding used by the STRICT form.

DaisyFilter itself is proprietary; these data sets remain under their own licences.

The upstream CSVs are not shipped in the jar. They are build-time inputs, kept in the repository at tools/sources/gamersafer/ and read only by the pack generator, the curator tool, and the documentation gate. Nothing loads them at runtime, so there was no reason to send them to every server. Attribution travels with the plugin regardless: the full MIT notice is reproduced in the jar’s NOTICE, and each pack records its own provenance in its source: field.

To change filtering behaviour, edit filters/ — that is the only thing the plugin reads.

Put them in filters/90-custom.yml. It loads last, is never overwritten by an update, and can override any shipped rule by reusing its id. Leet, lookalike-character, and repeated-letter variants are handled by the engine, so you never write those out yourself. See filters.md.

custom-rules.yml still works and is still loaded, but it predates the packs; new work belongs in 90-custom.yml, where you can see it alongside everything else and test it the same way.

Some things a word list cannot express. These rules match against the raw message so dots, slashes, and @ survive normalisation (match-original: true in 05-links.yml and 10-personal-info.yml):

  • URLs and www. links — blocked.
  • Bare domains — blocked. TLDs that never appear as an ordinary English word ending match on sight; short TLDs that collide with normal typing (no.me, gg.gg, see.us) additionally require a scheme, a www. prefix, a path, a port, or a subdomain, so a missing space after a full stop is not treated as an address.
  • IPv4 addresses — blocked at severity 3, since a raw IP is more often an off-platform server invite than anything else. Each octet is range-checked, so 1.2.3.999 is not a match.
  • Discord invites — blocked, in every hostname form including discordapp.com/invite.
  • Email-like and phone-like patterns — monitored and alerted only, never auto-punished. The phone pattern is deliberately narrow so sharing coordinates does not flag.

Put your own server address, your Discord, and any partner host in allowlist.ymldomains. The link rules cannot tell your address from an advertiser’s.

Rules can match a standalone word (WHOLE_WORD) or inside longer words (SUBSTRING), against any of four normalised forms of the message. The forms and what each one folds are documented in filters.md; severities and dispositions are in categories.md.