Self-hosted service
vale-cli/vale avatar
vale-cli/vale

Default branch v3, three vendor identities across install channels, and an image that installs four extra packages

:pencil: A markup-aware linter for prose built with speed and extensibility in mind.

6,387 stars240 forksGoMIT

At a glance

What is it?
Vale is a linter for prose that ships no style of its own and instead enforces whatever rules you point it at. The rules are YAML files that can carry their own fix, the parsing is real rather than heuristic, and the project itself is a good example of the trade-offs: a Makefile release target that only pushes a tag, an image with four extra packages, and a manifest carrying two majors of the same library.
Who is it for?
Vale is the right tool when your writing rules already exist somewhere other than a word processor, because rules are YAML files and a published guide like Microsoft's is one config line away. Decide two things before you wire it into a repository.
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 November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • vale-cli/vale6,387 ★ · +240
Star history
Repository2026-09-232026-11-14
vale-cli/vale6.1k6.4k

240 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Three install channels carry three vendor names

The install table lists a package manager per platform, and the identifiers underneath them do not share an owner. macOS gets the plain formula name, Windows gets a Chocolatey package of the same name plus a winget identifier that begins with a different organisation entirely, and Linux gets snap, pacman and apt. The container image is published under the maintainer's personal handle rather than the project name, and the build file defaults its Docker user to that same handle. So a single tool is distributed under the project name in two package managers, under a vendor organisation in winget, and under an individual account on a container registry. The Go install path is the only one that carries the module path verbatim, including its major version suffix. None of this is broken, and each identifier is documented in the table, but it means an installation script that assumes one owner string across channels will fail on at least two of them.

The sample output stops mid-word and the counts only add up with the suggestions

The console sample is the most informative thing on the page, and it ends badly. It shows a sync command reporting two packages written into a styles directory:

console
$ vale sync
 SUCCESS  Synced 2 package(s) to 'styles'.

Then a directory argument produces per-file findings with a line and column, a level, a message and a rule name. The rule names are the interesting part, because they carry their package: a suggestion to prefer one word over another comes from a wordiness rule, a passive-voice note from a passive rule, the one warning from a user-interface verbs rule, and the two errors come from a document-specific terms rule and a spelling rule. Two files are linted, with three findings in the first and two in the second. The summary line then reads two errors, one warning and a fragment, ending at the letters an, where and the suggestion count would have followed. So the visible counts describe the errors and the warning only, and the two suggestions are the part the truncated line was going to add up.

A rule is a YAML file, and it can carry its own fix

Rules are YAML files, and styles are pulled in through the configuration file: the quickstart names a published package with Packages = Microsoft, applies it with BasedOnStyles = Vale, Microsoft, and vale sync downloads it. The sample output shows an in-house rule at work too, a Docs.Terms error telling the reader to use 'Vale CLI' instead of 'Vale cli'. Extension points run from a token list through part-of-speech patterns, cross-file relationships and readability formulas to scripts. And a rule may carry a fix, which an editor applies with one keystroke and an agent applies without deciding anything.

Comments are lifted out of source with tree-sitter, and a string stays a string

The feature that distinguishes this from a plain text linter is that documentation is code. Comments and docstrings are extracted with tree-sitter grammars and linted as though they were their own files, so the Markdown inside a Rust documentation comment and the reStructuredText inside a Python docstring are both checked. The edge case the page calls out is the one that matters: a comment marker appearing inside a string literal stays code rather than being treated as prose. That is a parser's job, not a regular expression's, which is why the project claims it parses markup instead of guessing at it, with code spans, urls and fenced blocks skipped before any rule runs. The dependency list backs the claim up with two separate tree-sitter bindings, one general and one for a specific language, alongside a Markdown parser, an Org-mode parser and a CSS selector library.

The container installs four runtimes and skips a fifth because it would be seven times the size

The image builds with a Go toolchain on Alpine, with cgo enabled, and compiles the command with the version string injected at link time. The runtime stage is where it gets unusual. Four packages are installed: a Python documentation tool, an AsciiDoc converter, Node and npm, and then one npm package installed globally, mdx2vast. That single package is why the image needs Node at all. Left commented out at the top of the file is a fifth path: an XML toolchain with a Java runtime and a transformation library, with a note explaining that it is not packaged because it makes the size seven times as big, and a commented-out environment line that would have added its bin directory to the path. So the image is a document converter with a linter attached, and the size budget is written into the file as a reason.

make release creates a tag and pushes it, and does nothing else

The build file's release target is two commands: create a tag with the name passed in, then push that tag to the origin. No build, no packaging, no upload. Everything that turns a tag into a release is elsewhere, and the configuration for it sits at the repository root as a separate file. What the Makefile does do is keep the version string honest, deriving the most recent tag from the repository description command and passing it into the linker as the program's version, so a binary built from a checkout says what tag it came from. Cross-compilation is by variable, with the operating system and architecture overridable on the command line and an executable suffix added automatically on Windows. Container builds are narrower: the two targets listed are Linux on arm64 and Linux on amd64, nothing else.

The manifest carries two majors of one library and two expression languages

The dependency list is unusual in three ways worth noticing. First, two major versions of the same data-manipulation library appear as direct requirements, both of them, which is the kind of pairing that usually happens by accident. Second, two expression languages are compiled in: one general-purpose scripting language and one expression evaluator, both direct dependencies, which is what makes the promise of scriptable extension points and of readability formulas implementable rather than aspirational. Third, a backtracking regular expression engine is pulled in indirectly, which is the price of regular expressions that are not the regular-expression dialect most languages ship. Around those sit the pieces the format support implies: a Markdown parser, an Org-mode parser, tree-sitter bindings, a TOML parser, an INI parser, YAML, glob matching with doublestar semantics, a template function library, a table writer and a progress display library.

Private by design, on a page sponsored by two products that run it in CI

One of the reasons to use this tool is stated flatly: nothing leaves your machine, there is no account, no upload, and no training on your writing, and it is a single binary in Go with no runtime to install. Two sections earlier on the same page, the sponsor spotlights describe something different. One sponsor is described as shipping the linter as a built-in continuous integration check, and another as running it on every document its agents write, with the second one also suggesting documentation updates when a product changes. None of that contradicts the claim, because a server-side check is not an upload and an editor plugin is not a training set, but the two arrangements live at opposite ends of a spectrum the page never reconciles: a local pre-commit hook versus a hosted service that reads every document a company writes. The repository dogfoods the local end, with its own configuration file at the root and a set of published pre-commit hooks.

Editorial conclusion

Vale is the right tool when your writing rules already exist somewhere other than a word processor, because rules are YAML files and a published guide like Microsoft's is one config line away. Decide two things before you wire it into a repository. Which rules you actually want enforced, since the project deliberately ships none and a configuration file with a package name in it is the entire setup. And where it runs, because the page insists nothing leaves your machine while one sponsor ships it as a built-in CI check and another runs it on every doc its agents write. Both arrangements are legitimate, but they are different promises. Also check the channel you install from: the winget package identifier belongs to a different vendor name than the container image, and the default branch is v3 rather than main.

Frequently asked questions

What is a Vale ruleset?

Vale enforces your style: a published guide like Microsoft's or Google's, an in-house set of terms, or both. Rules are YAML files, and the quickstart pulls in a published package with Packages = Microsoft in the configuration file and applies it with BasedOnStyles = Vale, Microsoft.

What is vale sh?

It is the project's site and its documented home, listed as the homepage and linked from the header along with the documentation, a quickstart page, a package explorer for published styles, a content system, a blog and a chat invite.

Does Vale send my writing anywhere?

The page says nothing leaves your machine: no account, no upload, no training on your writing, one Go binary and no runtime to install. Two sponsor descriptions on the same page describe server-side use: Mintlify ships Vale as a built-in CI check, and Promptless runs Vale on every doc its agents write.

How do I install Vale on Linux?

Three package managers are listed for Linux, one each for snap, pacman and apt, each installed with sudo. A Go install path is also given using the module path with its major version, and prebuilt binaries for every platform are on the releases page, with Scoop, MacPorts, FreeBSD ports and conda-forge named on the installation page.

Which branch does Vale develop on?

The default branch is v3, matching the major version suffix in the module path and in the Go install command. The recent releases are all in that line, with the newest at v3.26.0.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. vale-cli/vale on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/vale-cli-vale.svg)](https://hysenlabs.com/projects/vale-cli-vale)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/vale-cli-vale.svg)](https://hysenlabs.com/projects/vale-cli-vale)

Was this useful?