# How to Use the Harper Command-Line Interface (CLI) for Grammar Checking

> Learn to use the Harper CLI for grammar checking directly in your terminal. Explore lint parse and spans commands with custom dialects and dictionaries.

- Repository: [Automattic/harper](https://github.com/Automattic/harper)
- Tags: how-to-guide
- Published: 2026-08-01

---

**The Harper CLI (`harper-cli`) is an experimental binary that exposes Harper’s grammar-checking engine directly in your terminal, supporting sub-commands like `lint`, `parse`, and `spans` with configurable dialects, dictionaries, and output formats.**

The Harper command-line interface provides direct access to the same grammar and spelling engine that powers the Harper language server and editor extensions. Built on top of `harper-core`, the CLI allows you to lint text files, inspect token streams, and integrate grammar checking into CI pipelines without requiring a graphical environment.

## Installing the Harper CLI

You can compile and install the binary directly from the repository using Cargo. This installs the `harper-cli` executable to your local cargo bin directory.

```bash
cargo install --path harper-cli --locked

```

The installation process compiles the CLI against the locked dependency versions specified in the repository, ensuring compatibility with the core library components defined in `harper-core`.

## Core Commands and Architecture

The CLI entry point in [`harper-cli/src/main.rs`](https://github.com/Automattic/harper/blob/main/harper-cli/src/main.rs) uses **clap** to define the `Cli` struct and route sub-commands. The primary functionality resides in [`harper-cli/src/lint.rs`](https://github.com/Automattic/harper/blob/main/harper-cli/src/lint.rs), which implements the `lint` function along with supporting types like `LintOptions` and the `OutputFormat` enum.

### Linting Text and Documents

The **`lint`** sub-command is the most common entry point. It reads one or more text files (or standard input) and reports grammar and spelling issues using the same rule engine as the graphical extensions.

```bash

# Lint a single file

harper-cli lint src/docs/example.md

# Lint multiple files with glob patterns

harper-cli lint src/**/*.md

# Lint from standard input in a pipeline

cat README.md | harper-cli lint -

```

The lint implementation loads the curated dictionary, optionally merges user and file-specific dictionaries, creates a `LintGroup`, executes the rule set, and formats results according to your selected output style.

### Inspecting Token Structure

Beyond linting, the CLI provides utilities for debugging and analysis:

- **`parse`** – Displays the token stream generated by Harper’s parsers
- **`spans`** – Shows token spans with positional information
- **`metadata`** – Retrieves lexical metadata for the input text

```bash

# Show token spans including newline characters

harper-cli spans --include-newlines src/main.rs

```

## Configuration and Dictionaries

The Harper CLI respects the same configuration conventions as `harper-ls`, looking for dictionaries in platform-specific directories while allowing explicit overrides via command-line flags.

### User and File Dictionaries

By default, the CLI searches for a user dictionary at `config_dir()/harper-ls/dictionary.txt` and file-local dictionaries under `data_local_dir()/harper-ls/file_dictionaries/`. You can override these locations using:

- **`--user-dict-path`** – Path to a plain-text dictionary file loaded into a `MutableDictionary`
- **`--file-dict-path`** – Directory containing file-specific dictionary overrides

```bash
harper-cli lint --user-dict-path ~/.config/harper/my-dict.txt document.md

```

### Dialect Selection

Use the **`--dialect`** flag to specify spelling conventions for the linting session. Supported values include `us` (American), `gb` (British), `ca` (Canadian), and `au` (Australian) English.

```bash
harper-cli lint --dialect gb document.txt

```

### Weirpack Rule Extensions

The CLI supports loading custom rule packs via **Weirpack** files. The `load_dict` function in [`harper-cli/src/lint.rs`](https://github.com/Automattic/harper/blob/main/harper-cli/src/lint.rs) handles reading these binary files and injecting custom rules into the linter.

```bash
harper-cli lint --weirpack rules/custom.weirpack src/**/*.txt

```

## Output Formats

The `OutputFormat` enum in [`harper-cli/src/lint.rs`](https://github.com/Automattic/harper/blob/main/harper-cli/src/lint.rs) defines three reporting styles selectable via the **`--format`** flag:

- **`default`** – Rich, colorized Ariadne reports with contextual snippets
- **`json`** – Machine-readable JSON output for integration with other tools
- **`compact`** – Single-line-per-issue format suitable for logs or quick scans

```bash

# JSON output for CI integration

harper-cli lint --format json --no-color src/**/*.md

# Compact format for quick review

harper-cli lint --format compact document.txt

```

Use **`--no-color`** to suppress ANSI color codes when redirecting output to files or systems that do not support terminal formatting.

## Rule Filtering

Control which rules execute during a linting run with filtering options:

- **`--only <rule>`** – Run only the specified rule (e.g., `passive-voice`)
- **`--ignore <rule>`** – Skip the specified rule
- **`--count`** – Display only the error count rather than full diagnostics

```bash

# Run only the passive voice rule and show error count

harper-cli lint --only passive-voice --count src/**/*.rs

```

## Practical Workflow Examples

```bash

# 1️⃣ Install the binary (run once)

cargo install --path harper-cli --locked

# 2️⃣ Lint a single file with default settings

harper-cli lint src/docs/example.md

# 3️⃣ Lint multiple files, suppress colour, and output JSON

harper-cli lint --no-color --format json src/**/*.md

# 4️⃣ Lint from standard input (useful in pipelines)

cat README.md | harper-cli lint -

# 5️⃣ Apply a custom Weirpack with additional rules

harper-cli lint --weirpack rules/custom.weirpack src/**/*.txt

# 6️⃣ Run only the “passive‑voice” rule and count errors

harper-cli lint --only passive-voice --count src/**/*.rs

# 7️⃣ Show token spans for a file (useful for debugging)

harper-cli spans --include-newlines src/main.rs

```

## Summary

- The **Harper CLI** provides terminal access to the full `harper-core` grammar engine used by editor extensions and language servers.
- Key source files include [`harper-cli/src/main.rs`](https://github.com/Automattic/harper/blob/main/harper-cli/src/main.rs) for argument parsing and [`harper-cli/src/lint.rs`](https://github.com/Automattic/harper/blob/main/harper-cli/src/lint.rs) for the linting logic and output formatting.
- The **`lint`** sub-command supports stdin, multiple files, and three output formats: default (Ariadne), JSON, and compact.
- Configuration options include **`--dialect`**, **`--user-dict-path`**, **`--file-dict-path`**, and **`--weirpack`** for customizing dictionaries and rule sets.
- Because the CLI is a thin wrapper around the core library, behavior remains consistent across all Harper integrations, making it ideal for CI pipelines and batch processing.

## Frequently Asked Questions

### How do I install the Harper CLI?

Compile and install the binary using Cargo from the repository root: `cargo install --path harper-cli --locked`. This builds the experimental `harper-cli` binary and places it in your cargo bin directory, ready for use in your terminal.

### Can I use harper-cli in CI pipelines?

Yes. Use the **`--format json`** flag for machine-readable output that CI systems can parse, and **`--no-color`** to disable terminal formatting. The CLI exits with a non-zero status when lints are found, making it compatible with standard CI failure detection mechanisms.

### What is the difference between the Harper CLI and harper-ls?

The **Harper CLI** (`harper-cli`) is a standalone binary for one-off linting and text analysis from the command line, while **harper-ls** is a language server protocol implementation for continuous integration with editors. Both use the same `harper-core` library and configuration paths, but the CLI is better suited for batch processing and scripting.

### How do I add custom words to the Harper dictionary?

Create a plain-text file with one word per line and pass it via **`--user-dict-path`**, or place it at the default location `config_dir()/harper-ls/dictionary.txt`. The CLI loads this into a `MutableDictionary` during initialization, merging your custom words with the curated built-in dictionary before linting begins.