For teams who want to check terminology automatically, we publish @lexeri/check-cli on npm — a command-line tool (CLI) that checks documents against a termbase straight from your CI/CD pipeline, without opening an editor.
The CLI uploads the given file(s), runs a term check against the termbase linked to your API token, waits for the results, lists every matched term with its state, and exits with a CI-meaningful exit code. This lets a build fail as soon as non-preferred terminology shows up.
Note: The Check CLI complements our Visual Studio Code Extension. The VS Code extension is made for interactive checks right inside the editor, while the CLI is built for automated checks in build pipelines.
Requirements
- Node.js version 20 or later
- A Lexeri API token (see below)
The CLI has no other runtime dependencies.
Installation
In CI we recommend running the CLI directly with npx, without installing it — that way you always use the latest version:
npx --yes @lexeri/check-cli --locale en src/i18n/en.json
For local use you can also install it globally:
npm install -g @lexeri/check-cli lexeri-check --locale en src/i18n/en.json
After a global install, the lexeri-check command is available.
API token
The CLI authenticates with an API token. Create it in the Lexeri web UI for the termbase you want to check against (see API tokens in the help center). The token needs the check_text, read, and show scopes. The termbase is derived from the token — there is no termbase flag.
Pass the token via the LEXERI_API_TOKEN environment variable (recommended for CI, as a masked variable) or via --token:
export LEXERI_API_TOKEN=eyJhbGciOi... lexeri-check --locale en src/i18n/en.json Resources/Strings.resx
The token is never logged — not even in verbose mode (--verbose).
Getting started
The basic invocation is:
lexeri-check [options] <file...>
You can pass one or more files. A sample result looks like this:
src/i18n/en.json (check a1b2c3, 214 sentences, 12.3s) STATE TERM PREFERRED OCCURRENCES not_recommended "whitelist" "allowlist" 4 preferred "email" - 2 6 matches: 4 not_recommended, 2 preferred → FAIL 1 file checked: 0 passed, 1 failed — FAIL (failing states: not_recommended, outdated)
For each file, matched terms are listed with their state, the preferred term, and the number of occurrences. For string formats, matches are reported with the string keys they occur under, so every violation can be traced back to the exact entry.
Options
| Flag | Env var | Default | Description |
|---|---|---|---|
-t, --token <jwt> |
LEXERI_API_TOKEN |
— | Lexeri API token (required) |
-l, --locale <code> |
LEXERI_LOCALE |
detected at upload | Source language of the documents |
--target-locales <csv> |
— | — | Target locales for XLIFF (.xlf/.xliff) translation checks |
--topics <csv> |
— | — | Restrict matching to these topic identifiers |
--tags <csv> |
— | — | Restrict matching to terms carrying these tags |
--filter <key>=<value> |
— | — | Filter by a custom termbase field (repeatable, see below) |
--fail-on <csv> |
— | termbase's negative states | Term states that fail the check (see below) |
--terms-url <url> |
LEXERI_TERMS_URL |
https://terms.lexeri.com |
Terms service base URL |
--files-url <url> |
LEXERI_FILES_URL |
https://files.lexeri.com |
Files service base URL |
--timeout <seconds> |
— | 300 |
Max wait per file for check completion |
--keep-check |
— | off | Keep the check and the uploaded document on the server after fetching results (deleted by default) |
--json |
— | off | Machine-readable JSON report on stdout |
-v, --verbose |
— | off | Log API requests to stderr (token never logged) |
Exit codes
The CLI exits with a code your pipeline can evaluate:
| Code | Meaning |
|---|---|
| 0 | All files passed |
| 1 | At least one match in a failing term state |
| 2 | Usage or configuration error (bad flags, missing token/locale, file not found) |
| 3 | Operational error (auth, network, API failure, timeout) |
With multiple files, the worst outcome wins: an operational error (3) beats failing terms (1) beats pass (0). A failure on one file does not stop the remaining files from being checked.
Which term states fail the check (--fail-on)
By default, the CLI fetches your termbase and fails on its negative term states: not_recommended, outdated, plus any custom states flagged as replaceable. preferred and admitted matches are reported but never fail.
--fail-on replaces that set entirely, e.g.:
lexeri-check --fail-on not_recommended,deprecated,misspelled docs/manual.docx
misspelled is a pseudo-state: include it to fail on misspelled term matches.
Matches in states that are neither failing nor known-positive are shown as unknown and never fail the check — add them to --fail-on explicitly if they should.
Scoping the check (--topics, --tags)
By default, a check matches against the whole termbase. To scope it — for example, to check UI strings only against your UI terminology — restrict matching by topic and/or tag when the check is created:
lexeri-check --topics 3fa5b2c1 --tags ui,frontend src/i18n/en.json
Topics are referenced by their identifier; unknown topic identifiers are ignored by the server. These are the same filters the topic and tag pickers in the Lexeri check form use.
Custom field filters (--filter)
Termbases can define custom fields on term entries and terms (picklist, number, boolean, date). Filter by them with repeatable --filter <key>=<value> arguments, where the key is the backend parameter name: term_entry_field_<field-identifier> or term_field_<field-identifier> (date fields take _start/_end suffixes):
lexeri-check \ --filter term_field_a1b2c3=released \ --filter term_entry_field_d4e5f6=ui \ --filter term_entry_field_d4e5f6=web \ src/i18n/en.json
Repeating the same key sends the values as an array, which is how multiple-selection picklist fields are queried. Values are validated server-side against the field's definition (e.g. picklist options); invalid queries are silently dropped by the server rather than raising an error.
Supported file formats
Files are parsed server-side, so the CLI does not filter by extension — the server decides what it can parse.
The formats most relevant for UI and software development:
-
String resources:
.resx,.json,.properties,.strings,.po,.yaml/.yml,.ini,.csv,.xml,.twine -
Translation interchange:
.xlf/.xliff,.sdlxliff,.mqxliff,.tmx— XLIFF files additionally support translation checks against target languages via--target-locales -
Docs in the repo:
.md,.html,.txt,.srt,.dita/.ditamap
Office and DTP documents are supported too: Word, Excel, and PowerPoint including legacy and macro-enabled variants (.docx/.doc/.docm, .xlsx/.xls/.xlsm, .pptx/.ppt/.pptm), OpenDocument (.odt, .ods, .odp), Apple iWork (.pages, .key), plus .pdf, .rtf, .epub, .vsdx, .idml, and .mif.
For string formats, matches are reported with the string keys they occur under, so violations can be traced back to the exact resource entry.
Using it in GitLab CI
Set LEXERI_API_TOKEN as a masked CI/CD variable, then call the CLI with npx:
terminology-check:
image: node:22-alpine
script:
- npx --yes @lexeri/check-cli --locale en src/i18n/en.json
rules:
- changes:
- "src/i18n/**/*"Check all string resources of a given type, e.g. every .resx file (glob expansion is done by the shell — on minimal images, use find):
script:
- find . -name '*.resx' -exec npx --yes @lexeri/check-cli --locale en {} +Check translated XLIFF files against a target language:
script:
- npx --yes @lexeri/check-cli --locale en --target-locales de translations/de.xlfKeep a machine-readable report as an artifact:
terminology-check:
image: node:22-alpine
script:
- npx --yes @lexeri/check-cli --json --locale en src/i18n/en.json > term-report.json
artifacts:
when: always
paths: [term-report.json]With --json, the report goes to stdout and everything else (progress, warnings) to stderr, so the redirection stays clean.
The CLI runs in any CI environment with Node.js 20 or later, so the examples above transfer to other CI systems as well.
JSON output
With --json you get a machine-readable report on stdout:
{
"version": 1,
"verdict": "fail",
"exitCode": 1,
"failOn": ["not_recommended", "outdated"],
"termbase": { "identifier": "…", "name": "Marketing" },
"files": [
{
"file": "docs/manual.docx",
"status": "fail",
"checkIdentifier": "…",
"localeCode": "en",
"sentenceCount": 214,
"durationMs": 12300,
"totalMatches": 6,
"countsByState": { "not_recommended": 4, "preferred": 2 },
"misspelledCount": 0,
"matches": [
{ "term": "whitelist", "state": "not_recommended", "classification": "fail", "preferred": "allowlist", "occurrences": 4, "misspelled": false }
],
"error": null
}
]
}How the check works
The CLI first resolves the termbase and the failing states from your API token. It then uploads your file(s) temporarily to Lexeri's files service, creates the check, waits for it to complete (polling every 2.5 seconds until it reaches 100% or --timeout), and fetches the term matches. After fetching, the check and the uploaded document are deleted from the server again — unless you use --keep-check.
Feedback
This is the first version of our Check CLI, and we have many more ideas for it. Do you have a wish or found a bug? Let us know: info@lexeri.com
We look forward to your feedback!