agentleFS
AutomatticAutomattic/harper/AGENTS.md

harper

AGENTS.md17k starsChanged 5 months agoApache-2.0View on GitHub

This repository’s documentation site is powered by Vite + SvelteKit + SveltePress. Use packages/web/vite.config.ts as the source of truth for documentation scope: - Sidebar and important doc routes are defined in packages/web/vite.config.ts. - Route /docs/... maps to packages/web/src/routes/docs/.... - Most docs are in +page.md; some are +page.svelte or route helpers. If you are working on the Harper repository itself, please pay special attention to the contributors/* pages. Importantly, all the tools available in this repository are available via just. To…

We split this AGENTS.md into the rules it gives an agent

22 rules. About 0 are common, 9 are distinctive, and 13 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈9

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 13

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use packages/web/vite.config.ts as the source of truth for documentation scope:

    line 5
  2. Very specific:

    If you are working on the Harper repository itself, please pay special attention to the contributors/* pages.

    line 10
  3. Very specific:

    If just format fails, you can use just setup to prepare the relevant dependencies.

    line 13
  4. Distinctive:

    Read the Desktop contributor documentation for the app's architecture and its relationship to the Cargo workspace.

    line 117
  5. Very specific:

    Use pnpm for frontend packages.

    line 121
  6. Very specific:

    Start the highlighter process directly: just dev-desktop-highlighter from repo root.

    line 123
  7. Very specific:

    Keep dictionary construction centralized through Config::dictionary_from_user_dictionary(user_dictionary: MutableDictionary) -> …

    line 193
  8. Very specific:

    Keep linter construction centralized through Config::create_linter().

    line 194
  9. Very specific:

    Do not use Document::new_markdown_default_curated(text) in the main highlighter lint callback when user dictionary words should suppress …

    line 196
  10. Distinctive:

    Avoid mixing behavior fixes with structural refactors in the highlighter.

    line 213
  11. Distinctive:

    When asked to write a new rule, keep these guidelines in mind:

    line 222
  12. Very specific:

    After adding a new rule, update harper-core/default_config.json so it is enabled in the curated default config.

    line 227
  13. Distinctive:

    If the rule is related to a closed compound noun, see if you can just add an entry to the existing closed compound linter.

    line 229
  14. Very specific:

    ALWAYS run extensive bullet tests with cargo run --bin harper-cli --release -- lint <TEXT> to make sure the new rule isn't already covered …

    line 233
  15. Distinctive:

    Keep the expression minimal but precise.

    line 239
  16. Distinctive:

    If a wordlist is needed, include it as its own expression, used with an expression reference.

    line 240
  17. Very specific:

    Use strategy "Exact" when casing must be normalized.

    line 244
  18. Distinctive:

    Prefer a mix of casing, punctuation, whitespace, and nearby-token variations.

    line 249
  19. Distinctive:

    Ensure exceptions do not block valid matches.

    line 252
  20. Distinctive:

    Ensure replacements are correct and not destructive.

    line 253
  21. Very specific:

    Write a Weir rule to a new file with a name of your choosing, including expr main, let fields, and tests.

    line 260
  22. Very specific:

    Before finishing your turn, run just format or cargo fmt if you have made any changes.

    line 264

≈ “Common” is an estimate: at least 1 in 5 of the 36,368 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

Harper Docs Map for Agents

This repository’s documentation site is powered by Vite + SvelteKit + SveltePress.

Use packages/web/vite.config.ts as the source of truth for documentation scope:

  • Sidebar and important doc routes are defined in packages/web/vite.config.ts.
  • Route /docs/... maps to packages/web/src/routes/docs/....
  • Most docs are in +page.md; some are +page.svelte or route helpers.

If you are working on the Harper repository itself, please pay special attention to the contributors/* pages. Importantly, all the tools available in this repository are available via just. To learn more, run just --list. Whenever agents are done making changes, they should run just format before handing work back to the user. If just format fails, you can use just setup to prepare the relevant dependencies.

Human coders should periodically review this file and manually migrate stable, human-facing guidance into the real documentation website under packages/web so it is available outside agent workflows. Agents should remind humans of this when possible.

Read First

  1. packages/web/vite.config.ts: Sidebar source of truth and canonical map of important docs routes.
  2. packages/web/src/routes/docs/about/+page.md: High-level product overview, privacy model, versioning policy, and ecosystem context.
  3. packages/web/src/routes/docs/weir/+page.md: Weir rule language reference with syntax, expression types, and examples.
  4. packages/web/src/routes/docs/rules/+page.svelte: Live/generated rule catalog (rule names, defaults, and descriptions).
  5. packages/web/src/routes/docs/contributors/introduction/+page.md: Entry point for contributors and links to deeper contributor docs.
  6. ./AGENT_POLICY.md: Harper's policy on code generated by large language models. Agents MUST read this before making ANY changes.

Core Documentation Directories

  • packages/web/src/routes/docs/about
  • packages/web/src/routes/docs/weir
  • packages/web/src/routes/docs/rules
  • packages/web/src/routes/docs/integrations
  • packages/web/src/routes/docs/harperjs
  • packages/web/src/routes/docs/contributors

Route Prefix to File Prefix

  • /docs/about -> packages/web/src/routes/docs/about/+page.md
  • /docs/weir -> packages/web/src/routes/docs/weir/+page.md
  • /docs/rules -> packages/web/src/routes/docs/rules/+page.svelte
  • /docs/integrations/* -> packages/web/src/routes/docs/integrations/*/+page.md
  • /docs/harperjs/* -> packages/web/src/routes/docs/harperjs/*/+page.md
  • /docs/contributors/* -> packages/web/src/routes/docs/contributors/*/+page.md

Files Listed in the Sidebar (Local)

  • packages/web/src/routes/docs/about/+page.md: High-level product overview, privacy model, versioning policy, and ecosystem context.
  • packages/web/src/routes/docs/weir/+page.md: Weir rule language reference with syntax, expression types, and examples. Very important if you're asked to write a Weir rule.
  • packages/web/src/routes/docs/rules/+page.svelte: Live/generated rule catalog (rule names, defaults, and descriptions).
  • packages/web/src/routes/docs/integrations/obsidian/+page.md: Obsidian plugin overview, privacy/value comparison, installation, and support links.
  • packages/web/src/routes/docs/integrations/chrome-extension/+page.md: End-user Chrome extension overview and install link.
  • packages/web/src/routes/docs/integrations/firefox-extension/+page.md: End-user Firefox extension overview and install link.
  • packages/web/src/routes/docs/integrations/wordpress/+page.md: Current WordPress guidance, including migration recommendation to Chrome extension and legacy plugin status.
  • packages/web/src/routes/docs/integrations/language-server/+page.md: harper-ls install methods, dictionaries, code actions, ignore comments, and full configuration reference.
  • packages/web/src/routes/docs/integrations/visual-studio-code/+page.md: VS Code extension install, command list, and settings reference.
  • packages/web/src/routes/docs/integrations/neovim/+page.md: Neovim setup using harper-ls, plus optional and common config tweaks.
  • packages/web/src/routes/docs/integrations/helix/+page.md: Helix setup using harper-ls, plus optional and common config tweaks.
  • packages/web/src/routes/docs/integrations/emacs/+page.md: Emacs setup using harper-ls, plus optional and common config tweaks.
  • packages/web/src/routes/docs/integrations/zed/+page.md: Zed extension entry point and link to canonical extension README.
  • packages/web/src/routes/docs/integrations/sublime-text/+page.md: Sublime Text setup with harper-ls and LSP package configuration.
  • packages/web/src/routes/docs/harperjs/introduction/+page.md: harper.js mission, package overview, and installation starting point.
  • packages/web/src/routes/docs/harperjs/linting/+page.md: Core harper.js lint workflow and linter usage patterns.
  • packages/web/src/routes/docs/harperjs/spans/+page.md: Explains span objects and how to use them to locate/handle lint ranges.
  • packages/web/src/routes/docs/harperjs/configurerules/+page.md: How to programmatically read and set LintConfig to enable/disable rules.
  • packages/web/src/routes/docs/harperjs/node/+page.md: Node.js-specific usage notes, especially LocalLinter vs WorkerLinter.
  • packages/web/src/routes/docs/harperjs/CDN/+page.md: Browser/CDN usage via unpkg and ESM import patterns.
  • packages/web/src/routes/docs/contributors/introduction/+page.md: Contributor onboarding overview and links to architecture/testing/rule-authoring docs.
  • packages/web/src/routes/docs/contributors/environment/+page.md: Local development environment setup across Rust, Node/pnpm, and optional Nix shell.
  • packages/web/src/routes/docs/contributors/committing/+page.md: Commit message conventions and commit hygiene requirements.
  • packages/web/src/routes/docs/contributors/architecture/+page.md: System architecture and roles of core components like harper-core, harper-ls, and harper.js.
  • packages/web/src/routes/docs/contributors/dictionary/+page.md: Process for adding or updating curated dictionary entries.
  • packages/web/src/routes/docs/contributors/testing-strategy/+page.md: Harper's risk-driven testing strategy, covering automated checks, production feedback, manual testing, and testability.
  • packages/web/src/routes/docs/contributors/author-a-rule/+page.md: Step-by-step workflow for implementing and testing new grammar rules.
  • packages/web/src/routes/docs/contributors/visual-studio-code/+page.md: How to run, debug, test, and package the VS Code extension locally.
  • packages/web/src/routes/docs/contributors/chrome-extension/+page.md: Internal architecture and local development notes for the browser extensions.
  • packages/web/src/routes/docs/contributors/desktop/+page.md: Placeholder for Harper Desktop contributor documentation.
  • packages/web/src/routes/docs/contributors/website/+page.md: Local development, preview, and validation for writewithharper.com (SvelteKit/SveltePress).
  • packages/web/src/routes/docs/contributors/wordpress/+page.md: How to build and run the WordPress plugin locally.
  • packages/web/src/routes/docs/contributors/obsidian/+page.md: Obsidian-plugin contributor workflow and plugin-specific constraints.
  • packages/web/src/routes/docs/contributors/review/+page.md: PR reviewer playbook, including ways to fetch artifacts and test patches locally.
  • packages/web/src/routes/docs/contributors/local-stats/+page.md: Local stats logging model, stats.txt format, locations, and privacy behavior.
  • packages/web/src/routes/docs/contributors/brill/+page.md: Brief explanation of Harper’s Brill-tagging approach and further reading link.
  • packages/web/src/routes/docs/contributors/faq/+page.md: Contributor FAQ for conceptual distinctions (for example Linter vs PatternLinter).

Documentation Route Helpers (Non-+page.md)

  • packages/web/src/routes/docs/about/+page.ts: Route behavior helper (ssr = false) for the About page.
  • packages/web/src/routes/docs/harperjs/CDN/example/+server.ts: Serves the HTML example used by the harper.js CDN documentation page.

External Sidebar Targets (No Local Source File)

  • https://docs.rs/harper-core/latest/harper_core/
  • /docs/harperjs/ref/index.html (generated API reference target)

Projects Contained in This Repository

  • harper-core: The core grammar checking engine. This is a dependency to pretty much everything related to Harper.
  • harper-ls: A Language Server compatible with a number of text editors, including Neovim, Zed, and Helix. See above linked documentation for more details.
  • harper-cli: A command-line binary for debugging Harper's core engine and markup language support.
  • harper-comments: Provides parsers for a number of programming languages to support linting their comments.
  • harper-wasm: The WebAssembly build target that powers browser and JavaScript integrations such as harper.js.
  • packages/lint-framework: A package containing the tooling necessary to read/write/highlight text on the web for the purpose of linting.
  • packages/components: Shared Svelte component package used by web-facing packages.
  • packages/harper-editor: Shared Svelte editor package used by web-facing packages and Harper Desktop.
  • packages/web: The Harper website, including documentation and a live demo that uses the lint-framework.
  • packages/harper.js: The JavaScript package that uses harper-wasm to lint text from websites or Node.js processes.
  • packages/chrome-plugin: The Harper Chrome Extension - uses the lint-framework. Also support Firefox.
  • packages/obsidian-plugin
  • packages/wordpress-plugin
  • packages/vscode-plugin: The Harper Visual Studio Code plugin. Uses harper-ls.
  • harper-desktop: The Harper Desktop app. It is a Tauri v2 + SvelteKit SPA with an offline editor, settings UI, tray/service control, and native overlay highlighter.

There are of course projects in this repository not listed above. If relevant, feel free to poke around.

Harper Desktop

Read the Desktop contributor documentation for the app's architecture and its relationship to the Cargo workspace.

Commands

  • Use pnpm for frontend packages; harper-desktop/package.json pins pnpm@10.10.0.
  • Dev app: just dev-desktop from repo root. It builds shared web packages, runs cargo tauri dev, and Tauri then runs pnpm dev on port 1420.
  • Start the highlighter process directly: just dev-desktop-highlighter from repo root.
  • Frontend checks: pnpm check from harper-desktop.
  • Frontend build only: pnpm build from harper-desktop.
  • Full desktop checks: just check-desktop from repo root.
  • Bundle builds match CI: just build-desktop-linux or just build-desktop-macos.
  • just build-desktop-linux builds deb/rpm/appimage bundles.
  • just build-desktop-macos builds app/dmg bundles.

Architecture

  • It is a SvelteKit SPA inside Tauri v2.
  • SSR is disabled in harper-desktop/src/routes/+layout.ts.
  • harper-desktop/svelte.config.js uses adapter-static with fallback: "index.html".
  • Main Rust entrypoint is harper-desktop/src-tauri/src/main.rs, which calls harper_desktop_lib::run().
  • CLI behavior is in harper-desktop/src-tauri/src/lib.rs: no subcommand runs the normal Tauri app; highlighter runs the native overlay highlighter.
  • Tauri config lives in harper-desktop/src-tauri/tauri.conf.json.
  • Tauri capabilities live in harper-desktop/src-tauri/capabilities/default.json.
  • The main Svelte route is harper-desktop/src/routes/+page.svelte; it switches between the settings UI and editor UI.
  • The editor UI lives in harper-desktop/src/lib/EditorView.svelte and uses workspace dependencies on harper.js and harper-editor.
  • The settings UI lives under harper-desktop/src/lib/settings/.
  • Rust uses local workspace dependencies from harper-desktop/src-tauri/Cargo.toml, including harper-core and harper-dictionary-wordlist.
  • The Tauri app starts a tray/menu-bar controlled highlighter service on launch and can open editor/settings windows from the tray.
  • Editor and settings windows hide on close instead of exiting; quit is handled through the tray menu.

Highlighter Architecture

  • The highlighter is Rust/egui/winit code under harper-desktop/src-tauri/src/highlighter/.
  • Highlighter is the public entry point for the overlay system.
  • Window owns native window/GPU plumbing.
  • WindowManager owns the winit event loop, monitor windows, cursor hit-testing, and popup selection.
  • RenderState owns highlight rendering, popup drawing, markdown rendering cache, and popup action dispatch.
  • RenderState uses ActionableLint values from harper-desktop/src-tauri/src/rect.rs.
  • ActionableLint stores lint geometry, the Harper Lint, and source text needed for suggestion application and popup actions.
  • Suggestion popup actions currently include close, apply suggestion, ignore lint, add to dictionary, disable rule, and refresh config.
  • Popup hover text is implemented in RenderState button helpers.
  • The highlighter read interval is set in run_highlighter() with with_read_interval(Duration::from_millis(16)).

OS Integration

  • OS integration is behind harper-desktop/src-tauri/src/os_broker.rs.
  • macOS uses harper-desktop/src-tauri/src/mac_broker.rs.
  • non-macOS currently uses NoopBroker.
  • macOS highlighter focus handling depends on MacBroker.last_focused; clicking the overlay can make the highlighter process focused, so accessibility reads fall back to the last non-highlighter PID.
  • macOS integrations are bundle-ID based and controlled by persisted Integration entries.
  • Highlighter stdout is reserved for JSON-line IPC. Diagnostics in highlighter paths should use eprintln!, not println!.

IPC And App State

  • Tauri app state lives in harper-desktop/src-tauri/src/config.rs.
  • Config currently stores mutable_dictionary: MutableDictionary, dialect: Dialect, ignored_lints: IgnoredLints, lint_config: FlatConfig, and integrations: Vec<Integration>.
  • Config::new() uses MutableDictionary::new(), Dialect::American, IgnoredLints::new(), FlatConfig::new_curated(), and curated default integrations.
  • Config is persisted under the system config directory in a harper-desktop folder. Main settings are serialized to config.json; the mutable dictionary is stored separately as dictionary.txt.
  • Config::load_from_system() loads the serialized config and then hydrates the mutable dictionary with the selected dialect.
  • The Tauri app owns shared config as Arc<Mutex<Config>>.
  • run_tauri() loads persisted config, creates HighlighterService, starts the highlighter service, and creates the tray/menu-bar UI.
  • The highlighter process is spawned through harper-desktop/src-tauri/src/highlighter_process.rs.
  • IPC is implemented under harper-desktop/src-tauri/src/communication/.
  • IPC uses newline-delimited JSON over child stdin/stdout.
  • The Tauri app is the protocol server.
  • The highlighter process is the protocol client.
  • Protocol messages live in harper-desktop/src-tauri/src/communication/message.rs.
  • Supported requests include GetLintConfig, GetDictionary, GetDialect, GetIgnoredLints, GetIntegrations, SetLintConfig, IgnoreLint, AddToDictionary, AddIntegration, RemoveIntegration, and SetIntegrationEnabled.
  • Supported responses include GetLintConfig, GetDictionary, GetDialect, GetIgnoredLints, GetIntegrations, and Ack.
  • IgnoredLints is transferred as whole serialized state and merged server-side.
  • AddToDictionary sends only the word; Rust appends it with DictWordMetadata::default().
  • The highlighter uses a Tokio current-thread runtime to call async IPC client methods from synchronous UI callbacks.
  • That runtime is bridge plumbing only; it is not used for linting or UI rendering.

Dictionary And Linting Gotchas

  • Keep dictionary construction centralized through Config::dictionary_from_user_dictionary(user_dictionary: MutableDictionary) -> Arc<MergedDictionary> and Config::create_dictionary().
  • Keep linter construction centralized through Config::create_linter().
  • The same merged dictionary source must be used for both Document::new_markdown_default(text, &dictionary) and LintGroup::new_curated(dictionary, dialect).
  • Do not use Document::new_markdown_default_curated(text) in the main highlighter lint callback when user dictionary words should suppress spelling lints.
  • Harper spelling lint behavior depends on document token metadata, so a linter with the updated dictionary is not enough if the Document was built with the curated dictionary only.
  • RenderState may still use curated document construction for localized source extraction where dictionary membership does not matter.

Frontend Integration

  • Tauri commands in harper-desktop/src-tauri/src/lib.rs include get_lint_config, get_dialect, set_dialect, set_lint_config, get_dictionary, set_dictionary, ignore_lint, add_to_dictionary, get_integrations, add_integration, remove_integration, and set_integration_enabled.
  • JS helper lives in harper-desktop/src/lib/client.ts.
  • JS helper class is named Client and exposes static methods for lint config, dialect, dictionary, ignored lints, dictionary additions, and integrations.
  • Client.ignoreLint(...) uses Harper JS ignored-lints export data and invokes the Rust command.
  • Client.addToDictionary(word) sends only the word to Rust.
  • Vite's dev server must stay on port 1420; harper-desktop/vite.config.js uses strictPort: true because Tauri expects that port.
  • Vite intentionally ignores src-tauri/** during frontend file watching.

Repo-Specific Gotchas

  • CI installs wasm-pack, tauri-cli, and cargo-hack with cargo binstall, then runs the relevant root just task.
  • Avoid mixing behavior fixes with structural refactors in the highlighter; popup/UI, IPC, dictionary behavior, config persistence, settings UI, and OS-coordinate fixes are easier to review separately.

Known Review Findings

  • Secondary-monitor highlighter coordinates may be wrong. Accessibility rectangles appear to be global screen coordinates, while each overlay window's egui origin is local to that monitor/window. Translate by monitor/window origin or render through one virtual-desktop-sized overlay.
  • macOS text range lookup may be wrong after emoji or other non-BMP characters. Harper spans are char-based, while macOS accessibility ranges are NSString/UTF-16 based. Convert spans before calling AXBoundsForRangeParameterizedAttribute.

On Writing New Rules

When asked to write a new rule, keep these guidelines in mind:

  • The user is almost always expecting you to write it to a file. Which file and where is up to you to find out.
  • You should include at least 15 total tests, covering a wide variety of cases. Cover false-positives, false negatives, true positives, and if relevant, true negatives.
  • You should run any and all tests to ensure that you do no break existing behavior and that your new rule runs the way you expect. At minimum, that means just test-rust. Make sure to check the snapshots for changes.
  • After adding a new rule, update harper-core/default_config.json so it is enabled in the curated default config.
  • Built-in Weir rules can be grouped by putting related .weir files in a directory under harper-core/src/linting/weir_rules; the directory name becomes the single public rule name.
  • If the rule is related to a closed compound noun, see if you can just add an entry to the existing closed compound linter.

Unless you are specifically requested to write the rule in a specific way, choose the language (Rust or Weir) and methodology that fits the task.

ALWAYS run extensive bullet tests with cargo run --bin harper-cli --release -- lint <TEXT> to make sure the new rule isn't already covered by Harper.

Workflow for Writing Weir Rules

  1. Draft the core expression
  • Encode the match with expr main using words, sequences, alternatives, filters, exceptions, POS tags, wildcards, or punctuation.
  • Keep the expression minimal but precise; avoid overmatching.
  • If a wordlist is needed, include it as its own expression, used with an expression reference.
  1. Add rule metadata
  • let message, let description, let kind, let becomes (and let strategy if needed).
  • Use strategy "Exact" when casing must be normalized; otherwise default behavior or MatchCase as appropriate.
  1. Add tests (required)
  • Include at least 15 tests.
  • Tests must cover: true positives, false positives, false negatives, and (if relevant) true negatives.
  • Prefer a mix of casing, punctuation, whitespace, and nearby-token variations.
  1. Sanity-check edge cases
  • Ensure exceptions do not block valid matches.
  • Ensure replacements are correct and not destructive.
  1. Run the tests.
  • Fix any issues that arise.

Output Format

Write a Weir rule to a new file with a name of your choosing, including expr main, let fields, and tests. Make sure it has the extension .weir.

Tips

Before finishing your turn, run just format or cargo fmt if you have made any changes. This can help diffs if a human decides to make a commit.

Try to write in a functional style. Minimize adding state whenever it is possible while also respecting the user's query. If additional state is necessary, please centralize it to increase visibility.

Download now (ZIP)

Trending

Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data

Week of Aug 30: 0 new projectsWeek of Sep 6: 0 new projectsWeek of Sep 13: 0 new projectsWeek of Sep 20: 0 new projectsWeek of Sep 27: 0 new projectsWeek of Oct 4: 0 new projectsWeek of Oct 11: 0 new projectsWeek of Oct 18: 0 new projects
Aug 2026Sep 2026Oct 2026
New projects taking a version of this file each week, over the 8 weeks our latest run read: only 0 in all, so this is a hint, not a trend.

Who's talking about Automattic/harper

The biggest 5 of 108 mentions linking to the repository that our crawl found. Each line is their own headline.

See all 108

Talked about on GitHub, Bluesky, YouTube, the web and Hacker News (108 times).

On GitHub · 50

45 more on GitHub

On Bluesky · 35

30 more on Bluesky

On YouTube · 16

11 more on YouTube

On the web · 5

On Hacker News · 2

  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 28,693 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.