Run it in CI
This page runs three term jobs on every pull request. check fails on a
broken reference and annotates the line. write -f vale --check fails when
the committed Vale style has fallen behind the set. lint holds the
definitions to the house voice. All three read the same manni.config.yaml
as a local run.
The recipes run npx, which fetches the published package on demand. The
runner needs Node.js 24 or newer, and the steps that run Vale need it on PATH.
How the gate works
Section titled “How the gate works”Exit codes drive the gate. They are the family’s:
| Code | Meaning |
|---|---|
0 | No error-severity finding, or --check found the style up to date. |
1 | At least one error-severity finding the baseline does not hold, or --check found a file that differs. |
2 | The job could not run. No terms, no Vale on PATH, a bad flag or a bad config key. The message goes to stderr, prefixed manni:. |
Warnings and notices never fail the job. asymmetric-hierarchy is a
warning, and abstract-too-long and unused-term are notices. Every other
check rule is an error. term.severity moves any of them; see the
rules reference.
-f github produces inline annotations. One workflow command per
finding, on the file and line, titled with the rule id:
$ manni term check -f github::error file=docs/guides/fitting.md,line=3,title=manni%3Aterm/undefined-term::concepts: "PAL" names no entry. "progressive lens" lists it as an alt-label.lint -f github prints the same shape, under manni:term/prose/<Style.Rule>:
$ manni term lint -f github::warning file=docs/terms/kubernetes.md,line=7,title=manni%3Aterm/prose/House.Simply::Drop 'Simply'.::warning file=docs/terms/kubernetes.md,line=11,title=manni%3Aterm/prose/House.Simply::Drop 'just'.::error file=docs/terms/progressive-lens.md,line=9,title=manni%3Aterm/prose/House.Length::Keep a sentence under 20 words.json, sarif and junit are there for dashboards, code scanning and the
test tab. The CLI reference has each
shape.
The workflow
Section titled “The workflow”-
Declare the docset and Vale’s configuration in
manni.config.yaml, so each job runs with no arguments:manni.config.yaml collections:- name: sitepaths:- "docs/**/*.md"tools:vale:config: .vale.ini -
Commit the generated style. Run
manni term write -f valelocally and commitTerms/under your styles directory, beside.vale.ini. -
Add the workflow.
.github/workflows/terms.yml name: Termson:pull_request:jobs:check:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v7- uses: actions/setup-node@v6with:node-version: 24# Every concepts: value names an entry, and the set is consistent.- run: npx -y @hawkeyexl/manni term check -f githubvale:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v7- uses: actions/setup-node@v6with:node-version: 24# The latest Vale release, onto PATH for both manni jobs below.- name: Install Valeenv:GH_TOKEN: ${{ github.token }}run: |gh release download --repo errata-ai/vale --pattern '*_Linux_64-bit.tar.gz' --output vale.tar.gztar -xzf vale.tar.gz -C "$RUNNER_TEMP" valeecho "$RUNNER_TEMP" >> "$GITHUB_PATH"- run: vale sync# The committed Terms style matches the set.- run: npx -y @hawkeyexl/manni term write -f vale --check# The definitions hold to the house voice.- run: npx -y @hawkeyexl/manni term lint -f github -
Open a pull request. A
concepts:value that names no entry fails thecheckjob and annotates the line. A term edited without regenerating the style fails thevalejob, and its log names each file that would change.
A failing --check prints what differs:
$ manni term write -f vale --check.vale/styles/Terms/Deprecated.yml would change$ echo $?1The fix is local. Run manni term write -f vale, and commit the result.
Ramp in with a baseline
Section titled “Ramp in with a baseline”A docset whose concepts: values were never checked fails its first run.
The baseline lets the check go in without fixing that backlog first.
-
Record the backlog once. With no baseline file yet,
--baselinerecords every current finding and exits0:Terminal window $ manni term check --baseline✓ 1 finding recorded in .manni-term-baseline.jsonCommit
.manni-term-baseline.json. -
Run the job with the same flag. A finding the file holds is counted as baselined. Only a new one fails:
Terminal window $ manni term check --baseline✓ 2 terms, 3 references, no findings, 1 baselinedThe job line becomes
npx -y @hawkeyexl/manni term check -f github --baseline. -
Burn the backlog down. Fix findings as pages are touched. Delete the file and run
--baselineagain to record the smaller backlog.
To compare on every run without the flag, name the file under term::
term: baseline: .manni-term-baseline.jsonWith the key set and no file on disk, the run stops with exit 2, and says
how to record one.
Verify it works
Section titled “Verify it works”Open a pull request that adds an alt-label to a guide’s concepts:. Then check
that:
- The
checkjob is red, and the guide carries an annotation titledmanni:term/undefined-termthat names the entry claiming the alt-label. - A pull request that adds a term nothing references stays green, with a
manni:term/unused-termnotice. - A pull request that adds a hidden-label without running
write -f valefails thevalejob withTerms/Deprecated.yml would change.