Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "humanizer",
"description": "Rewrite AI-sounding text so it reads naturally without changing what it says.",
"version": "2.11.2",
"version": "2.12.0",
"author": {
"name": "blader",
"url": "https://github.com/blader"
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Keep the skill portable. Do not write instructions that limit it to one or two a

## Key files

- `SKILL.md` is the source of truth and the repo's only skill file. It contains portable YAML metadata, 35 numbered patterns, and their examples.
- `SKILL.md` is the source of truth and the repo's only skill file. It contains portable YAML metadata, 41 numbered patterns, and their examples.
- `README.md` explains installation, use, patterns, and version history.
- `.claude-plugin/plugin.json` describes the Claude plugin and points its skill loader at the root `SKILL.md`.
- `.claude-plugin/marketplace.json` lets users add this repo as a Claude marketplace.
Expand All @@ -20,7 +20,7 @@ Keep the skill portable. Do not write instructions that limit it to one or two a

Keep `SKILL.md` and `README.md` in sync.

- **Patterns:** The skill has 35 numbered patterns. If you add, remove, or renumber a pattern, update the README table, heading, validator, and every pattern reference.
- **Patterns:** The skill has 41 numbered patterns. If you add, remove, or renumber a pattern, update the README table, heading, validator, and every pattern reference.
- **Version:** Keep the same version in `SKILL.md` under `metadata.version`, the first README version entry, and `.claude-plugin/plugin.json`. Do not add a top-level `version` field to the skill.
- **Compatibility:** Keep install and use instructions neutral across agents. Names such as Claude Code, OpenCode, and Codex are examples, not limits.
- **History:** Add a short README version note for any behavior change or non-obvious fix.
Expand Down
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Humanizer rewrites AI-sounding text so it reads like a person wrote it, without

## How it works

Humanizer uses 35 patterns from Wikipedia's ["Signs of AI writing"](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing), maintained by WikiProject AI Cleanup. It makes a first pass without treating the original structure as fixed. Then it checks the draft against those patterns and the original claims before rewriting whatever still needs work.
Humanizer uses 41 patterns. The first 35 come from Wikipedia's ["Signs of AI writing"](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing), maintained by WikiProject AI Cleanup. Six discourse patterns come from [StoryScope](https://arxiv.org/abs/2604.03136), a 2026 study of how the shape of AI stories differs from human ones. It makes a first pass without treating the original structure as fixed. Then it checks the draft against those patterns and the original claims before rewriting whatever still needs work.

> "LLMs use statistical algorithms to guess what should come next. The result tends toward the most statistically likely result that applies to the widest variety of cases."

Expand Down Expand Up @@ -52,7 +52,7 @@ Now humanize this text:

Humanizer follows the sample's rhythm, word choice, punctuation, and deliberate quirks.

## The 35 patterns
## The 41 patterns

### Content patterns

Expand Down Expand Up @@ -114,6 +114,19 @@ Humanizer follows the sample's rhythm, word choice, punctuation, and deliberate
| 24 | **Too many qualifiers** | "could potentially possibly" | "may" |
| 25 | **Generic positive endings** | "The future looks bright" | End with a fact or a sourced plan |

### Discourse patterns

Measured on short fiction. Applying these to posts, emails, and docs extends the mechanism to formats the study did not test.

| # | Pattern | Before | After |
|---|---------|--------|-------|
| 36 | **A moral spelled out at the end** | "she finally understood that grief was..." | End on the events or a concrete action |
| 37 | **A portrait before the person acts** | "Marta was a tall woman in her fifties with..." | Let the character enter through action or speech |
| 38 | **Feelings shown only through the body** | "Her chest tightened. Her breath caught." | Suggest naming a feeling plainly |
| 39 | **Causality without seams** | "Because the letter arrived late, she missed..., which forced..." | Let one thing simply happen |
| 40 | **Chronology without jumps** | Earliest event first, step by step to the end | Consider opening mid-scene; keep procedures in order |
| 41 | **Never turning to the reader** | "The meeting ran long. The agenda had nine items." | Suggest one direct aside where the format allows it |

## Full example

*Details such as the month and neighborhood need to come from the writer. If they are missing, Humanizer should ask instead of making them up.*
Expand Down Expand Up @@ -146,14 +159,16 @@ Humanizer follows the sample's rhythm, word choice, punctuation, and deliberate

## Sources

- [Wikipedia: Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing) is the source for the pattern list.
- [Wikipedia: Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing) is the source for patterns 1-35.
- [WikiProject AI Cleanup](https://en.wikipedia.org/wiki/Wikipedia:WikiProject_AI_Cleanup) maintains the page.
- [StoryScope](https://arxiv.org/abs/2604.03136) (Russell et al., 2026) is the source for the discourse patterns.

## Version history

<details>
<summary>Show release notes</summary>

- **2.12.0** - Added discourse patterns #36-41 for story shape: stated morals, portrait introductions, body-only emotion, causal chains without seams, strict chronology, and missing reader address. Based on the StoryScope study of AI fiction. 41 patterns total.
- **2.11.2** - Removed the plugin symlink and separate Claude Desktop package. Current Claude Code loads the root `SKILL.md` directly, so GitHub's source ZIP now works in Claude Desktop. No change to the 35 patterns.
- **2.11.1** - Added a Claude Desktop-ready release package with one regular `humanizer/SKILL.md` file. GitHub's source archive still keeps the plugin symlink (fixes #224). No change to the 35 patterns.
- **2.11.0** - Rewrote all repo guidance, descriptions, checks, and skill instructions in Plain Language. Kept all 35 patterns and their behavior.
Expand Down
67 changes: 62 additions & 5 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ description: |
Rewrite AI-sounding text so it reads naturally without changing what it says.
Use when editing or reviewing prose for inflated claims,
sales language, vague sources, repetitive structure, stock AI words, passive
voice, filler, or chatbot artifacts. Based on Wikipedia's "Signs of AI writing."
voice, filler, or chatbot artifacts. Based on Wikipedia's "Signs of AI writing"
and the StoryScope study of AI fiction.
license: MIT
metadata:
version: "2.11.2"
version: "2.12.0"
---

# Humanizer: remove AI writing patterns

Rewrite AI-sounding text so it reads like the writer, not a chatbot. Do not change what it says or make up details.

The patterns below come from Wikipedia's ["Signs of AI writing"](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing), maintained by WikiProject AI Cleanup.
Patterns 1-35 come from Wikipedia's ["Signs of AI writing"](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing), maintained by WikiProject AI Cleanup. Patterns 36-41 come from [StoryScope](https://arxiv.org/abs/2604.03136), a 2026 study of how AI stories differ from human ones in shape rather than style.

## What to do

Expand Down Expand Up @@ -390,6 +391,60 @@ Remove only the unsupported defense. If it contains a real claim, state that cla

One rejected option may be valid. Several short, unrelated rejections are a stronger sign. Ask what new information each sentence adds. If it only records an earlier edit, rewrite the paragraph around its main point.

## Discourse patterns

The patterns above fix sentences. These six fix the shape of the whole piece, such as how a character enters or when the timeline breaks. They come from the [StoryScope](https://arxiv.org/abs/2604.03136) study of AI fiction, which found its narrative-feature classifier survives a style rewrite: after a full span-level rewrite of 278 AI stories, it still detected them at 93.9% macro-F1 versus 95.5% before, because the shape was untouched. These six are the shape gaps a rewrite can act on; the study measured many more.

One limit applies. The study measured short fiction, so treating essays, posts, and documentation the same way is a reasoned extension, not a tested result.

Apply these checks to narrative and personal prose. Leave reference and technical text alone. §38 and §41 name something the text lacks, so offer them to the writer instead of editing them in. In embedded mode there is no place to offer a suggestion, so skip 38 and 41 there.

### 36. A moral spelled out at the end

**Words to watch:** she finally understood that, the lesson was clear, in that moment he realized, it was never about the, what mattered all along
**Problem:** AI narrators state the story's theme outright. Human writers usually let the events carry it. Cut the stated lesson, or end on a concrete action instead.
**Before:**
> She looked at the empty chair and finally understood that grief was not something to escape but something to carry.
**After:**
> She looked at the empty chair, then set out two cups anyway.

### 37. A portrait before the person acts
**Problem:** AI writing introduces a character with a block of appearance and background before the character does anything. Let the person enter through action or speech, and move any needed description into the scene.
**Before:**
> Marta was a tall woman in her fifties with silver-streaked hair and sharp green eyes. She had run the library for twenty years and was known for her dry wit.
**After:**
> Marta stamped the book without looking up. "Third time you've lost this one."

### 38. Feelings shown only through the body

**Words to watch:** chest tightened, stomach dropped, breath caught, heart hammered, hands trembled
**Problem:** The body is the dominant emotional register in 81% of AI stories versus 38% of human ones; plain feeling words dominate in 8% versus 29%. When each emotion in a passage arrives as a body part, suggest naming one or two feelings plainly. This is a craft choice, so offer it instead of making the change yourself.
**Before:**
> Her chest tightened. Her breath caught as her stomach dropped.
**After:**
> She was afraid, and annoyed at herself for it. Her breath caught.

### 39. Causality without seams
**Problem:** AI causal chains run somewhat tighter than human ones (4.20 vs 3.92 on the study's 1-5 continuity scale). Human stories leave more room for coincidence and digression. Do not bridge every step. Let one thing simply happen.
**Before:**
> Because the letter arrived late, she missed the train, which forced her onto the bus, where she met the man who would change her life.
**After:**
> The letter arrived late and she missed the train. On the bus, a stranger took the seat next to her.

### 40. Chronology without jumps
**Problem:** AI jumps across time somewhat less than human writers (2.12 vs 2.40 on a 1-5 scale). In a longer narrative, consider opening mid-scene or letting a memory interrupt the timeline. Keep procedures, changelogs, minutes, and other sequential formats in order.
**Before:**
> Anna grew up in Ohio. She studied chemistry, moved to Boston, and took a lab job. Years later the lab closed.
**After:**
> The morning the lab closed, Anna thought about Ohio. She had come to Boston out of a chemistry program, straight into this job.

### 41. Never turning to the reader
**Problem:** Human writers address the reader directly far more often than AI does. Where the format allows an aside, one direct address can make the text sound like a person talking. Offer it to the writer instead of adding one yourself.
**Before:**
> The meeting ran long. The agenda had nine items.
**After:**
> The meeting ran long. You know how those go.

## Check for false positives

### What not to flag
Expand Down Expand Up @@ -449,8 +504,10 @@ These details often carry the writer's voice. Keep them unless they hurt the mea

Return the result required by [How to return the result](#how-to-return-the-result).

## Source
## Sources

This skill is based on [Wikipedia: Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing), maintained by WikiProject AI Cleanup. Its patterns come from reviews of AI-generated text on Wikipedia.
Patterns 1-35 are based on [Wikipedia: Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing), maintained by WikiProject AI Cleanup. They come from reviews of AI-generated text on Wikipedia.

Wikipedia's main point: "LLMs use statistical algorithms to guess what should come next. The result tends toward the most statistically likely result that applies to the widest variety of cases."

Patterns 36-41 are based on [StoryScope](https://arxiv.org/abs/2604.03136) (Russell et al., 2026), which measured 304 features across 61,608 human and LLM stories and found that narrative features alone separate human from AI writing at 93.2% macro-F1, within three points of a model that also uses style.
12 changes: 6 additions & 6 deletions scripts/validate-package.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,16 @@ def require_match(match: re.Match[str] | None, message: str) -> re.Match[str]:
int(number)
for number in re.findall(r"(?m)^### ([0-9]+)\. ", SKILL)
]
if pattern_numbers != list(range(1, 36)):
raise SystemExit(f"Number SKILL.md patterns from 1 through 35: {pattern_numbers}")
if pattern_numbers != list(range(1, 42)):
raise SystemExit(f"Number SKILL.md patterns from 1 through 41: {pattern_numbers}")

readme_numbers = {
int(number) for number in re.findall(r"(?m)^\| ([0-9]+) \|", README)
}
if readme_numbers != set(range(1, 36)):
raise SystemExit("List patterns 1 through 35 in the README table")
if readme_numbers != set(range(1, 42)):
raise SystemExit("List patterns 1 through 41 in the README table")

if len(SKILL.splitlines()) > 500:
raise SystemExit("Keep SKILL.md at 500 lines or fewer")
if len(SKILL.splitlines()) > 520:
raise SystemExit("Keep SKILL.md at 520 lines or fewer")

print(f"Humanizer package v{skill_version} is valid")