Word-list files under .mdsmith/wordlists/

July 12, 2026 · View on GitHub

A word-list is a named set of literal strings. A rule names one or more lists in its lists: setting, and the resolved entries union into the rule's own list. A list lives in a YAML file under .mdsmith/wordlists/ whose basename is the list name. One file per list, no nesting. The directory sits next to .mdsmith.yml at the workspace root.

.mdsmith.yml
.mdsmith/
  wordlists/
    house-banned.yaml
    product-names.yaml

File shape

The body has an optional extends: parent and a required entries: list of literal strings. A key outside that set is a config error naming the key and file.

# .mdsmith/wordlists/house-banned.yaml
entries:
  - "synergy"
  - "circle back"
  - "it's important to note that"

Each entry is matched verbatim by the rule that reads it. Quote any entry YAML would otherwise mangle — a trailing comma, a leading symbol.

Referencing a list from a rule

Every rule that takes a list setting also takes a lists: key. The named lists resolve to entries that union with the rule's own inline list:

rules:
  forbidden-text:
    lists: [house-banned]
    contains: ["one-off phrase"]

forbidden-text then flags any paragraph that contains a house-banned entry or the inline phrase. lists: appends across config layers, so a convention's lists: and a project's lists: combine rather than replace.

lists: fills one setting per rule:

Rulelists: fills
forbidden-textcontains
forbidden-paragraph-startsstarts
proper-namesnames
required-mentionsmentions
no-inline-htmlallow
descriptive-link-textbanned
callout-typeallow
no-unused-link-definitionsignored-labels
the placeholder rulesplaceholders

The mechanism is neutral about how a rule reads its list. forbidden-text bans each entry; required-mentions requires each entry in every section.

No lists ship compiled into the binary. Every list a rule names is one a project declares — in a file here or inline in .mdsmith.yml. The no-llm-tells convention is the home for the curated anti-slop vocabulary; it ships those words as the rules' inline presets, not as a named list you extend. To start from that curated set as editable files, run mdsmith init --add wordlists. It scaffolds ai-speak.yaml and ai-openers.yaml here for you to own.

Extending a list

A list may name one parent with extends:. The parent's entries come first, then the list's own, with duplicates dropped. Chains resolve to the root; a cycle or a missing parent is a config error. Use extends: to share one base list across several denylists:

# .mdsmith/wordlists/our-slop.yaml
extends: house-banned
entries:
  - "best-in-class"
  - "move the needle"

Basename rule

The list name is the basename minus extension. It must match [a-z][a-z0-9-]* — lower case, starting with a letter, with optional hyphen-separated segments. Both *.yaml and *.yml are scanned; the same basename across both extensions is a config error naming both files. Subdirectories and symlinks are rejected. A file over 1 MB is rejected.

Composition with .mdsmith.yml

An inline wordlists: block in .mdsmith.yml is a first-class source — the inline twin of a file:

wordlists:
  product-names:
    entries: ["mdsmith", "Goldmark"]

The same name declared in both a file and inline is a config error naming both sources. The two do not merge.

The no-llm-tells convention ships a curated anti-slop vocabulary as inline rule presets. A project that wants those words selects the convention. It does not name a list here. The convention files page covers the sibling .mdsmith/conventions/ directory.