Anti-Slop Writing Skills: Unslop, miodkuj, and What the Evals Say
Unslop is an agent skill that strips the patterns making prose read as machine-written, backed by three deterministic Python scanners rather than a model’s judgement alone. It ships four commands, a catalogue of 16 literal phrase triggers and 36 structural patterns, and, unusually for the genre, an eval suite whose latest public result its own author records as a no-ship.
Every team shipping AI-assisted writing eventually meets the same review comment: “this reads like ChatGPT.” Nobody can point at the sentence that did it. The reviewer is reacting to a shape, not a word: an opener clearing its throat, three examples where two would have done, a moralising last paragraph. That shape survives every round of “make it sound more natural,” because the model rewriting it has the same defaults as the model that wrote it.
What an anti-slop skill actually buys you
Section titled “What an anti-slop skill actually buys you”- A vocabulary for the review comment you keep leaving: not “this feels off” but “negative parallelism, three in one section, and a moralising coda.”
- Detection you can run in CI without an agent at all — unslop’s scanners are standard-library Python that exit non-zero on a flag.
- An audit mode that reports and changes nothing, which is the mode you actually want the first ten times.
- A defensible answer to the em-dash argument, including when to ignore the rule.
- For Polish, a rule set that is not a translated English word list, because the tells are structurally different.
What unslop does to a draft
Section titled “What unslop does to a draft”Unslop splits the problem along one axis, and the split is the design. Detection is cheap, deterministic and benchmarkable, so it carries the trust. Voice work is generative, so it runs underneath: as the README puts it, “any mimic or rewrite that reintroduces a tell fails, however well it matches the voice.”
Four commands cover the surface:
| Command | What it does |
|---|---|
rewrite | The default. Diagnoses a draft, reconstructs it under the guards, validates the result. |
cleanup | Co-writer mode: reviewable suggestions with span, severity, category and rationale. Includes a report-only variant that changes nothing. |
teach | Builds a reusable voice profile from your own writing samples. |
mimic | Drafts or rewrites in a taught voice, then clears the full removal-gate battery. |
A bare /unslop <text> with no command word defaults to rewrite. Phrases route too: “just flag it” lands in cleanup report-only, “does this sound like me?” lands in the voice check.
The part worth stealing even if you never install it is cleanup’s four contract gates, which are what make an “accept all” button safe by construction rather than by hope. Span-minimality means an edit changes only its own span, so a whole-sentence rewrite fails the gate. Replacement-scanner means each proposed replacement passes both scanners in isolation and adds no new violation in context. Accept-all means applying every suggestion yields a document that still passes and still preserves every constraint against the original. Span-overlap means two suggestions may not fight over the same characters.
Three scanners, and why they are Python instead of prompt
Section titled “Three scanners, and why they are Python instead of prompt”Detection stacks three deterministic passes, coarse to fine. Each returns JSON, exits non-zero on a flag, and carries false-positive protection rows so a literal use never trips it.
-
Phrase layer (
banned_phrase_scan.py) — 16 literal triggers, each with contextual false-positive protection. Gated words fire only in their jargon collocations. Quoted spans, blockquotes and code fences are masked before scanning, so a tutorial documenting bad writing does not flag its own examples. -
Structure layer (
structure_scan.py) — 36 structural patterns plus document-level metrics with names that tell you what is being measured:sentence_burstiness,paragraph_cv,triad_density,one_line_staccato_share,connective_paragraph_openers,signpost_density,conclusion_coda,summary_sandwich. This is the layer that catches rhythm: uniform sentence length, staccato runs, every paragraph opening on “However,” or “Moreover,” and the bold-label listicle standing in for prose. -
Silhouette layer (
silhouette_scan.py) — scores how the ideas are arranged, a level above the surface. It catches outline-following and recap loops: body paragraphs opening on a discourse cue instead of their own claim (scaffold_opener_share), opening vocabulary that vanishes mid-document and returns at the end (callback_content, which the repo calls the strongest single tell), and section headings that restate the intro’s outline (heading_preview).
On the corpus committed to the repo, the silhouette layer separates cleanly: 12 of 12 AI documents flagged, 0 of 8 human documents flagged. The honest caveat is in the README too — a cue-deletion attack collapses the scaffold metric, which is why silhouette is scored jointly with the structure scanner rather than trusted alone.
Because the scanners are plain Python 3.8+ with no third-party dependencies, they run without the skill and without an agent:
python3 scripts/banned_phrase_scan.py < input.txtpython3 scripts/structure_scan.py --genre docs < README.mdpython3 scripts/silhouette_scan.py < input.txtpython3 scripts/validate_preservation.py original.txt transformed.txtThat is the version to put in a pre-publish hook. The agent is for judgement calls; the scanner is for the ones that do not need judgement.
Why a 50 KB rule catalogue costs almost no context
Section titled “Why a 50 KB rule catalogue costs almost no context”Unslop’s phrase catalogue is a 50 KB markdown file. Its eval runner is bigger. A skill that loaded all of that on every session would be indefensible, and it does not, because of how the Agent Skills format works.
Loading happens in three stages. The name and description from the frontmatter sit in the system prompt at all times, at roughly 100 tokens per skill. The SKILL.md body loads only when the skill triggers, and is meant to stay under about 5k tokens. Everything else (references/, presets/, scripts/) loads only when something reaches for it, and scripts run through bash, so only their output enters context, never their source.
So the catalogue costs nothing until a rewrite actually needs a rule, and the eval suite costs nothing ever, unless you are contributing to the project. This is the architectural fact that makes a skill of this size reasonable, and it is worth internalising before you write one of your own: the budget is the description, not the repository.
What the catalogue actually bans
Section titled “What the catalogue actually bans”Every family is pinned by an eval row, and every entry carries a severity — hard (always a tell) or soft (a default register guard your real voice may override).
| Family | Caught examples |
|---|---|
| Throat-clearing openers | “Here’s the thing:”, “The uncomfortable truth is”, “Let me be clear”, “It turns out”, “Let’s dive in” |
| Emphasis crutches | “Full stop.”, “Let that sink in.”, “Make no mistake”, “Read that again.”, “This cannot be overstated.” |
| Negative parallelism | “It’s not X, it’s Y”, “Not only… but also”, “Not merely X, but Y”, “No X, no Y, just Z” |
| Significance inflation | “stands as a testament to”, “pivotal moment”, “enduring legacy”, “rich tapestry”, “cornerstone of” |
| False agency | “the numbers speak for themselves”, “the data tells a story”, “paints a clear picture” |
| Wh-opener self-Q&A | “Why does this matter? Because…”, “What does this mean for…”, “Why should you care?” |
| Vague attribution | “Experts argue”, “Studies show”, “Some critics” — attributed and possessive forms stay clean |
| Business-jargon collocations | “navigate challenges”, “leverage synergies”, “deep dive”, “circle back”, “move the needle” |
| Chatbot residue | “I hope this helps”, “Certainly!”, “Great question!”, “as an AI language model” |
| Reasoning-chain leaks | “Let me think step by step”, “Breaking this down”, “Here’s my thought process” |
Single words are graded rather than banned outright: delve, tapestry, underscore and load-bearing are hard; myriad and plethora are soft. The gated ones carry exemptions — load-bearing is a hard flag as a metaphor and explicitly exempt in “literal construction and mechanics.”
On punctuation the catalogue is blunt, and it is the rule people argue about:
Em-dashes are the single most reliable AI punctuation tell. […] Rule: Default to zero em-dashes. If one is absolutely necessary for rhythm and a comma or period genuinely won’t work, allow one per several paragraphs at most. Two or more in any paragraph is always wrong.
How a new rule gets in
Section titled “How a new rule gets in”The maintenance loop is the most transferable thing in the repo, and the worked example in the README is a good one. The maintainer caught the phrase “Four presets, one input.” on his own marketing page — a standalone header in slogan cadence. Precheck said the catalogue did not cover it, which is what made it worth adding.
The eval row landed red first, before any fix existed:
{ "id": "OWNER-01", "stdin": "Four presets, one input.", "assertions": [ { "type": "json", "path": "total_violations", "gte": 1 }, { "type": "violation_category_equals", "value": "slogan_fragment" } ]}Then the pattern was written to turn it green, anchored to line boundaries on purpose — standalone headline position is the tell, not the “N X, one Y” shape by itself. A protection row proves “The unit has two bedrooms, one bath, and a den.” stays clean, because the same words mid-sentence never reach a line boundary.
That is the whole discipline: a new pattern ships only once a false-negative row fails without it and a false-positive row proves the literal sense survives. Detection catalogues decay as the generators change, so the growth path has to be adversarial refresh rather than a one-time word list.
What unslop refuses to touch
Section titled “What unslop refuses to touch”Do-no-harm is half the product, and it is the half that decides whether you can leave the thing switched on.
- Register guards. “never store secrets”, “may cause drowsiness”, “does not establish causation” are content, not filler. In legal, medical, security and scientific text those hedges and absolutes carry meaning, and
validate_preservation.py --strictturns dropping one into a hard failure. - Literal domain usage. Construction, mechanics, law, medicine, finance, sailing and code all use the gated words literally, and every contextual pattern ships with a row proving it.
- Quoted examples. Quotes, blockquotes and code fences are exempt by default, so documentation never flags the bad writing it is teaching. (This article would otherwise be one enormous violation.)
- Facts, with magnitude awareness. Numbers, names, dates, units and references like
Section 12(b)survive a rewrite, and the check is magnitude-aware:$47.3Mcannot silently become$47.3 billion. - Genre carve-outs.
--genre docsallows the bold-label lists reference documentation really uses;--genre socialallows the short-line cadence that belongs in social copy. - English only. Non-English input gets cheap detection and a clear decline; the scanners return
non_english: trueand stop. That refusal is the reason the next section of this article exists.
Installing unslop in Cursor, Claude Code, or Codex
Section titled “Installing unslop in Cursor, Claude Code, or Codex”Unslop follows the Agent Skills open standard, so the install is the same skills CLI used everywhere else in this section.
npx skills add theclaymethod/unslop -g -a cursorGlobal skills land in ~/.cursor/skills/; project-scoped ones go to .agents/skills/<name>/SKILL.md, the shared open-standard directory Cursor reads. There is no slash command — describe what you want (“audit this draft for AI tells, change nothing”) and the description triggers it.
npx skills add theclaymethod/unslop -g -a claude-codeThis writes ~/.claude/skills/unslop/. The skill sets user-invocable: true and an argument-hint, so it appears as /unslop with its four sub-commands: /unslop cleanup, /unslop rewrite, /unslop teach, /unslop mimic.
If you would rather track the repo directly:
git clone https://github.com/theclaymethod/unslop.git ~/dev/unslopln -s ~/dev/unslop ~/.claude/skills/unslopnpx skills add theclaymethod/unslop -g -a codexInstalls to .agents/skills/<name>/SKILL.md, which Codex scans from the working directory up to the repo root. Codex loads the body only when it decides to use the skill, so an installed skill costs almost nothing until it is relevant.
One command covers several agents at once, which is the usual case if you write in more than one place:
npx skills add theclaymethod/unslop -g -a claude-code -a cursor -a codexWhy unslop publishes a failing grade
Section titled “Why unslop publishes a failing grade”This is the part of the project that has no equivalent anywhere else in the genre.
Most skills in this genre ship a rule list and a claim. Unslop ships three separate scoreboards and refuses to let one flatter the others: core product (detection, repair, preservation, damage, net improvement), voice (teach and mimic fidelity), and engineering (scanner coverage, schemas, routing, caching, regressions). The README is explicit about why they are separated: “The engineering suite can show that the implementation behaves as specified. Only the core scoreboard can show that the specification improves writing.”
The core comparison is paired and model-controlled. The same gpt-5.6-luna gets the same unfamiliar source in both arms; one arm runs the frozen unslop pipeline, the other gets neutral editorial guidance with no repository access, no scanner output and no validation feedback. A blinded gpt-5.6-sol judge sees randomised arm labels.
And the latest valid public result of that comparison is a no-ship. Unslop materially improved recall and repair over plain Luna, but missed the precision, damage and whole-document safety bar. Later development runs were directionally better, with seven wins, four ties and no losses, but they predate scorer fixes, and a fresh preregistered corpus failed its composition floor before either arm ran, so the project states plainly that the current beta “does not claim a validated comparative lift.”
Set that against the field. The most-starred skill in this category, blader/humanizer, carries more than 36,500 stars and no eval suite at all. Stars rather than installs, to be precise about it: the counts throughout this article come from the GitHub API, which is the one measure available for every project here. Unslop has more than two orders of magnitude fewer, and a benchmark that says its author’s own product is not ready. If you are choosing between them on evidence rather than popularity, that asymmetry is the finding — and the honest reading is that nobody in this genre has yet demonstrated that automated de-slopping improves a document overall. One project is simply measuring.
The measurement pays off elsewhere too. Running GEPA over the command surface collapsed seven redundant phases into one canonical command, which cut warmed model calls from 48 to 24, command tokens from 19 to 3, and deterministic orchestration time from about 6.25 seconds to about 3.02 seconds, with the required gates intact. You only find a 2x saving like that if you were measuring in the first place.
miodkuj: the same problem in a language the catalogues do not cover
Section titled “miodkuj: the same problem in a language the catalogues do not cover”Unslop stops at non-English input and says so. That is the correct behaviour and it leaves a real hole, because Polish AI slop is not English AI slop with different words in it.
Miodkuj fills it. Its one-line promise is “Polszczyzna bez sztucznego tonu”, Polish without the artificial tone, and it goes after three things at once: AI slop, bureaucratic register, and calques from English. Its own summary of the research position is the important part: miodkuj does not translate English banned-word lists, it adapts anti-slop patterns to Polish.
The name is a coined verb, roughly “to Miodek a text,” after Professor Jan Miodek, the linguist who has been Poland’s public authority on correct usage for decades. The README carries the disclaimer you would want: the name is a linguistic homage, and Professor Miodek neither participates in nor endorses the project.
The patterns an English list cannot reach
Section titled “The patterns an English list cannot reach”Some families overlap with unslop’s — chatbot residue (jako model językowy, oto poprawiona wersja), throat-clearing (warto zauważyć, w dzisiejszych czasach), inflated importance (kluczowy, przełomowy, holistyczny). The interesting half has no English counterpart at all, because it comes from the officialese register that dominates Polish institutional writing:
| Family | Before | After |
|---|---|---|
| Officialese | w dniu dzisiejszym | dzisiaj |
| Officialese | dokonać zakupu | kupić |
| Officialese | posiadać możliwość | może |
| Nominalisation | przeprowadzenie analizy danych | zespół przeanalizował dane |
| Impersonal fog | należy złożyć wniosek | złóż wniosek |
| Genitive chain | w przypadku braku możliwości uruchomienia pojazdu | jeśli nie możesz uruchomić pojazdu |
The genitive-chain row is the one that shows why a translated list would fail. Polish can stack four nouns in the genitive and stay grammatical while becoming unreadable; English has no such construction, so no English catalogue has a rule for it. The same goes for participial heaviness (mając na uwadze, biorąc pod uwagę, uwzględniając) and for nominalisation as a morphological signal — miodkuj literally watches the -anie, -enie, -cie endings.
Every family carries an explicit false-positive guard, and the file opens by telling the agent how to read it: “Use these as cluster-sensitive signals. Most items are not absolute bans.”
The three rules that do the work
Section titled “The three rules that do the work”Strip out the watchlists and miodkuj is three ideas.
Minimum effective edit. “If the source already passes the quality gate, return it unchanged; do not replace correct wording merely to show an edit.” This is the instruction most rewriting tools lack, and its absence is why they churn good prose.
The Specificity Ladder. When a generic claim needs grounding, use a fact already present in the source; failing that, recombine what is there without increasing certainty; failing that, make the claim smaller or delete it. The rule underneath is stated flatly: never invent a number, example, customer, source, mechanism or comparison to make prose sound human, because “a plausible inference is still new information.” Removing a slogan does not license replacing it with an invented explanation.
The Portability Test. “If a sentence could move unchanged to another company, ministry, product, project, or person, it is probably filler.” One sentence, and it catches more marketing copy than any word list. It comes with its own guard: do not apply it mechanically to definitions, legal formulas, standard warnings, or necessary procedural language.
There is also a register layer that a general-purpose humaniser would flatten. Legal and official text must keep the obligated party, the legal force and the formal register; academic text keeps its hedging and its valid passive forms; technical documentation keeps its terms and code. Audit mode is explicitly forbidden from claiming AI authorship: “Do not infer AI authorship from stylistic patterns. Describe the writing that is present.”
Why miodkuj ships no scanner
Section titled “Why miodkuj ships no scanner”Unslop’s whole trust argument is determinism. Miodkuj deliberately declines it, and says why in its research summary:
Nie dodajemy deterministycznego lintera do rdzenia. Taki linter pomaga przy pracy wsadowej, lecz sama lista dopasowań nie rozstrzyga kontekstu i nie chroni głosu autora.
We are not adding a deterministic linter to the core. Such a linter helps with batch work, but a list of matches on its own does not resolve context and does not protect the author’s voice.
Both positions are defensible because they optimise different failure modes. Unslop’s scanners give you a gate you can put in CI and a number you can benchmark, at the cost of needing a false-positive protection row for every pattern to stop the gate mangling literal usage. Miodkuj’s context-first approach cannot be a CI gate and cannot be benchmarked the same way, but it never has to be told that niniejszy is correct in a statute.
If your Polish text is institutional, legal or academic, the second bet is the right one. If you are gating a documentation pipeline in English, the first is.
Installing miodkuj
Section titled “Installing miodkuj”Miodkuj ships as one skill file used on every platform, which is why its frontmatter is spec-minimal — just name and description, no Claude Code-only fields. That is what lets the identical file upload to ChatGPT and Claude.ai as well as installing as a plugin.
/plugin marketplace add bartekpucek/miodkuj/plugin install miodkuj@miodkuj/reload-pluginsInvoke it as /miodkuj:miodkuj. Claude Code namespaces a plugin’s skills with the plugin name, so this route does not give you a short /miodkuj. If you want that, copy the skill directory in by hand instead:
miodkuj_tmp="$(mktemp -d)"git clone --depth 1 https://github.com/bartekpucek/miodkuj.git "$miodkuj_tmp"mkdir -p ~/.claude/skillscp -R "$miodkuj_tmp/plugins/miodkuj/skills/miodkuj" ~/.claude/skills/miodkujrm -rf "$miodkuj_tmp"codex plugin marketplace add bartekpucek/miodkujcodex plugin add miodkuj@miodkujStart a new task and invoke it with $miodkuj. Codex will also select it on its own when your request matches the skill description, which is written bilingually for exactly that reason.
There is no packaged Cursor install. The skill is a standard SKILL.md directory, so copy it into the shared open-standard path Cursor reads:
miodkuj_tmp="$(mktemp -d)"git clone --depth 1 https://github.com/bartekpucek/miodkuj.git "$miodkuj_tmp"mkdir -p .agents/skillscp -R "$miodkuj_tmp/plugins/miodkuj/skills/miodkuj" .agents/skills/miodkujrm -rf "$miodkuj_tmp"For ChatGPT and Claude.ai, download miodkuj.skill from the repository’s latest release and upload it under Skills instead.
The rest of the anti-slop field
Section titled “The rest of the anti-slop field”The genre is crowded and the star counts are not a quality signal. Verified on 19 August 2026:
| Skill | Stars | Shape | How it differs |
|---|---|---|---|
blader/humanizer | 36,531 | Skill + Claude plugin + Codex manifest | The default choice. Ports Wikipedia’s signs-of-AI-writing into numbered patterns with before/after pairs. No scanners, no evals. |
hardikpandya/stop-slop | 15,877 | One SKILL.md + 3 reference files | The earliest of the big ones. Deliberately tiny: 8 core rules, 12 quick checks, 1–10 scoring on five dimensions. Unslop credits it by name in its own catalogue. |
petergyang/no-ai-slop | 5,366 | Skill + Codex plugin | Edit and detect modes, minimum-effective-edit, a portability test. Philosophically the closest thing to miodkuj in English — which is presumably why miodkuj lists it as a source. |
theclaymethod/unslop | 77 | Skill + 20 Python scanners + eval suite | The only one with deterministic scanners you can run in CI and a published core benchmark. |
bartekpucek/miodkuj | 68 | Skill + plugin manifests for four platforms | The only serious Polish one. Register-aware, deliberately linter-free. |
Two absences matter here. Anthropic ships no anti-slop or writing-style skill — the official anthropics/skills repository contains nineteen skills, and the nearest neighbours are doc-coauthoring and internal-comms, neither of which addresses AI tells. Nor does obra/superpowers, whose fourteen skills are all development-process skills; its writing-skills is about authoring skills, not prose.
The real upstream for all of them is Wikipedia’s Signs of AI writing, maintained by WikiProject AI Cleanup. It is the most thorough catalogue in existence, it tracks vocabulary by era (the “delve / tapestry / testament” cohort belongs to 2023–2024; “align with, enhance, fostering, showcasing” to 2024–2025), and it is free. Unslop is the only skill here that syncs from it programmatically — scripts/wiki_sync.py check diffs the catalogue against the live page and proposes updates, eval-row-first.
If you want detection without an agent in the loop at all, Vale rule packs exist too (JMill/deslop, t0ddharris/slopster), though both are early and neither approaches the coverage of unslop’s scanners.
Where these skills fight you
Section titled “Where these skills fight you”The em-dash rule will fight your house style, and sometimes it should lose. This site’s own style guide uses em dashes deliberately; a zero-default would strip a working part of the register. Unslop actually handles this correctly rather than dogmatically — the whole soft severity tier exists so that “your real voice can override” the default register guard, and voice preferences that contradict a measured default surface as a named conflict rather than being resolved silently. What it will not let you do is override a hard rule quietly. Decide once, write it into the top of your skill file, and move on.
Hard bans land on legitimate technical prose. load-bearing and wedge are both hard flags as metaphors. If you write about architecture, both words appear in their ordinary engineering senses regularly. The catalogue exempts literal construction and mechanics use, but “this assumption is load-bearing” in a design document is exactly the metaphorical sense the rule targets, and it is also exactly the right phrase. Expect to argue with it.
Neither project has proven it improves documents. Unslop says so in its own README. The others have not measured. Treat all of them as tools for finding candidates, not as a quality gate you can hand a merge decision to.
Check the license before you vendor unslop. The README says “Licensed MIT” and SKILL.md declares license: MIT, but there is no LICENSE file in the repository, and GitHub’s API reports no detected license. That is almost certainly an oversight rather than a trap, but if you are pulling the scanners into a commercial pipeline, open an issue and get it fixed first.
Both are small and moving. Neither has cleared a hundred stars, unslop’s core contract was rewritten a fortnight ago, and miodkuj is eleven weeks old. That is fine for a skill you read and adapt. It is not a dependency you pin a publishing pipeline to without vendoring.
And the deepest one, which Wikipedia states better than anyone: its guidance asks editors to “not merely treat these signs as the problems to be fixed; that could just make detection harder.” Optimising prose against a tell list is not the same as writing well. A draft that passes every scanner can still be an outline with no argument in it, three examples that all make the same point, and a conclusion that restates the introduction. The scanners cannot see that. You can.
Use them the way you would use a linter: to catch the mechanical errors so your attention is free for the ones that matter.