SkillAgentSearch skills...

Proselint

A linter for prose.

Install / Use

/learn @amperser/Proselint
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<img src="https://raw.githubusercontent.com/amperser/proselint/main/logo.png" alt="proselint logo" width="200">

Workflow status codecov License

Writing is notoriously hard, even for the best writers, and it's not for lack of good advice — a tremendous amount of knowledge about the craft is strewn across usage guides, dictionaries, technical manuals, essays, pamphlets, websites, and the hearts and minds of great authors and editors. But poring over Strunk & White hardly makes one a better writer — it turns you into neither Strunk nor White. And nobody has the capacity to apply all the advice from Garner’s Modern English Usage, an 1100-page usage guide, to everything they write. In fact, the whole notion that one becomes a better writer by reading advice on writing rests on untenable assumptions about learning and memory. The traditional formats of knowledge about writing are thus essentially inert, waiting to be transformed.

We devised a simple solution: proselint, a linter for English prose. A linter is a computer program that, akin to a spell checker, scans through a file and detects issues — like how a real lint roller helps you get unwanted lint off of your shirt.

proselint places the world's greatest writers and editors by your side, where they whisper suggestions on how to improve your prose. You’ll be guided by advice inspired by Bryan Garner, David Foster Wallace, Chuck Palahniuk, Steve Pinker, Mary Norris, Mark Twain, Elmore Leonard, George Orwell, Matthew Butterick, William Strunk, Elwyn White, Philip Corbett, Ernest Gowers, and the editorial staff of the world’s finest literary magazines and newspapers, among others. Our goal is to aggregate knowledge about best practices in writing and to make that knowledge immediately accessible to all authors in the form of a linter for prose; all in a neat command-line utility that you can integrate into other tools, scripts, and workflows.

Installation

To get this up and running, install it using pip.

pip install proselint

Fedora

sudo dnf install proselint

Debian

sudo apt install python3-proselint

Ubuntu

sudo add-apt-repository universe
sudo apt install python3-proselint

Nix

proselint is packaged by nixpkgs.

pre-commit

To use proselint with pre-commit (by Andy Airey), point its config at this repository:

repos:
  - repo: https://github.com/amperser/proselint
    rev: v0.16.0
    hooks:
      - id: proselint

Be sure to change rev to use the desired proselint git tag or revision.

Declarative

environment.systemPackages = [pkgs.proselint];

Imperative

nix profile install nixpkgs#proselint

Plugins for other software

proselint is available on:

The following plugins are also available, but they are archived or unmaintained:

Usage

Suppose you have a document text.md with the following text:

John is very unique.

You can run proselint over the document using the command line:

proselint check text.md

This prints a list of suggestions to stdout, one per line. Each suggestion is of the form:

file:<line>:<column>: <check_name>: <message>

For example,

text.md:1:9: uncomparables: Comparison of an uncomparable: 'very unique' is not comparable.

The command-line utility can also print suggestions in JSON using the --output-format json option. In this case, the output is considerably richer, following our stable wire schema.

{
  "result": {
    "file:///path/to/text.md": {
      "diagnostics": [
        {
          // Name of the check that output this suggestion.
          "check_path": "uncomparables",
          // Message to describe the suggestion
          "message": "Comparison of an uncomparable: 'very unique' is not comparable.",
          // Line and column where the error begins in the source
          "pos": [1, 9],
          // Absolute start and end of the error in the source
          "span": [9, 20],
          // Suggested replacements for the content, if applicable
          "replacements": null,
        }
      ]
    }
  }
}

To run the linter as part of another Python program, you can use the LintFile class in proselint.tools. This requires CheckRegistry to be populated.

from proselint.checks import __register__
from proselint.registry import CheckRegistry
from proselint.tools import LintFile

CheckRegistry().register_many(__register__)
suggestions = LintFile("source-name", "This sentence is very unique").lint()

This will return a list of suggestions:

[LintResult(
    check_result=CheckResult(
        check_path='uncomparables',
        message="Comparison of an uncomparable: 'very unique' is not comparable.",
        span=(18, 29),
        replacements=None,
    ),
    pos=(1, 18),
)]

Checks

You can disable any of the checks by modifying $XDG_CONFIG_HOME/proselint/config.json. If $XDG_CONFIG_HOME is not set or empty, ~/.config/proselint/config.json will be used. Check selection is granular at any level, illustrated in the following example:

{
  "checks": {
    "typography": true,
    "typography.symbols": false,
    "typography.symbols.curly_quotes": true,
    "typography.punctuation.hyperbole": false,
  }
}

This configuration would enable all checks in the typography module, excluding typography.punctuation.hyperbole and those in typography.symbols, but preserving typography.symbols.curly_quotes. Using this system allows you to concisely and precisely select checks at an individual level.

| ID | Description | | ----- | --------------- | | annotations | Catch annotations left in the text | | archaism | Avoid archaic forms | | cliches.hell | Avoid a common cliché regarding hell | | cliches.misc | Avoid clichés | | dates_times.am_pm | Format the time of day correctly | | dates_times.dates | Format dates appropriately | | hedging | Avoid undermining yourself with uncertainty | | industrial_language.airlinese | Avoid jargon of the airline industry | | industrial_language.bureaucratese | Avoid bureaucratese | | industrial_language.chatspeak | Avoid lolling and other chatspeak | | industrial_language.commercialese | Avoid jargon of the commercial world | | industrial_language.corporate_speak | Avoid corporate buzzwords | | industrial_language.jargon | Avoid miscellaneous jargon | | lexical_illusions | Avoid repeating words or phrases | | malapropisms | Avoid common malapropisms | | misc.apologizing | Be confident and avoid excessive apologizing | | misc.back_formations | Avoid redundant backformations | | misc.but | Do not start a paragraph with "But..." | | misc.capitalization | Capitalize only what ought to be capitalized | | misc.composition | Adhere to principles of composition | | misc.currency | Avoid redundant currency symbols | | misc.debased | Avoid debased language | | misc.false_plurals | Avoid false plurals | | misc.greylist | Avoid greylisted terms | | misc.illogic | Avoid illogical forms | | misc.inferior_superior | Superior to, not than | | misc.institution_name | Use the correct names of institutions | | misc.latin | Avoid overuse of Latin phrases | | misc.many_a | Use singular forms with "many a" | | `misc.metadiscour

Related Skills

View on GitHub
GitHub Stars4.5k
CategoryDevelopment
Updated16m ago
Forks180

Languages

JavaScript

Security Score

95/100

Audited on Mar 29, 2026

No findings