How to Find Configuration Files in Automattic/harper: A Complete Guide to Core, LSP, and Desktop Settings

Harper stores configuration across five distinct areas—core defaults in harper-core/default_config.json, user-specific files for the language server under ~/.config/harper-ls/, desktop settings in ~/.config/harper-desktop/, plugin descriptors in each package, and web-app build configs—with all paths resolvable through the dirs::config_dir() pattern in harper-ls/src/config.rs and harper-desktop/src-tauri/src/config/mod.rs.

The Automattic/harper repository organizes its configuration across multiple crates and user environments. Whether you're customizing lint rules, debugging the language server, or packaging the desktop app, knowing exactly where each configuration file lives saves hours of searching. This guide maps every configuration entry point in the source tree and shows how Harper resolves them at runtime.


Core Default Configuration

The core default configuration ships as a read-only JSON file compiled into the binary. This defines the baseline lint rules, dialect settings, and dictionary data that all Harper tools inherit.

Location and Structure

  • Source file: harper-core/default_config.json
  • Purpose: Built-in rule sets, dictionary data, and default lint configuration
  • User override: Not writable at runtime; modify the source and rebuild
{
  "rules": {
    "no-passive-voice": { "enabled": true, "severity": "error" },
    "closed-compound-nouns": { "enabled": false }
  },
  "dictionary": { "dialect": "american" }
}

To load these defaults programmatically:

use harper_core::default_config::DefaultConfig;

fn load_core_defaults() -> harper_core::LintConfig {
    // `DefaultConfig::load()` reads the JSON compiled into the binary.
    DefaultConfig::load().unwrap()
}

Modify harper-core/default_config.json directly when you need to change out-of-the-box behavior, then run just test-rust to verify your changes.


Harper LS (Language Server) Configuration

The language server configuration handles LSP-specific options: user dictionary paths, ignored lint rules, dialect preferences, and code-action settings. This is the most frequently customized configuration area.

Runtime Path Resolution

In harper-ls/src/config.rs, the Config struct defines default paths using dirs::config_dir():

// Default resolution: $XDG_CONFIG_HOME/harper-ls/ or ~/.config/harper-ls/
config_dir().unwrap().join("harper-ls/dictionary.txt")

Default User Directory

Platform Path
Linux/macOS ~/.config/harper-ls/ or $XDG_CONFIG_HOME/harper-ls/
Windows %APPDATA%\harper-ls\

Creating and Modifying Config Programmatically

use harper_ls::config::Config;
use std::path::PathBuf;

// The default constructor reads the XDG config directory.
let mut cfg = Config::default();

// Override the dictionary location at runtime (e.g., for tests)
cfg.user_dict_path = PathBuf::from("./my-custom-dictionary.txt");

// Persist the change by writing to the user config folder
cfg.save().expect("Failed to write harper-ls config");

The Config struct in harper-ls/src/config.rs controls file naming conventions and persistence logic.


Harper Desktop Configuration

The desktop application stores UI-related settings and highlighter IPC configuration separately from the language server. It uses Tauri's configuration system with custom Rust-side resolution.

Configuration Locations

File Purpose
harper-desktop/src-tauri/tauri.conf.json Static Tauri configuration (window size, permissions, security policies)
harper-desktop/src-tauri/src/config/mod.rs Runtime config directory resolution

The Rust module calls dirs::config_dir() to resolve ~/.config/harper-desktop/ (or platform equivalent):

// From harper-desktop/src-tauri/src/config/mod.rs
let config_path = config_dir()?.join("harper-desktop");

Accessing Settings from TypeScript

import { Client } from './client';

// Retrieve the whole config object from the Rust side
Client.getLintConfig().then((config) => {
  console.log('Current lint config:', config);
});

The TypeScript helper resides in harper-desktop/src/lib/client.ts, which communicates with the Rust backend reading from the user config directory.


Plugin and Package Configurations

Harper's plugin packages each maintain their own configuration descriptors. These are development-time files, not user-editable at runtime.

Package Configuration File Purpose
WordPress plugin packages/wordpress-plugin/src/harper/block.json Block definition for Gutenberg integration
VS Code extension packages/vscode-plugin/package.json Extension manifest and contribution points
Chrome extension packages/chrome-extension/package.json Browser extension configuration
Web documentation packages/web/vite.config.ts Vite build configuration and sidebar routing
Web documentation packages/web/tsconfig.json TypeScript compiler options

These files follow standard conventions for their respective ecosystems. The WordPress block.json exemplifies plugin-specific JSON descriptors:

{
  "name": "harper/harper",
  "title": "Harper Grammar Checker",
  "category": "common",
  "editorScript": "file:./index.js"
}

Searching the Repository for Configuration Files

Use these commands to locate all configuration-related files in the Automattic/harper repository:


# List all JSON configuration files

git ls-files '**/*.json'

# Find config directory resolution code

git grep -R "config_dir"

# Find all Rust files containing Config struct definitions

git grep -l "struct Config" -- '*.rs'

Typical git ls-files output includes:


Key Files Reference

Bookmark these source locations for quick access:

File Purpose
[harper-core/default_config.json](https://github.com/Automattic/harper/blob/master/harper-core/default_config.json) Default lint rule set and dialect
[harper-ls/src/config.rs](https://github.com/Automattic/harper/blob/master/harper-ls/src/config.rs) Runtime Config struct with path resolution
[harper-desktop/src-tauri/src/config/mod.rs](https://github.com/Automattic/harper/blob/master/harper-desktop/src-tauri/src/config/mod.rs) Desktop config directory handling
[harper-desktop/src-tauri/tauri.conf.json](https://github.com/Automattic/harper/blob/master/harper-desktop/src-tauri/tauri.conf.json) Static Tauri application configuration
[packages/web/vite.config.ts](https://github.com/Automattic/harper/blob/master/packages/web/vite.config.ts) Documentation site build configuration

Summary


Frequently Asked Questions

Where does Harper LS store user configuration on Linux and macOS?

Harper LS follows the XDG Base Directory Specification. It stores user configuration in $XDG_CONFIG_HOME/harper-ls/ if the environment variable is set, otherwise falling back to ~/.config/harper-ls/. The path resolution logic appears in harper-ls/src/config.rs using the dirs::config_dir() crate.

How do I change Harper's default lint rules for all users?

Edit harper-core/default_config.json in the repository source, then rebuild. This JSON file compiles into the binary via DefaultConfig::load(), making it the authoritative source for out-of-the-box rule settings. Run just test-rust after modifications to ensure the new defaults pass validation.

What's the difference between harper-ls and harper-desktop configuration?

Harper LS configuration controls language server behavior—diagnostics, code actions, dictionary paths, and ignored rules. Harper Desktop configuration manages UI state, window geometry, and highlighter IPC settings. They use separate directories (harper-ls/ vs. harper-desktop/) under the XDG config root, with distinct Rust modules handling path resolution.

How can I programmatically discover where Harper will write config files?

Import the relevant config module and inspect the resolved path. For Harper LS: Config::default() reveals the active paths after dirs::config_dir() resolution. For Desktop: the config_dir() function in harper-desktop/src-tauri/src/config/mod.rs exposes the same information. Both respect $XDG_CONFIG_HOME on Unix systems and %APPDATA% on Windows.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →