A local detector for AI-writing patterns. Scores every prose file your agent saves. Python standard library only, no network, no model.
# Add to your Claude Code skills
git clone https://github.com/seyedehsanhadi/sloptrimsloptrim is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by seyedehsanhadi. A local detector for AI-writing patterns. Scores every prose file your agent saves. Python standard library only, no network, no model. It has 50 GitHub stars.
sloptrim's catalog security scan is still queued. You can run an instant dependency and prompt-injection check now with the "Scan for vulnerabilities" button above.
Clone the repository with "git clone https://github.com/seyedehsanhadi/sloptrim" and add it to your Claude Code skills directory (see the Installation section above). sloptrim ships a SKILL.md manifest, so compatible agents can discover and load it automatically.
sloptrim is primarily written in Python. It is open-source under seyedehsanhadi on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh sloptrim against similar tools.
No comments yet. Be the first to share your thoughts!
Unlocks once the catalog security scan passes (runs nightly).
The deep catalog scan for this skill is still queued. Run an instant dependency check now instead.
Trims AI slop from text. Works a catalogue of 71 patterns: 62 machine-checked by scripts/detect.py, 9 requiring semantic judgment during the rewrite. Of the 62, 50 can move the score; the rest are reported as writing advice and count for nothing. Mode-aware so it does not invent voice on factual content. Preserves facts. Rebuilds the cleaned text toward a selectable human-voice style profile so it does not read as a sterile de-AI'd husk.
This skill never talks about itself. It hands back the cleaned text and nothing else.
Never emit: any announcement that sloptrim ran, style/mode lines, scores or reports, drafts, self-audit notes, facts-preserved lines, change lists, preambles, closing offers.
Emit only:
Every internal step still runs - detector, tiering, self-audit, character scrub. Silence means nothing is printed, not that anything is skipped.
Break silence only for: (a) a fact you cannot preserve, or an unusual word you cannot verify against the domain - one line, then the text; (b) the user explicitly asking for the score, the report, a style choice, or a diff - then answer in full; (c) a high-stakes first-person deliverable - a cover letter, personal statement, or bio the user is about to send - where after the text you may add exactly one line offering a voice switch (for example: "Voice here is plain-professional; say the word for warmer or more formal."). One line, only for these high-stakes cases, never for routine prose.
Never ask. Read the content and pick:
If the user names a style or pastes a writing sample, that wins (see Matching the user's own voice).
scripts/detect.py and tier the pass to _metrics.ai_tell_score: clean (≤20) - character scrub and flagged spans only, do NOT rewrite (a human-first draft keeps its voice); light tells (21-40) - targeted edits plus rhythm repair; mixed and above - full rewrite toward the style profile.references/patterns.md when you need the precise Before/After examples for any pattern.python "$DETECT" on the draft; ask what still reads as AI, and whether it over-flattened (length_cv < 0.35, uniform paragraphs, readability_uniform true, contractions gone in drastic mode - a flat husk reads as machine-made just as fast as slop). Fix only the offending spans; cap at two loops; accept at clean/light tells and not over-flattened. Check the other direction in the same pass: count the words. Past 1.25x the input you have written new material, and no score justifies keeping it.python "$DETECT" on the final text and confirm invisible_chars, nonstandard_spaces, and homoglyphs are 0 (#62/#66/#67/#68 silent). Drafts from other models can carry zero-width or TAG-block characters that survive copy-paste; python "$DETECT" --clean strips them, normalizes spaces, folds homoglyphs, and trims stray whitespace without touching visible content.Removing AI tells is only half the job. The other half is rebuilding the text toward a voice a person would actually write in. Pick one from the content, silently (see Style, chosen silently). Each profile is a positive target - it does not change which AI tells are removed or the preservation rules; it sets the rhythm, register, punctuation, and paragraph shape the cleaned prose is rebuilt into.
1. 2000s textbook (default) - pre-LLM human academic prose (a well-edited textbook, roughly 2000-2008). Clear declarative sentences, one idea each; real length variation (a short statement, a longer development, a worked example - never metronomic); concrete examples introduced naturally; occasional first-person-plural for exposition, never first-person-singular opinion; semicolons and parentheses where a writer would use them, em-dash sparing. Forbidden: hype adjectives, signposting, hedge stacks, rule-of-three, "In today's world" openers, upbeat conclusions, emoji, bold-for-emphasis. Neutral and patient; explains, does not sell. Conservative mode.
2. Plain / clear (Zinsser) - tight modern nonfiction. Short words over long, cut every clutter phrase, concrete nouns and active verbs, one thought per sentence. Good for docs, READMEs, business prose. Conservative unless source is first-person.
3. Conversational essay - first-person, contractions, asides, real rhythm; reacts to facts rather than only reporting them; lets some mess in (tangents, half-formed thoughts). Implies drastic mode. Only for content that already carries a personal voice - never forced onto encyclopedic text.
4. Journalistic / news - AP style: short lede carrying the key fact first, inverted pyramid, attributed claims ("according to…"), plain verbs, no editorializing. Conservative.
If the user names a profile, rewrite toward it. Otherwise infer it per Style, chosen silently.
When the user provides a writing sample (inline or a file path), take the target voice from it instead of a profile: measure its sentence lengths and their variation, formality, paragraph openers, punctuation habits, recurring phrases - then rebuild the cleaned text with those habits. No sample: fall back to Content type and voice below.
The biggest failure mode is injecting authorial voice into content that has none by design. A Wikipedia article does not get to say "I keep coming back to..." Classify first:
Encyclopedic / factual - third-person, dense with proper nouns, dates, statistics, citations, technical vocabulary (Wikipedia, science, news, docs, specs). → Conservative mode. Remove AI patterns, vary rhythm, keep tone neutral. Do not add first-person stance, opinions, or asides. Keep formal contractions (it is, do not) as-is.
Opinion / first-person - already uses "I" or "we"; expresses stance; has takes and asides (essays, posts, reviews). → Drastic mode. Remove AI patterns AND add voice. Contract where natural (it's, don't, you've).
Mixed or unclear → default to conservative.
Classification signals: first-person markers above ~2 % of words → opinion. Proper-noun density above ~5 %, numbers / dates / citations present → encyclopedic. Imperative voice → conservative (technical).
Take positions - respond to facts instead of only stating them. Let rhythm move irregularly: a blunt sentence, then one that unwinds at its own pace; the enemy is a metronome in either direction. Acknowledge complexity, use "I" where it fits, and leave the small irregularities a person would - a digression, a parenthetical, an idea carried only as far as it needs to go. Be specific about feelings rather than generic.
Must survive every rewrite: numbers and units (0.19, 1989, 340 kg/m³, 55 %), proper nouns, hyphenated technical terms (thin-walled, load-bearing, strength-to-weight), citations, domain vocabulary.
Safe to paraphrase: hedges (typically, generally), generic passive verbs (results from, consists of), abstract property nouns when the domain term is also present, filler adverbs. Paraphrasing a hedge keeps the qualification and changes the wording; deleting the last one turns a qualified claim into an absolute one and is covered below.
Never invent: dates, statistics, quotes, named individuals, citations to sources not in the input. If specifics are missing, stay vague - do not supply plausible-sounding facts.
Never change what a statement asserts, who it belongs to, or how much of it there is. These are the failures that survive an entity check, because no number or name moves; every one was found in a real rewrite. Do not:
The bike weighs 23.2 lb is the writer's observation. Claimed weight is 23.2 lb attributes it to the manufacturer and is a different sentence. Never add claimed, reportedly, said to be or allegedly to something stated plainly, and never remove them from something attributed.there is the risk of over-diagnosis becomes an assertion that over-diagnosis happens if risk of is cut. Hedge stacking is pattern 54 and gets fixed by removing one hedge, never the last one.its small size makes it more of a deterrent than real theft prevention is a complaint. Reading it as the reason the lock works reverses the writer's judgment.30-hour battery life is not 30 hours of noise cancellation. Keep every figure attached to the thing it measured, especially in headings, subject lines and captions, where a reader sees it alone.[Name], {{first_name}} and [Your Company] are merge fields belonging to whatever system will fill them. Leave the token exactly as written, or leave the document alone.Domain-correctness check: every unusual word (≥ 7 letters, uncommon) in the rewrite must fit the surrounding domain vocabulary. Real-but-wrong words ("infantilization" appearing near vacuum-pressure / polymer terms) are harder to catch than typos and worse for credibility.
Character layer (§62, §66, §67, §68 in references/patterns.md): remove invisible and zero-width characters, normalize non-standard spaces to U+0020, trim stray trailing whitespace, fold mixed-script homoglyphs to ASCII (genuine non-Latin words untouched). Never strip legitimate \t / \n / \r inside the body. scripts/detect.py --clean applies all four deterministically.
Each pattern has a full Before / After in references/patterns.md (read it for the precise phrasing list when working a pattern). The numbering groups patterns by function; it folds the community-documented signs together with this project's additions rather than ordering them by origin.
--clean) - character layerWhen working on a specific pattern, read references/patterns.md and jump to the matching section for the exact phrasing list and Before / After.
Resolve the detector path first - scripts/detect.py is bundled in the skill directory, not the user's project, so a bare relative path will not resolve. Set DETECT once: as a plugin, $CLAUDE_PLUGIN_ROOT/scripts/detect.py; as a cloned skill, Glob **/sloptrim/scripts/detect.py (usually ~/.claude/skills/sloptrim/scripts/detect.py). Then run it before manual review:
python "$DETECT" input.txt # pass a path (works on all shells)
It emits JSON: pattern IDs with counts and samples, a _metrics block (rhythm statistics, contraction and passive ratios, character-layer counts), and ai_tell_score (0-100) with a band (clean / light tells / mixed / heavy tells / pervasive tells). The score weighs pattern diversity over raw density, floors when the character layer finds codepoints that carry no meaning in the text, and ignores copy-editing preferences. It is a triage heuristic, not a calibrated classifier.
A score describes the writing in front of it. It is not a judgement about who or what wrote a document, it cannot support one, and it must never be used to accuse a person of anything. See ETHICS.md. The 9 catalogue entries with no detector behind them (7, 9, 28, 29, 43, 45, 49, 52, 53) are worked by reading; even machine-checked ones deserve a reading pass for what the regex misses.
For the deterministic character layer, --clean emits the scrubbed text instead of JSON - it strips the invisible and non-printing codepoints, normalizes non-standard spaces to U+0020, folds mixed-script homoglyph letters back to ASCII (#66), and trims stray whitespace, leaving visible content untouched:
python "$DETECT" --clean gemini_nano_output.txt > clean.txt
Run it on any draft produced by another model to remove smuggled zero-width or TAG-block characters before the text ships.
Removing AI patterns is half the job; fill the space with patterns a person writes: active specific verbs (runs between, locks into - not serves as, provides); a short pivot sentence every 3-4 sentences that reframes the next idea; em-dash for contrast at most once per paragraph; the colon as an explanation hinge; concrete subjects ("Wind turbine blades rely on balsa" beats "Balsa is used in turbines"); specific judgments ("unusually high stiffness"); a final sentence that carries weight - a fact or real observation, never a generic positive close; varied paragraph length, one-sentence paragraphs allowed.
The catalogue folds publicly documented signs of AI writing with newer model-specific tells; all worked examples in references/patterns.md are original, and the lexical layer (#1) is the refresh point as model vocabularies shift. Scope is rewriting, not detection; defeating institutional integrity systems is out of scope. Version 0.9.0.
A local detector for AI-writing patterns. It scores every prose file your agent saves and asks for the flagged spans to be fixed. Python standard library only, no network, no model. Prose only, never code.
Install · What it does · Measured · Limits · Patterns · Ethics
[!IMPORTANT] This is a command-line tool and an agent plugin. There is no website and no hosted version. Nothing you write is uploaded, there is no account, and no text ever leaves your machine. Any site offering a service under this name is unrelated to this project.
Paste into Claude Code, Codex, Cursor, or any coding agent:
Install the sloptrim plugin from https://github.com/seyedehsanhadi/sloptrim
Restart, then run /sloptrim doctor. It answers with four [OK] lines.
/plugin marketplace add seyedehsanhadi/sloptrim
/plugin install sloptrim@sloptrim
git clone https://github.com/seyedehsanhadi/sloptrim.git ~/.claude/skills/sloptrim
mkdir -p ~/.claude/commands
cp ~/.claude/skills/sloptrim/install/sloptrim-command.md ~/.claude/commands/sloptrim.md
Do not skip the mkdir. On a fresh machine ~/.claude/commands does not exist yet
and the copy fails with "No such file or directory". In PowerShell the last two lines
are New-Item -ItemType Directory -Force $HOME/.claude/commands and Copy-Item.
The copy puts /sloptrim in the / menu, because Claude Code does not scan a skill
folder's own commands/. A marketplace install needs no such step. Either way the
router also answers to /sloptrim:sloptrim.
The score is 0-100 against 71 documented patterns. 62 of them have a detector; the other 9 need a reading and are worked during the rewrite. Of the 62, 50 can move the score and 12 are reported as writing advice and count for nothing: most of them because measurement showed they mark formal register rather than machine authorship, the rest because they are typographic habits.
| Formats | 20, including .docx, .pptx, .xlsx, OpenDocument, .epub, .ipynb, LaTeX |
| Runs in | Claude Code, on save. Other agents via /sloptrim init, which writes the contract to AGENTS.md, and .cursor/rules/ |
| Needs | Node for the hooks, Python 3.9 or newer for the detector, nothing else |
| Suite | 97 Python tests and 53 hook checks, green in CI on Linux, Windows and macOS, against Python 3.9 and 3.13 |
| Does not see | A file written by a Bash command, which reaches disk without passing Write or Edit |
| Command | Effect |
|---|---|
/sloptrim full |
Contract + guard (default) |
/sloptrim strict |
Flags at 20 instead of 40, and asks for a character scrub |
/sloptrim lite / off |
Contract only / nothing |
/sloptrim check <file> |
Score a file, name the tells, no rewrite |
/sloptrim init |
Write the contract to ./AGENTS.md and a Cursor rule to ./.cursor/rules/ |
/sloptrim doctor |
Diagnose the install |
python scripts/detect.py draft.docx # JSON: patterns, metrics, 0-100 score
A score lands in one of five bands: clean, light tells, mixed, heavy tells,
pervasive tells. The guard nudges above 40, or above 20 in strict mode.
The figures below were measured against corpora held privately. Neither those corpora nor the harness that read them is in this repository, and nothing here recomputes any of it. They are cited as results, with the corpus named, and cannot be re-derived from what you have cloned.
False positives on human prose, at the default threshold, worst corpus first:
| corpus | n | rate |
|---|---|---|
| American textbooks, 30 titles | 9,333 | 0.85% |
| MAGE human web text | 504 | 0.40% |
| PubMed abstracts, pre-2020 | 529 | 0.00% |
| arXiv abstracts, pre-2021 | 939 | 0.00% |
Detection, ROC-AUC per corpus. The worst one is the headline:
It cannot tell you whether a current frontier model wrote something. The machine arms above come from GPT-2, GPT-J, OPT, FLAN-T5, MPT, Mistral, Mixtral, GPT-3.5 and GPT-4, nothing newer. A run against a current frontier model measured ROC-AUC 0.551, close to a coin flip.
The writing contract has no measured effect. Twenty documents drafted twice from one brief with the switch toggled, both arms verified from the transcripts: mean change +2.25, bootstrap 95% CI -5.65 to +9.90, sign test p = 0.27. Its banned-word list works; nothing else in it does. That is 20 pairs against the 40 the protocol asks for, so the question is unresolved rather than settled.
It is not an authorship classifier and must not be used as one. A score says something about writing, never about a person. Read ETHICS.md.
Apache-2.0 (full text, NOTICE). Cite with CITATION.cff.