Vale CLI: a markup-aware prose linter that runs your style guide as code
:pencil: A markup-aware linter for prose built with speed and extensibility in mind.
At a glance
- What is it?
- Vale is a Go binary that parses Markdown, AsciiDoc, HTML and source-code comments, then applies YAML style rules to the prose inside them. It ships no opinions of its own, which is both its selling point and the source of its setup cost.
- Who is it for?
- Adopt Vale if your team already has a written style guide and wants it enforced in editors and CI without a hosted service: the binary is self-contained, runs offline, and the sync command pulls published packages such as Microsoft's. Skip it if you want a linter that decides what good writing is for you, or if your content is not markup, code, or a format a View can point at.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Vale CLI actually lints, and who ends up using it
Vale is a command-line linter for prose. The README frames the problem in one line: most tools see text, Vale sees a document. That distinction matters because the failure mode of a naive prose checker is flagging words inside a code fence, a URL, or a variable name. Vale parses the markup first. Markdown, AsciiDoc, reStructuredText and HTML go through a real parser, and the README states that code spans, URLs and fenced blocks are skipped before a rule ever runs.
The second audience is developers who write comments. Vale lifts comments and docstrings out of source code using tree-sitter grammars, so a comment marker inside a string literal stays code. The README gives the example of Markdown inside a Rust doc comment or reStructuredText inside a Python docstring being linted as though it were its own file.
Who is this for? The README names teams at AWS, NVIDIA, Microsoft, GitLab and Red Hat among those who publish their configs. That is a documentation-team profile: people with an existing style guide, a docs repository, and enough volume that manual review does not scale. It is a poor fit for someone who wants a tool to tell them what good writing is. Vale does not ship opinions of its own; it is a framework for enforcing yours.
The third case is prose that hides in files nobody thinks of as prose. A View declares where the writing lives in an OpenAPI description, a notebook cell or a commit message, so Vale lints that region and passes over the rest. That capability is what separates Vale from a spell checker pointed at a repository, and it is also why the tool expects configuration before it does anything useful.
The mechanism: scopes, packages and a sync step
Vale separates what to check from how to check it. A rule is a YAML file. The README describes extension points that run from a token list to part-of-speech patterns, cross-file relationships, readability formulas and scripts. Rules can target structural positions, called scopes, so a check can apply to headings, list items or table cells rather than to the whole file. A rule can also carry its own fix, which the README says an editor applies with one keystroke and an agent applies without deciding anything.
The dependency list in go.mod shows the machinery behind that: goldmark for Markdown, go-org for Org mode, cascadia for CSS-style HTML selection, go-tree-sitter for source grammars, prose for part-of-speech tagging, and expr and tengo for the scripting extension points. This is a parser stack, not a regex stack, and it is the reason a rule can say heading rather than line 12.
Styles arrive as packages. The README shows vale sync reporting that it synced two packages into a styles directory. The Package Explorer and the published configs linked from the README are where those packages come from. The README also links Vale Studio and Vale CMS, which are separate hosted surfaces rather than part of the CLI.
One consequence of the design: nothing useful happens until you supply config. A fresh install with no .vale.ini and no styles will not reproduce the README's sample output. The repository does carry a .vale.ini at its top level, which means the project lints its own documentation with the same tool it ships, and that file is a working example of the config format.
Installing Vale and running it on a docs directory
The README does not carry a numbered install section, but it links a Quickstart at docs.vale.sh/topics/quickstart and shows badges for Homebrew, Chocolatey and Docker, which indicates the supported distribution channels. The repository also contains a Dockerfile that builds the binary from source and publishes the image as jdkato/vale.
The Dockerfile is worth reading before you containerize Vale in CI. It compiles with CGO_ENABLED=1 and a build-base toolchain, then runs the resulting binary on alpine with py3-docutils, asciidoctor, nodejs and npm installed and mdx2vast installed globally through npm. Those extras are there because some formats need external converters; the Go binary alone does not carry them. The Dockerfile also documents a debug shell entry point:
docker run -it --entrypoint /bin/sh jdkato/vale -sThe README's own console example is the shortest path to a first real run. It syncs packages and then lints a directory of Markdown files:
vale sync
vale docs/The documented output is a per-file listing with line and column, a severity of suggestion, warning or error, the matched text, and the rule name in the form of package plus rule, for example Microsoft.Wordiness or Vale.Spelling. The run ends with a count: two errors, one warning and two suggestions across two files. If you see that shape of output, the pipeline is working. If you see nothing at all, check that sync actually placed packages in the styles directory your config points at.
For a project that wants to pin the tool in CI, the repository ships .goreleaser.yml and a Makefile whose build target produces bin/vale with version metadata injected through ldflags, so a self-built binary reports the tag it was built from:
make build os=linux arch=amd64The Makefile accepts os and arch variables and defaults to the host system when they are unset, so the same target covers darwin, windows and linux builds. The repository also carries a .pre-commit-hooks.yaml, which means Vale can be wired into a pre-commit setup without writing a hook definition yourself.
Where Vale gets in the way
The clearest limitation is the one the project states as a feature. Vale does not ship opinions of its own. Install it, run it with no configuration, and it has nothing to say. The value only appears after someone writes or adopts a ruleset, and that is real work: choosing a published guide, deciding which rules to disable, and maintaining exceptions as the guide changes.
Rule noise is the predictable second problem. A published guide such as Microsoft's encodes that guide's preferences, not your product's terminology. Teams that sync a package wholesale often end up suppressing rules one by one. The README's sample output includes a Docs.Terms rule flagging the casing of the product name, which is exactly the kind of check that has to be local.
Format coverage has an external dependency the binary does not hide. The Dockerfile installs asciidoctor, py3-docutils, nodejs and npm, and installs mdx2vast globally. If you run Vale on a bare machine or a slim CI image, formats that rely on those converters will not behave the way the container does. The Dockerfile also carries a comment noting that DITA and XML support is not packaged because it would make the image about seven times larger, so that format is a build-it-yourself proposition.
The scripting extension points widen the surface area rather than narrowing it. A rule that embeds an expr or tengo script is a small program, and it fails like one. The README does not document rollback for a bad package sync, so if a synced package breaks your build the recovery path is whatever your version control or your own backup of the styles directory provides.
Finally, Vale is a linter, not a proofreader. It matches patterns you wrote. It will not tell you that a paragraph is confusing, and a passing run is not evidence that the documentation is correct.
Vale versus a hosted grammar and style service
The obvious alternative category is a hosted writing assistant, the kind that plugs into a browser or a word processor and returns suggestions from a service-side model. The difference in approach is structural, not cosmetic.
A hosted assistant owns the rules. You get its judgment, updated on its schedule, and your text leaves your machine. Vale inverts all three properties. Rules are files in your repository, so they are reviewable in a pull request and versioned alongside the docs they govern. The README states the tool runs entirely offline on macOS, Windows and Linux. And the checks are deterministic: the same input produces the same output, which is what makes a CI gate workable. A gate that changes its mind between runs gets disabled by the second person it blocks.
That inversion is also the trade. A hosted service can improve without you doing anything; a Vale ruleset only improves when someone edits it. A hosted service can flag a clumsy sentence it has never seen a rule for; Vale cannot, unless someone writes the pattern. If your team has no written guide and no appetite to write one, a hosted assistant will produce useful feedback on day one and Vale will not.
The middle ground is what most adopters appear to do: start from a published package, either Microsoft's or Google's, and layer an in-house package on top for product terms and casing. The README's adopters page is a list of exactly those layered configs, published for others to read.
Maintenance, releases and the MIT licence
The default branch is v3 and the repository is not archived. The most recent release listed is v3.22.0 on 2026-09-17, with v3.21.0 and v3.20.0 in the two weeks before it, and the last push to the repository was on 2026-09-19. That is a steady release cadence on a versioned major line, which matters for upgrades: rules and config written against v3 should keep working across point releases, but a future major would be the moment to re-read the changelog.
The README is candid about staffing. It describes jdkato as the sole developer and asks for sponsorship through GitHub Sponsors or Open Collective, with a sponsors page listing everyone who funds the project. For an adopter, that is a bus-factor consideration rather than a blocker: the code is MIT-licensed, the repository is public, and a fork is legally and practically available. The practical upgrade cost is low because the artifact is a single binary. You replace the binary, run your existing config against a representative sample of documents, and compare the output counts. A point release that changes rule behavior will show up as a changed error and warning count rather than as a crash.
On licensing, MIT is permissive. It allows commercial use, modification and redistribution provided the copyright notice and permission notice are preserved. That is a statement about the project's own code. Style packages you sync from elsewhere carry their own terms, and the README does not describe them. If you redistribute a synced package inside a product, read that package's licence rather than assuming Vale's applies. This is not legal advice; check with counsel if the redistribution is material to your business.
Frequently asked questions
The questions below cover the points that come up before a first install: what a ruleset is, how to get the binary, and what the name refers to. Each answer stays within what the README and the repository files state.
Editorial conclusion
Adopt Vale if your team already has a written style guide and wants it enforced in editors and CI without a hosted service: the binary is self-contained, runs offline, and the sync command pulls published packages such as Microsoft's. Skip it if you want a linter that decides what good writing is for you, or if your content is not markup, code, or a format a View can point at. Before committing, verify two things yourself: that the packages you sync match the guide you actually follow, and that your CI image carries the external tools your formats need, since the Dockerfile installs py3-docutils, asciidoctor, nodejs and npm rather than bundling them in the Go binary.
Frequently asked questions
What is a Vale ruleset?
A ruleset is the set of YAML rule files Vale applies to your documents. The README describes rules as files with extension points that run from a token list to part-of-speech patterns, cross-file relationships, readability formulas and scripts, and packages are distributed and pulled in with vale sync.
What is vale sh?
vale.sh is the project's homepage, linked from the README alongside docs.vale.sh, the Package Explorer, Vale Studio and Vale CMS. The README does not describe a separate product called vale sh.
How do I install Vale CLI?
The README links a Quickstart at docs.vale.sh/topics/quickstart and shows Homebrew, Chocolatey and Docker badges, and the repository includes a Dockerfile that builds the binary and publishes it as jdkato/vale. The README itself does not list per-platform install commands.
Does Vale work on Markdown and source-code comments?
Yes. The README states that Markdown, AsciiDoc, reStructuredText and HTML go through a real parser, and that Vale lifts comments and docstrings out of source code with tree-sitter grammars so a comment marker inside a string literal stays code.
Does Vale need an internet connection to run?
The README states the tool runs entirely offline on macOS, Windows and Linux. The sync step that pulls style packages is a separate operation from linting a directory.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/vale-cli-vale)