How to Debug Automattic/harper: A Complete Guide to Troubleshooting the Grammar Checker

To debug Automattic/harper, set RUST_BACKTRACE=1 and RUST_LOG=debug environment variables, use the CLI's built-in debug subcommand, attach debuggers to individual components like harper-ls or the desktop highlighter, and leverage the repository's justfile recipes for streamlined development workflows.

Automattic/harper is a multi-language grammar-checking ecosystem built around a Rust core (harper-core) that powers CLI tools, language servers, desktop overlays, and WebAssembly bindings. Because the same core library runs across diverse front-ends—from terminal applications to browser plugins—debugging requires component-specific strategies while leveraging common Rust tooling. This guide covers the exact source file locations, environment variables, and diagnostic commands needed to troubleshoot issues across the entire Harper codebase.

Debugging the Core Engine (harper-core)

The heart of Harper lives in the harper-core crate, where most runtime errors surface. To debug the core library, compile with backtrace support and run the test suite:

RUST_BACKTRACE=1 cargo test -p harper-core

If you need to step through execution, attach lldb or gdb directly to the compiled test binaries. The core's entry points are located in harper-core/src/lib.rs, while the primary lint group construction happens in harper-core/src/expr_linter_skeleton.rs. Adding eprintln! statements in these files provides immediate diagnostic output during development.

Debugging the CLI (harper-cli)

The CLI serves as the primary debugging tool for Harper. It includes a dedicated debug subcommand defined in the Cli struct at harper-cli/src/main.rs#L43-L51, which prints internal state when combined with linting flags.

Run the CLI with debug output enabled:

cargo run -p harper-cli -- lint --debug path/to/file.txt

The actual lint implementation resides in harper-cli/src/lint.rs. You can add temporary eprintln! statements here or in the core library to dump runtime values—these diagnostic prints are stripped before release builds.

Debugging the Language Server (harper-ls)

The LSP server (harper-ls) forwards requests from editors like VS Code, Neovim, and Helix to the core engine. To debug the server, run it directly with debug logging enabled:

RUST_LOG=debug cargo run -p harper-ls -- --stdio

The server's request handling logic lives in harper-ls/src/backend.rs. Insert tracing::debug! calls in this file to surface the exact JSON-RPC messages exchanged between the editor client and the Harper backend.

Debugging the Desktop Highlighter (harper-desktop)

The desktop UI consists of a Tauri front-end and a native highlighter process that communicates via newline-delimited JSON. You can attach a debugger to the highlighter by running it as a standalone process:

cargo run -p harper-desktop -- highlighter

The highlighter's IPC messages are defined in harper-desktop/src-tauri/src/communication/message.rs. Use eprintln! statements in this module to emit debug diagnostics safely without breaking the JSON protocol. The desktop entry point at harper-desktop/src-tauri/src/main.rs controls the highlighter process lifecycle and bridges the UI components.

Debugging WebAssembly Builds (harper-wasm)

The WASM module powers browser integrations and the harper.js npm package. Debugging WebAssembly requires source maps and browser DevTools:

  1. Build with development source maps using the justfile recipe at justfile#L63-L77:

    just build-wasm
  2. Open your browser's DevTools and load a page importing harper_wasm.js

  3. Set breakpoints in the generated JavaScript—the source maps will map execution back to the original Rust code

The build configuration uses wasm-pack build --target web --dev to ensure debug symbols are available.

Essential Environment Variables

All Rust binaries in the Harper ecosystem respect standard Rust logging and backtrace environment variables:

  • RUST_LOG: Controls verbosity using the env_logger crate. Use RUST_LOG=trace for maximum output, or target specific crates with harper_core=debug.
  • RUST_BACKTRACE: Set to 1 for basic stack traces or full for complete call stacks on panic.

Example of filtering logs to the core crate only:

RUST_LOG=harper_core=debug cargo run -p harper-cli -- lint path/to/file.txt

For full diagnostic output during testing:

RUST_BACKTRACE=full RUST_LOG=debug cargo run -p harper-cli -- lint --quiet examples/README.md

Streamlining Development with Just Commands

Harper includes a comprehensive justfile with shortcuts for common debugging tasks. The most useful recipes include:

  • just dev-desktop: Spins up the desktop UI with live-reload enabled
  • just dev-web: Launches the documentation site with embedded linting
  • just test-harperjs: Runs the full JavaScript binding test suite to surface WASM bridge errors
  • just fmt: Runs cargo fmt and pnpm format to prevent spurious parsing failures

List all available commands with just --list. These recipes are defined around justfile#L33-L41 and provide consistent build flags across components.

Summary

  • Core debugging: Use RUST_BACKTRACE=1 cargo test -p harper-core and attach debuggers to harper-core/src/lib.rs
  • CLI diagnostics: Leverage the debug subcommand at harper-cli/src/main.rs#L43-L51 and add eprintln! statements in harper-cli/src/lint.rs
  • LSP troubleshooting: Run RUST_LOG=debug cargo run -p harper-ls -- --stdio and instrument harper-ls/src/backend.rs
  • Desktop debugging: Launch the highlighter process with cargo run -p harper-desktop -- highlighter and use eprintln! in harper-desktop/src-tauri/src/communication/message.rs
  • WASM debugging: Build with just build-wasm (defined at justfile#L63-L77) and use browser DevTools with source maps
  • Universal logging: Set RUST_LOG=trace and RUST_BACKTRACE=full for verbose output across all components

Frequently Asked Questions

How do I attach a debugger to the Harper language server in VS Code?

Run the server manually with RUST_LOG=debug cargo run -p harper-ls -- --stdio in your terminal, then configure VS Code to connect to this running process. Alternatively, set "harper.ls.logLevel": "debug" in your VS Code settings to see debug messages in the editor's output panel without manually launching the server.

Where should I add print statements when debugging the desktop highlighter?

Add eprintln!("DEBUG: {:?}", your_variable); statements in harper-desktop/src-tauri/src/highlighter_process.rs or harper-desktop/src-tauri/src/communication/message.rs. Using eprintln! (stderr) instead of println! ensures the debug output doesn't interfere with the newline-delimited JSON IPC protocol between the highlighter process and the Tauri front-end.

How can I debug WebAssembly-specific issues in Harper?

Build the WASM module using just build-wasm, which invokes wasm-pack build --target web --dev with source maps enabled. Open your browser's DevTools, navigate to the sources tab, and set breakpoints in the generated harper_wasm.js file—the source maps will automatically map execution back to the original Rust source code in harper-wasm/src.

What is the fastest way to run tests while debugging the core engine?

Use RUST_BACKTRACE=1 cargo test -p harper-core to run the core test suite with full backtraces enabled. This command targets only the harper-core package, avoiding unnecessary compilation of the CLI, LSP server, or desktop components while you iterate on core logic in harper-core/src/lib.rs or harper-core/src/expr_linter_skeleton.rs.

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 →