Chapter I
Preface
One AI tell survives every model jump: writers who all sound like the same writer. Pilcrow is a small toolkit for noticing it before you ship.
The deterministic engine catches 49 lexical and structural patterns. The phrasebank handles outright AI vocabulary (delve into, rich tapestry). The antithesis cadence catches the not just X, but Y rhythm. The copula dodge spots serves as and stands as standing in for plain is. The rest of the family covers em-dash density, throat-clearing openers, hero-tagline cadence, AI fossils like chat sign-offs and citation tokens, and the bullet-bold-lead markdown signature.
The LLM catalog adds 19 higher-level patterns regex can’t catch — buried lede, mixed metaphor, voice drift, missing stakes, marketing-template cadence, stakes inflation, listicle-in-prose — packaged as a single critique prompt you pipe into any model.
Credit to Paul Bakaus’s impeccable, which does the same job for frontend design. Same idea, applied to prose.
Detection-only. The engine never edits your text. Findings carry line, column, excerpt, and an optional suggestion; the LLM (or you) decides what to change.
Chapter II
Install
Two paths. Pick one.
Global (recommended)
npm install -g pilcrow-ink
The package on npm is pilcrow-ink; the binary it installs is pilcrow.
Per-project, no install
npx pilcrow-ink audit drafts/
npx pilcrow-ink skills install
Works from any project without touching node_modules.
Add the skill to your AI harness
Once iw is available, drop the skill into the right place for whichever harness you use:
cd your-project
pilcrow skills install # auto-detects .claude / .cursor / .gemini / .agents / etc.
pilcrow skills install --all # install into every supported provider
pilcrow skills update # re-sync after `npm update -g pilcrow-ink`
pilcrow skills check # show installed versions vs the package
Supported harnesses: Claude Code, Cursor, Gemini CLI, Codex / Agents, OpenCode, Kiro, Pi, Qoder, Trae, GitHub Copilot.
Chapter III
The CLI
Four commands.
pilcrow audit [paths...] # human-readable findings (default)
pilcrow lint [paths...] # JSON output for LLM consumption
pilcrow critique [path] # print the LLM-critique prompt
pilcrow rules [--json] # list every rule
If you pass no paths, the CLI reads stdin. If you pass a directory, it walks the tree and scans every .md, .mdx, .markdown, and .txt file. audit exits non-zero when an error-severity rule fires; lint exits the same way and prints JSON instead of pretty output.
A first run
$ echo "Let me delve into the rich tapestry of features." | pilcrow audit
<stdin> 3 findings
ERROR 1:8 ai-tell-phrasebank — "delve into" (≈ "delve into")
ERROR 1:23 ai-tell-phrasebank — "rich tapestry" (≈ "rich tapestry")
ERROR 1:28 ai-tell-phrasebank — "tapestry of" (≈ "tapestry of")
Each finding includes a short excerpt of the surrounding text and a one-line suggestion when the rule has one.
Piping to an LLM
The critique command emits a single prompt the model reads against the 19 higher-level rules. Pipe it into your model of choice:
pilcrow critique drafts/post.md | claude
pilcrow critique drafts/post.md | llm -m gpt-5
The expected JSON response shape is documented inside the prompt itself.
Chapter IV
Commands
Pilcrow exposes twenty-one commands grouped by what they do. The CLI ships audit, lint, critique, and rules today; the rest live in the skill and run inside an agent harness. All commands are detection-only at the deterministic layer; the LLM decides what to change.
Detect & report
| audit | run the deterministic catalog and report findings |
| critique | run the LLM pass against the higher-level catalog |
| polish | final pre-publish pass; surfaces both layers in one report |
One-axis edits
Each pushes the prose along a single dimension of the seven references.
| clarify | untangle unclear writing |
| tighten | line-edit-level cuts; reduce word count |
| pace | modulate sentence-length variation and rhythm |
| vivid | add concrete imagery and specificity |
| voice | adjust voice and register |
| lead | sharpen openings, leads, hooks |
| humanize | strip AI tells, restore an authentic cadence |
Direction modifiers
Push the prose somewhere on purpose.
| sharpen | make weak or timid prose decisive |
| soften | tone down strident or aggressive prose |
| distill | strip to essence; aggressive compression |
| harden | anticipate counterarguments; add caveats and evidence |
Flow
Multi-step orchestrations that carry context across phases.
| craft | full plan → draft → critique → revise → polish |
| shape | outline before drafting |
| live | generate variants of a passage side-by-side |
Context
| adapt | rewrite for a different audience or genre |
Bootstrap
One-time per-project setup.
| teach | interview the writer; write VOICE.md |
| document | infer VOICE.md from existing prose in the repo |
| extract | pull recurring phrases and patterns into a personal style guide |
Chapter V
What audit catches
Forty-nine deterministic rules, no LLM, no API key, milliseconds per file. They fall into eight families.
For the full catalog with every rule’s id, severity, and description, see The catalog.
| Family | Rules |
|---|---|
| AI phrasebank | ai-tell-phrasebank, overused-words, antithesis-cadence, throat-clearing-openers, cliche-closers, meta-discourse, copula-dodge |
| AI fossils | signoff-chatbot, sycophant-opener, disclaimer-tail, citation-artifact |
| Phrase | corporate-cliche, cliche-list, wordy-phrases, redundant-pairs, weasel-hedges, vague-quantifiers |
| Density | em-dash-density, adverb-density, nominalization-density, boosters, passive-voice, pronoun-density-low, parenthetical-aside-density, inline-bold-emphasis |
| Cadence | sentence-length-monotony, sentence-too-long, paragraph-monotony, parallel-triplet-density, transition-stacking, repeated-words-window, noun-stacking, anaphora-cadence, fragment-cadence, hero-tagline-imperative, from-x-to-y, present-participle-tail |
| Consistency | dash-style-inconsistency, quote-style-inconsistency, oxford-comma-inconsistency |
| Weak constructions | there-is-there-are, expletives, negation-of-negation, pronoun-it-vague |
| Markdown shape | bullet-bold-lead, title-case-headers, colon-headline, decorative-emoji, false-precision-headline |
The phrasebank carries the strongest AI tells (delve, tapestry of, navigate the landscape, plays a crucial role) at severity error. The single-word list (transformative, groundbreaking, seamless, foster, unleash, robust, …) sits at severity info because any one word can be defensible in context; the volume is the tell. The antithesis rule wants two or more matches in the document before it fires, since one instance is rhetoric and repetition is the fingerprint.
Density rules report only when a threshold is crossed: more than 1.5 em-dashes per 100 words, more than 5 unfortunate adverbs per 100, more than 8 nominalizations. Below that, prose breathes.
Run pilcrow rules to see every rule with its description and severity. Run pilcrow rules --json to get a machine-readable copy.
Chapter VI
What critique catches
Nineteen higher-level patterns regex can’t catch. These rules describe shapes of argument and rhetoric, not strings of characters. The engine ships them as a catalog plus a prompt builder; the model reads the prose against the catalog and returns structured JSON findings the CLI can consume.
| Rule | What it watches for |
|---|---|
| buried-lede | the real point doesn’t appear in the first paragraph |
| voice-consistency | register drifts across sections without narrative cause |
| mixed-metaphor | two incompatible images in one sentence |
| claim-without-support | a non-trivial claim with no evidence, reasoning, or example |
| missing-stakes | the reader can’t answer so what after reading |
| distinctive-vs-generic | could’ve been written by anyone (or any model) |
| abstract-without-concrete | extended theory with no grounding example or scene |
| showing-vs-telling | tells the reader what to feel instead of showing why |
| transition-coherence | paragraphs that don’t connect |
| register-mismatch | formal and casual jammed together without intent |
| excessive-balance | every claim earns a but or however |
| redundant-thesis | opening and closing repeat the same line |
| marketing-template-cadence | imperative-fragment-plus-tricolon hero rhythm, regardless of content specificity |
| sycophantic-tone | passage-level flattery of reader, prompt, or topic |
| stakes-inflation | civilizational stakes attached to small things |
| false-reframe | not X, it’s Y with no semantic content behind it |
| invented-concept-label | Capitalized Compound treated as established term without definition |
| listicle-disguise | numbered list flowed into parallel paragraphs as prose |
| one-point-dilution | single idea restated under five framings, no new argument |
Each rule in the catalog ships with a description, a positive example, and a negative example, all embedded directly in the prompt. The model returns JSON that the engine parses back into the same Finding shape the deterministic engine uses, so the two passes can be merged into one report.
Chapter VII
Fuzzy matching
Literal regex matches the wrong things. The phrasebank rules tokenize the prose, strip apostrophes, and stem each token before comparison. One phrase entry catches all the variants the model will produce in the wild.
| Phrase | Also catches |
|---|---|
delve into | delves, delving, delved, delve deeply into |
foster | fosters, fostering, fostered |
let’s dive in | Let’s dive in, lets dive in |
One inserted word is permitted between phrase tokens, so delve deeply into matches delve into. Apostrophes are stripped from both sides before matching, so Let’s matches lets.
For the complete list of phrases, words, and patterns the engine watches, see The catalog — auto-generated from the source on every deploy.