# How to Contribute to Automattic Harper: The Complete Guide to This Rust Grammar Checker

> Learn how to contribute to Automattic Harper, the Rust grammar checker. Clone the repo, set up the toolchain, and submit your changes via pull request.

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

---

**To contribute to Automattic Harper, clone the repository, run `just setup` to configure the build toolchain, select a component from the Rust core to the WebAssembly bridge, and submit changes via pull request after running `just precommit` to verify formatting and tests.**

Automattic Harper is a high-performance grammar checker built as a modular Rust monorepo with WebAssembly bindings and editor integrations. Whether you want to improve the core linting engine, add language server features, or build plugins for VS Code and Obsidian, understanding the repository structure is essential before you contribute to Automattic Harper.

## Understanding the Harper Monorepo Architecture

Harper organizes its codebase into distinct packages that share a common Rust core. Knowing where each component lives helps you target contributions effectively.

The repository structure includes:

- **harper-core**: The Rust engine at `harper-core/src` that tokenizes, parses, and lints English text. It provides the `Document`, `Parser`, and `Linter` traits.
- **harper-wasm**: Builds the WebAssembly binary using `wasm-pack`, located in the `harper-wasm` directory.
- **harper-ls**: The Language Server Protocol implementation in `harper-ls` that powers VS Code, Neovim, Helix, and Emacs.
- **harper.js**: The NPM package in [`harper.js`](https://github.com/Automattic/harper/blob/main/harper.js) that loads the WASM module for Node.js and browser environments.
- **Integration plugins**: Chrome/Firefox extensions, Obsidian, and WordPress plugins, each with their own `pnpm`-based build pipeline.
- **harper-desktop**: A Tauri/SvelteKit desktop application providing an overlay highlighter.

## Setting Up Your Development Environment

Before writing code, install the required tooling: `just` (task runner), `cargo` (Rust), `pnpm`, `node`, and `wasm-pack`. The repository automates dependency installation through the `justfile`.

Run the setup command from the repository root:

```bash
just setup

```

This command populates caches and pulls all dependencies across the monorepo, preparing you to build any component.

## The Contribution Workflow

Follow these steps to ensure your contribution aligns with project standards and passes CI.

### 1. Review the Contributor Documentation

Start with the contributor introduction at `packages/web/src/routes/docs/contributors/introduction/+page.md`. This explains where to file bugs, ask questions, and find environment-specific guides.

### 2. Fork and Branch

Create a fork on GitHub and branch from `main` using a descriptive name related to your feature or fix.

### 3. Pick Your Target

Decide whether you will work on:

- The **core engine** (`harper-core`) for grammar rules and parsing
- The **language server** (`harper-ls`) for LSP features
- **JavaScript bindings** ([`harper.js`](https://github.com/Automattic/harper/blob/main/harper.js)) for API improvements
- **Editor plugins** (VS Code, Obsidian, etc.)
- The **desktop application** (`harper-desktop`)

The architecture overview at `packages/web/src/routes/docs/contributors/architecture/+page.md` maps these relationships.

### 4. Code to Standards

All Rust code must pass `cargo fmt` and `cargo clippy`. JavaScript and TypeScript code must pass `pnpm format`. The project uses **conventional commit** messages (documented in `packages/web/src/routes/docs/contributors/committing/+page.md`).

### 5. Run Pre-Commit Checks

Before pushing, execute:

```bash
just format
just precommit

```

The `just format` command formats all Rust and JavaScript code. The `just precommit` task runs the full test suite and linters. Fix any failures before submitting.

### 6. Open a Pull Request

Push your branch and open a PR against `main`. GitHub Actions automatically lint the contribution. Reviewers expect all checks to pass and guidelines to be honored.

## Essential Commands for Contributors

The `justfile` serves as the single source of truth for build scripts. Here are the commands you'll use most frequently when you contribute to Automattic Harper.

### Building the Project

Compile the entire repository or specific components:

```bash

# Build everything including WebAssembly

just build-web

# Build the Chrome extension specifically

just build-chrome

```

### Running Tests

Execute the test suites for different components:

```bash

# Run Rust unit tests

just test-rust

# Run VS Code extension tests

just test-vscode

# Run Chrome extension tests

just test-chrome

```

### Using the CLI for Testing

Test the core engine directly on files:

```bash
cargo run --bin harper-cli -- lint README.md

```

This uses the same `Document` and `Linter` traits that power all integrations.

### Adding Dictionary Words

To add curated nouns to the dictionary:

```bash
just addnoun "HarperBot"

```

This appends the entry to `harper-core/dictionary.dict` with proper formatting.

## Implementing New Linters

To add a new grammar rule, create a Rust file in `harper-core/src/linting/linters/` and implement the `Linter` trait:

```rust
// Example: harper-core/src/linting/linters/my_rule.rs
pub struct MyRule;

impl Linter for MyRule {
    fn lint(&self, doc: &Document) -> Vec<Lint> {
        // Detection logic here
        vec![]
    }
}

```

Register your linter in [`harper-core/src/linting/lint_group.rs`](https://github.com/Automattic/harper/blob/main/harper-core/src/linting/lint_group.rs) to include it in the default lint set. After changes, run:

```bash
just format
just test-rust

```

## Summary

- Automattic Harper is a Rust monorepo with WebAssembly bindings, language servers, and editor plugins.
- Run `just setup` to configure your environment, then use `just precommit` before submitting PRs.
- Core contributions modify `harper-core/src/`, while integrations live in separate package directories.
- All code must pass `cargo fmt`, `cargo clippy`, or `pnpm format`, and use conventional commit messages.
- The `justfile` centralizes build commands like `just test-rust`, `just build-web`, and `just addnoun`.

## Frequently Asked Questions

### What programming languages do I need to know to contribute to Automattic Harper?

You will primarily work with **Rust** for the core engine and language server, and **JavaScript/TypeScript** for the WASM bindings, VS Code extension, Obsidian plugin, and desktop application. The Chrome extension and web packages may also require Svelte or HTML/CSS knowledge.

### How do I run the Harper CLI locally to test my changes?

Use Cargo to run the CLI binary directly: `cargo run --bin harper-cli -- lint path/to/file.rs`. This executes the `harper-cli` tool using your local source code, allowing you to test grammar rules against any text file before committing changes.

### Where should I add a new grammar rule or linter?

Create a new file in `harper-core/src/linting/linters/` implementing the `Linter` trait, then register it in [`harper-core/src/linting/lint_group.rs`](https://github.com/Automattic/harper/blob/main/harper-core/src/linting/lint_group.rs). This directory contains all linting implementations, and the [`lint_group.rs`](https://github.com/Automattic/harper/blob/main/lint_group.rs) file manages which rules are active by default.

### How do I add words to Harper's curated dictionary?

Run the command `just addnoun "YourWord"` from the repository root. This utility updates `harper-core/dictionary.dict` with the proper flags and formatting required by the core tokenizer, ensuring consistent dictionary management across the project.