Skip to content

Keep the terms and the docs in step

A term set says which names are preferred, which are admitted and which are deprecated. This page turns that into prose checks. manni term write -f vale renders the set as a Vale style named Terms. Vale then flags a deprecated name, a term in the wrong case, or an acronym used before its expansion. manni term lint runs the same Vale configuration over the definitions themselves.

Every transcript below is real output from the built tool and Vale 3.20.0.

  • A term set that manni term check passes. Get started builds one.
  • Vale on PATH. Both verbs start vale as a process. write -f vale -o <dir> runs without it, and so does lint when no entry has a definition, abstract or scope note.
  • A Vale configuration with a StylesPath. The example uses a house style named House, with a sentence-length rule and a rule against filler words.

The example set has three terms. progressive lens has the alt-labels PAL and graduated lens, and the hidden-label no-line bifocal. Kubernetes has the alt-label K8s and the hidden-label Kubernates. corrective lens has neither.

  1. Tell manni where Vale’s configuration is. tools: is a top-level key of the family config, beside collections:. Every domain that runs Vale reads it:

    manni.config.yaml
    collections:
    - name: site
    paths:
    - "docs/**/*.md"
    tools:
    vale:
    config: .vale.ini
    .vale.ini
    StylesPath = .vale/styles
    MinAlertLevel = suggestion
    [*.md]
    BasedOnStyles = House

    Without tools.vale.config, Vale looks for its configuration itself, as it does when you run it.

  2. Write the style. With no -o, manni asks Vale where its styles directory is, and writes Terms/ there:

    Terminal window
    manni term write -f vale
    Wrote 3 terms to .vale/styles/Terms
    Casing.yml 2 labels
    Lowercase.yml 3 labels
    Deprecated.yml 2 swaps
    PAL.yml 1 acronym
    notice: no section of .vale.ini uses the Terms style. Add it to BasedOnStyles:
    [*.md]
    BasedOnStyles = House, Terms

    manni never edits a Vale configuration. The notice names the line to add, and the file to add it to.

  3. Wire the style in. Add Terms to the section the notice names:

    .vale.ini
    StylesPath = .vale/styles
    MinAlertLevel = suggestion
    [*.md]
    BasedOnStyles = House, Terms

    Run manni term write -f vale again and the notice is gone.

  4. Run Vale over a guide. This one breaks each kind of rule once:

    docs/guides/fitting.md
    ---
    title: Fitting lenses
    concepts: [progressive lens, corrective lens, Kubernetes]
    ---
    # Fitting lenses
    Most customers over fifty ask for a PAL.
    A progressive lens (PAL) has no visible line, unlike a no-line bifocal.
    Our fitting service runs on kubernetes.
    The booking system also runs on Kubernates.
    Terminal window
    $ vale docs/guides/fitting.md
    docs\guides\fitting.md
    8:37 warning Spell out 'PAL' on first use, as 'progressive lens (PAL)'. Terms.PAL
    10:56 warning Use 'progressive lens' instead of 'no-line bifocal'. Terms.Deprecated
    12:29 error Use 'Kubernetes' instead of 'kubernetes'. Terms.Casing
    14:33 warning Use 'Kubernetes' instead of 'Kubernates'. Terms.Deprecated
    ✖ 1 error, 3 warnings and 0 suggestions in 1 file.

    PAL on line 10 is not flagged, because its expansion sits beside it.

Each file is built from one kind of label, and each opens with a marker line:

FileVale checkBuilt fromLevel
Terms/Casing.ymlsubstitutionlabels and alt-labels that hold a capital and don’t start with a lowercase letter, such as Kubernetes, K8s or C++error
Terms/Lowercase.ymlsubstitutionlabels and alt-labels entirely in lowercaseerror
Terms/SentenceStart.ymlsubstitutionlabels and alt-labels that start lowercase and hold a capital later, such as iPhoneerror
Terms/Deprecated.ymlsubstitutionhidden-labels, each swapped for its entry’s labelwarning
Terms/<ACRONYM>.ymlconditionaleach all-caps alt-label of a label that is not all caps, unless the alt-label is another term’s labelwarning

A file with nothing to hold is not written. A label that is all caps, such as API, gets no casing rule and no acronym rule, because it is the name itself.

.vale/styles/Terms/Lowercase.yml
# Generated by manni term write. Edit the terms, not this file.
extends: substitution
message: "Write '%[2]s' in lowercase, except to start a sentence."
level: error
ignorecase: true
nonword: true
vocab: false
swap:
\bcorrective lens\b: "[Cc]orrective lens"
\bprogressive lens\b: "[Pp]rogressive lens"
\bgraduated lens\b: "[Gg]raduated lens"

A term that starts lowercase may still start a sentence. Lowercase.yml and SentenceStart.yml allow a capital first letter, and both messages print what the writer wrote rather than the pattern. manni’s own glossary writes this one for meta-schema URI:

.vale/styles/Terms/SentenceStart.yml
# Generated by manni term write. Edit the terms, not this file.
extends: substitution
message: "Write '%[2]s' as the term list spells it, with a capital only to start a sentence."
level: error
ignorecase: true
nonword: true
vocab: false
swap:
\bmeta-schema uri\b: "[Mm]eta-schema URI"
.vale/styles/Terms/PAL.yml
# Generated by manni term write. Edit the terms, not this file.
extends: conditional
message: "Spell out 'PAL' on first use, as 'progressive lens (PAL)'."
level: warning
ignorecase: false
first: '\b(PAL)\b'
second: '(?i)progressive lens \((PAL)\)'

Three rules keep the style safe to commit:

  • manni owns Terms/. A file there without the marker line is someone else’s, and the write stops with exit 2 rather than replace it. A marked file the set no longer produces, such as the rule for a removed acronym, is deleted.
  • vale sync leaves the files alone. Commit them beside the config, and let --check say when they fall behind.
  • manni writes no vocabulary file. The casing rules above do that job, so accept.txt stays yours.

To write the style somewhere Vale does not report, pass -o <styles directory>. That form does not start Vale at all.

A definition is prose, and the house voice applies to it too. manni term lint writes each entry’s definition, abstract and scope-note to a temporary file named <id>.<field>.md. Then it runs Vale once over all of them, with the same configuration:

Terminal window
manni term lint
docs/terms/kubernetes.md:7
warning manni:term/prose/House.Simply Drop 'Simply'.
docs/terms/kubernetes.md:11
warning manni:term/prose/House.Simply Drop 'just'.
docs/terms/progressive-lens.md:9
error manni:term/prose/House.Length Keep a sentence under 20 words.
1 error, 2 warnings in 3 terms

Each finding sits on the source line of its field. Line 7 is the abstract. Line 11 is the second line of a literal scope-note: | block, so the finding lands on that exact line. The definition of progressive lens is a folded >- block, so its finding sits on the field’s first line.

A definition is often one long noun phrase, and a sentence-length rule written for guides fires on it. Vale matches a section by file name, so a [*.definition.md] section applies to definitions and nothing else:

.vale.ini
StylesPath = .vale/styles
MinAlertLevel = suggestion
[*.md]
BasedOnStyles = House, Terms
[*.definition.md]
House.Length = NO
docs/terms/kubernetes.md:7
warning manni:term/prose/House.Simply Drop 'Simply'.
docs/terms/kubernetes.md:11
warning manni:term/prose/House.Simply Drop 'just'.
2 warnings in 3 terms

The length finding is gone, and the exit code is 0. The abstract and scope-note files still get House.Length, because their names end .abstract.md and .scope-note.md.

The style is rendered from the set, so it falls behind whenever a term changes. --check renders without writing, and exits 1 when a file differs. Add the hidden-label Kubernets to Kubernetes, and:

Terminal window
$ manni term write -f vale --check
.vale/styles/Terms/Deprecated.yml would change
$ echo $?
1

Write the style again, and the check passes:

Terminal window
$ manni term write -f vale --check
.vale/styles/Terms is up to date
$ echo $?
0

--dry-run prints the same lines, writes nothing, and exits 0. A file the set would drop is named too, as in .vale/styles/Terms/PAL.yml would be removed.