Local AI text humanizer for Spanish & English, built on controlled experiments: a base model without chat training rewrites, a fidelity guard keeps every concept and quote, the rhythm is rebuilt, and flagged paragraphs are re-sampled and selected. 0% in Grammarly, ZeroGPT and GPTZero. No API · Humanizador IA local.
Python
4
18 commits
updated Oct 8, 2026
English · Español

humanizar-es takes a text written with ChatGPT, Claude, Gemini or DeepSeek and gives it back saying the same thing, in prose that the three detectors we measured read as human: 0% in Grammarly, 0% in ZeroGPT and 0% AI / 98% human in GPTZero, on the same 1,990-word essay that started at 45%. It runs on your own computer with an open model: no API, no keys, no per-word fees, and your text never leaves your machine. Use it by hand or as a skill for your coding agent (Claude Code, Codex, OpenCode, Antigravity).
It is not a synonym spinner, a "rewrite it in a human tone" prompt, or a typo generator. It is a four-stage pipeline, and every stage exists because a controlled experiment showed what a detector actually measures: one variable at a time, the same text in every condition, and a human-written control and the AI original in every session.
| AI-generated essay | Grammarly | ZeroGPT | GPTZero |
|---|---|---|---|
| Aristotle: act and potency · 1,990 words · before | 45% | 45.3% | 37% AI |
| Aristotle: act and potency · after | 0% and 0% | 0% | 0% AI · 98% human |
| Tourism and AI in Chiapas · 1,150 words | 77% → 0% | — | — |
| An AI classification model · 690 words | → 0% | — | — |
| Dragon Ball and its generation · 910 words | 84% → 10% | — | — |
| 🇬🇧 Remote work (English) · 601 words | — | 100% → 0% | — |
| 🇬🇧 Electric vehicles (English) · 673 words | — | 100% → 0% | — |
October 2026. The first essay keeps 24 of 24 key names, terms and figures, and its two quotations of Aristotle word for word. Grammarly reads ~1,400 words, so it was measured in halves. The Dragon Ball essay ran on an earlier version of the pipeline.
original ─► 1. rewrite ──► 2. fidelity ──► 3. rhythm ──► 4. selection ──► final
base model concepts, blocks of candidates,
without chat quotes, copy, uneven measured in the
training ≤3-word fixes length whole document
Three detectors, three different signals. The pipeline exists because each one was taken apart with experiments:
| Detector | What it reacts to | What does not move it |
|---|---|---|
| GPTZero | the fingerprint of chat training; its newer English model (4.1o) also reads base-model text, our next milestone | — |
| Grammarly | rhythm: sentences of even length, each closed by its own period | double spaces (typos do move it, but leave visible errors) |
| ZeroGPT | individual sentences that read like a textbook; it scores sentence by sentence and weighs by words | joining sentences of a human text (Unamuno joined: 0%) |
Xu et al. (2026), Base Models Look Human To AI Detectors,
showed that text from a base model scores 97–99% human on GPTZero and Pangram, and the
same model after chat training 17–30%. Our tests agree: every rewrite we tried with a chat
model stayed between 64% and 100% in Grammarly. rewrite.py paraphrases with
Qwen3-4B-Base plus the paper's HIP adapter, through llama.cpp, on your CPU.
Each paragraph gets one pass, and a try is rejected and retried when it:
check.py then compares concepts and negations, and a person fixes one to three words
at most. Anything bigger is regenerated by the model (--only), never written by hand and
never pasted back from the original: hand fixes of four or more words kept half an essay
at 3% in Grammarly; regenerating those paragraphs brought it to 0%.
People write in bursts, some sentences long, some short. join.py --pauses 2 leaves two or
three periods per paragraph, in blocks of uneven length of at least two sentences,
cutting first where a sentence already opens with a discourse marker («Sin embargo»,
"For example", «Segundo»). Inside a block it links with "and" or ";". No content word is
touched.
The base model is a sampler: the same paragraph comes out differently every time, and a
detector can score two samples 0% and 100%. So the paragraphs a detector still flags are
regenerated several times (--candidates), each candidate is joined and measured inside
the whole document (context changes the score), and the one that passes is adopted
(--take). All candidates come from the same base model, so selection adds no chat
fingerprint. Two findings made this work:
--lead "Desde la") fixed it:
22 candidates of one paragraph with the original opening scored 100%; with another
opening, 0%.Same essay, one change at a time.
| Grammarly | |
|---|---|
| Rewritten by the base model only | 84% |
| … plus random double spaces | 84% |
| … removing ~35% of the commas | 60% |
| … joining ~60% of the sentences | 40% |
| … joining every sentence of each paragraph | 8% |
| The original, without the base model, joining every sentence | 57% |
| Rewriting with a chat model (four different recipes) | 64–100% |
| Pauses, with a sentence left alone between two periods | 6% |
| Pauses, blocks of two or more sentences | 0% and 0% |
| ZeroGPT (deterministic: the same text always gives the same score) | |
|---|---|
| The AI original | 34.3% |
| Rewritten by the base model, sentences unjoined | 33.9% |
| … all sentences joined | 44.0% |
| … with pauses | 52.4% |
| A human text (Unamuno, 1914), joined the same way | 0% |
| After selection: candidates measured in the whole document | 0% |
The tension is real: Grammarly wants long sentences, ZeroGPT punishes a long sentence that
contains one textbook clause. Rhythm alone cannot satisfy both; rhythm plus selection does.
Every measurement: references/evidence.md.
git clone https://github.com/ervin-mo/humanizar-es.git
cd humanizar-es
python3 install.py # on Windows: python install.py
Open a new session and ask: "humanize this text" (or «humaniza este texto»). The skill walks the agent through every stage: install what's missing (it asks before downloading the model), list with you what must not be lost, rewrite, show you every change, rebuild the rhythm, and select candidates for whatever your detector still flags.
| Agent | Skills folder | Covered by install.py? |
|---|---|---|
| Claude Code | ~/.claude/skills | yes |
| Codex | ~/.agents/skills | yes |
| OpenCode | ~/.agents/skills, ~/.claude/skills | yes |
Antigravity (agy) | ~/.agents/skills | yes |
DeepSeek Harness (dsh) | ~/.agents/skills | yes |
| Gemini CLI | ~/.gemini/skills | with --agent gemini |
You need Python 3.9+ (no extra packages) and llama.cpp:
| macOS and Linux | Windows | |
|---|---|---|
| llama.cpp | brew install llama.cpp | winget install llama.cpp |
| The model | python3 scripts/install_model.py | python scripts\install_model.py |
The installer checks every file against its sha256 and resumes if the download is cut. It runs on CPU: 8 GB of free RAM is enough, no GPU. On an M4 Mac it takes about 30–60 seconds per paragraph; on a few-years-old PC, 1 to 3 minutes.
On Windows, type python where it says python3.
1. List what must not be lost in concepts.txt: full proper names, figures, terms.
One per line, variants with |, * for prefixes.
Aristotle
act and potency | act and potentiality
self-regulat*
2. Rewrite with the base model:
python3 scripts/rewrite.py my-text.txt -o rewritten.txt --concepts concepts.txt
3. Check, and fix one to three words at most. For anything bigger, regenerate that paragraph:
python3 scripts/check.py my-text.txt rewritten.txt --concepts concepts.txt
python3 scripts/rewrite.py my-text.txt -o rewritten.txt --concepts concepts.txt --only 6,11
Don't ask ChatGPT to fix it: it puts back the fingerprint the base model removed.
4. Rebuild the rhythm (the language is detected automatically):
python3 scripts/join.py rewritten.txt -o final.txt --concepts concepts.txt --pauses 2
5. Measure the final text in your detector, in the format you will hand in, with a
human text as control (references/detectors.md).
6. Select, for what is still flagged. Generate candidates of those paragraphs, with other opening words if the paragraph starts with a stock phrase:
python3 scripts/rewrite.py my-text.txt -o rewritten.txt --concepts concepts.txt \
--only 4 --candidates 6 --lead "Desde la" --temperature 1.1
Join each candidate into the full text, measure, adopt the one that passes, and join again:
python3 scripts/rewrite.py my-text.txt -o rewritten.txt --take 4=rewritten.txt.candidates/p04-3.txt
python3 scripts/join.py rewritten.txt -o final.txt --concepts concepts.txt --pauses 2
Reread the adopted paragraph against the original: passing a detector is worth nothing if it dropped an idea.
Worked examples, with every hand fix listed, are in examples/.
| Rewrite | Rhythm | Check | Measured | |
|---|---|---|---|---|
| Español | ✅ | ✅ «y», «;», «pero»… | ✅ | ✅ four essays, three detectors |
| English | ✅ (the HIP adapter was trained in English) | ✅ "and", ";", "but"… | ✅ | ✅ ZeroGPT, two essays · GPTZero: next milestone |
Other languages: the rewrite may work (the base model is multilingual), but join.py
only knows Spanish and English connectors. Adding one is a small dictionary in
scripts/join.py; pull requests welcome.
| Detector | Status |
|---|---|
| Grammarly | ✅ 0% on three of four essays (10% on one run with an older version) |
| GPTZero | ✅ 0% AI · 98% human (Spanish) · English: next milestone (what we tried) |
| ZeroGPT | ✅ 0% in Spanish and English, with stage 4 (selection) where needed |
| QuillBot | not usable in Spanish: it scored the AI original 100% human |
Each detector runs its own model, so a version that passes one may not pass another; the first essay passes all three at once. Measurements on more detectors and more kinds of text are the contribution we need most.
Is it free? Do I need an OpenAI key or any account? Free and keyless. The model downloads once and runs on your computer.
Does it change what my text says?
It is built not to: tries that lose a concept, change a quote or invent a reference are
rejected, check.py compares concepts and negations, and you reread every paragraph.
Does it add typos on purpose, like other "humanizers"? No. It changes who wrote the sentences and their rhythm, not the spelling.
Are the results consistent? Three of four essays reached 0% in Grammarly, and the latest one passes Grammarly, GPTZero and ZeroGPT at once. The pieces that can be deterministic are (the joining is seeded; ZeroGPT gives the same score for the same text), output that copies the original is refused, and 48 tests run on every change on Ubuntu, macOS and Windows. Detectors drift over time, which is why every session carries controls.
Does the selection step send my text anywhere? The tool never does. Measuring is your step, in your detector, as with any text you check.
Do I need a GPU? No. It runs on CPU, at low priority, so your computer stays usable.
Made for text you sign and answer for: brand content, outreach, documentation, emails, drafts written with AI help. Don't use it to hand in graded work as your own where AI is banned or must be disclosed. That problem isn't technical; it's academic honesty.
humanizar-es/
├── SKILL.md the skill for agents
├── install.py installs the skill (install.sh: shortcut for macOS/Linux)
├── scripts/
│ ├── install_model.py downloads the model (once)
│ ├── rewrite.py stages 1, 2 and 4: rewrite, guard fidelity, candidates
│ ├── check.py stage 2: concepts and negations, original vs rewrite
│ └── join.py stage 3: rebuild the rhythm of each paragraph
├── examples/ worked examples in Spanish and English
├── references/ every measurement, and how to measure
└── tests/ 48 tests on Ubuntu, macOS and Windows (no network, no model)
The old script names (hip.py, unir.py, verificar_fidelidad.py, instalar_hip.py)
still work.
What's missing most is evidence: the pipeline measured on more texts, more languages
and more detectors, always with a human control and the AI original. Open an issue or a
PR with the numbers in references/evidence.md.
python3 -m unittest discover -s tests -v
Code and docs: MIT, © ervin-mo. The HIP method and adapter are by Xu et al.
(2026); the base model is Alibaba's Qwen3-4B-Base. Both are Apache-2.0 and downloaded
separately: see THIRD_PARTY.md. If you use this in your work, cite the
repo (CITATION.cff) and the HIP paper.
Local AI text humanizer for Spanish & English, built on controlled experiments: a base model without chat training rewrites, a fidelity guard keeps every concept and quote, the rhythm is rebuilt, and flagged paragraphs are re-sampled and selected. 0% in Grammarly, ZeroGPT and GPTZero. No API · Humanizador IA local.
Python
4
18 commits
updated Oct 8, 2026
English · Español

humanizar-es takes a text written with ChatGPT, Claude, Gemini or DeepSeek and gives it back saying the same thing, in prose that the three detectors we measured read as human: 0% in Grammarly, 0% in ZeroGPT and 0% AI / 98% human in GPTZero, on the same 1,990-word essay that started at 45%. It runs on your own computer with an open model: no API, no keys, no per-word fees, and your text never leaves your machine. Use it by hand or as a skill for your coding agent (Claude Code, Codex, OpenCode, Antigravity).
It is not a synonym spinner, a "rewrite it in a human tone" prompt, or a typo generator. It is a four-stage pipeline, and every stage exists because a controlled experiment showed what a detector actually measures: one variable at a time, the same text in every condition, and a human-written control and the AI original in every session.
| AI-generated essay | Grammarly | ZeroGPT | GPTZero |
|---|---|---|---|
| Aristotle: act and potency · 1,990 words · before | 45% | 45.3% | 37% AI |
| Aristotle: act and potency · after | 0% and 0% | 0% | 0% AI · 98% human |
| Tourism and AI in Chiapas · 1,150 words | 77% → 0% | — | — |
| An AI classification model · 690 words | → 0% | — | — |
| Dragon Ball and its generation · 910 words | 84% → 10% | — | — |
| 🇬🇧 Remote work (English) · 601 words | — | 100% → 0% | — |
| 🇬🇧 Electric vehicles (English) · 673 words | — | 100% → 0% | — |
October 2026. The first essay keeps 24 of 24 key names, terms and figures, and its two quotations of Aristotle word for word. Grammarly reads ~1,400 words, so it was measured in halves. The Dragon Ball essay ran on an earlier version of the pipeline.
original ─► 1. rewrite ──► 2. fidelity ──► 3. rhythm ──► 4. selection ──► final
base model concepts, blocks of candidates,
without chat quotes, copy, uneven measured in the
training ≤3-word fixes length whole document
Three detectors, three different signals. The pipeline exists because each one was taken apart with experiments:
| Detector | What it reacts to | What does not move it |
|---|---|---|
| GPTZero | the fingerprint of chat training; its newer English model (4.1o) also reads base-model text, our next milestone | — |
| Grammarly | rhythm: sentences of even length, each closed by its own period | double spaces (typos do move it, but leave visible errors) |
| ZeroGPT | individual sentences that read like a textbook; it scores sentence by sentence and weighs by words | joining sentences of a human text (Unamuno joined: 0%) |
Xu et al. (2026), Base Models Look Human To AI Detectors,
showed that text from a base model scores 97–99% human on GPTZero and Pangram, and the
same model after chat training 17–30%. Our tests agree: every rewrite we tried with a chat
model stayed between 64% and 100% in Grammarly. rewrite.py paraphrases with
Qwen3-4B-Base plus the paper's HIP adapter, through llama.cpp, on your CPU.
Each paragraph gets one pass, and a try is rejected and retried when it:
check.py then compares concepts and negations, and a person fixes one to three words
at most. Anything bigger is regenerated by the model (--only), never written by hand and
never pasted back from the original: hand fixes of four or more words kept half an essay
at 3% in Grammarly; regenerating those paragraphs brought it to 0%.
People write in bursts, some sentences long, some short. join.py --pauses 2 leaves two or
three periods per paragraph, in blocks of uneven length of at least two sentences,
cutting first where a sentence already opens with a discourse marker («Sin embargo»,
"For example", «Segundo»). Inside a block it links with "and" or ";". No content word is
touched.
The base model is a sampler: the same paragraph comes out differently every time, and a
detector can score two samples 0% and 100%. So the paragraphs a detector still flags are
regenerated several times (--candidates), each candidate is joined and measured inside
the whole document (context changes the score), and the one that passes is adopted
(--take). All candidates come from the same base model, so selection adds no chat
fingerprint. Two findings made this work:
--lead "Desde la") fixed it:
22 candidates of one paragraph with the original opening scored 100%; with another
opening, 0%.Same essay, one change at a time.
| Grammarly | |
|---|---|
| Rewritten by the base model only | 84% |
| … plus random double spaces | 84% |
| … removing ~35% of the commas | 60% |
| … joining ~60% of the sentences | 40% |
| … joining every sentence of each paragraph | 8% |
| The original, without the base model, joining every sentence | 57% |
| Rewriting with a chat model (four different recipes) | 64–100% |
| Pauses, with a sentence left alone between two periods | 6% |
| Pauses, blocks of two or more sentences | 0% and 0% |
| ZeroGPT (deterministic: the same text always gives the same score) | |
|---|---|
| The AI original | 34.3% |
| Rewritten by the base model, sentences unjoined | 33.9% |
| … all sentences joined | 44.0% |
| … with pauses | 52.4% |
| A human text (Unamuno, 1914), joined the same way | 0% |
| After selection: candidates measured in the whole document | 0% |
The tension is real: Grammarly wants long sentences, ZeroGPT punishes a long sentence that
contains one textbook clause. Rhythm alone cannot satisfy both; rhythm plus selection does.
Every measurement: references/evidence.md.
git clone https://github.com/ervin-mo/humanizar-es.git
cd humanizar-es
python3 install.py # on Windows: python install.py
Open a new session and ask: "humanize this text" (or «humaniza este texto»). The skill walks the agent through every stage: install what's missing (it asks before downloading the model), list with you what must not be lost, rewrite, show you every change, rebuild the rhythm, and select candidates for whatever your detector still flags.
| Agent | Skills folder | Covered by install.py? |
|---|---|---|
| Claude Code | ~/.claude/skills | yes |
| Codex | ~/.agents/skills | yes |
| OpenCode | ~/.agents/skills, ~/.claude/skills | yes |
Antigravity (agy) | ~/.agents/skills | yes |
DeepSeek Harness (dsh) | ~/.agents/skills | yes |
| Gemini CLI | ~/.gemini/skills | with --agent gemini |
You need Python 3.9+ (no extra packages) and llama.cpp:
| macOS and Linux | Windows | |
|---|---|---|
| llama.cpp | brew install llama.cpp | winget install llama.cpp |
| The model | python3 scripts/install_model.py | python scripts\install_model.py |
The installer checks every file against its sha256 and resumes if the download is cut. It runs on CPU: 8 GB of free RAM is enough, no GPU. On an M4 Mac it takes about 30–60 seconds per paragraph; on a few-years-old PC, 1 to 3 minutes.
On Windows, type python where it says python3.
1. List what must not be lost in concepts.txt: full proper names, figures, terms.
One per line, variants with |, * for prefixes.
Aristotle
act and potency | act and potentiality
self-regulat*
2. Rewrite with the base model:
python3 scripts/rewrite.py my-text.txt -o rewritten.txt --concepts concepts.txt
3. Check, and fix one to three words at most. For anything bigger, regenerate that paragraph:
python3 scripts/check.py my-text.txt rewritten.txt --concepts concepts.txt
python3 scripts/rewrite.py my-text.txt -o rewritten.txt --concepts concepts.txt --only 6,11
Don't ask ChatGPT to fix it: it puts back the fingerprint the base model removed.
4. Rebuild the rhythm (the language is detected automatically):
python3 scripts/join.py rewritten.txt -o final.txt --concepts concepts.txt --pauses 2
5. Measure the final text in your detector, in the format you will hand in, with a
human text as control (references/detectors.md).
6. Select, for what is still flagged. Generate candidates of those paragraphs, with other opening words if the paragraph starts with a stock phrase:
python3 scripts/rewrite.py my-text.txt -o rewritten.txt --concepts concepts.txt \
--only 4 --candidates 6 --lead "Desde la" --temperature 1.1
Join each candidate into the full text, measure, adopt the one that passes, and join again:
python3 scripts/rewrite.py my-text.txt -o rewritten.txt --take 4=rewritten.txt.candidates/p04-3.txt
python3 scripts/join.py rewritten.txt -o final.txt --concepts concepts.txt --pauses 2
Reread the adopted paragraph against the original: passing a detector is worth nothing if it dropped an idea.
Worked examples, with every hand fix listed, are in examples/.
| Rewrite | Rhythm | Check | Measured | |
|---|---|---|---|---|
| Español | ✅ | ✅ «y», «;», «pero»… | ✅ | ✅ four essays, three detectors |
| English | ✅ (the HIP adapter was trained in English) | ✅ "and", ";", "but"… | ✅ | ✅ ZeroGPT, two essays · GPTZero: next milestone |
Other languages: the rewrite may work (the base model is multilingual), but join.py
only knows Spanish and English connectors. Adding one is a small dictionary in
scripts/join.py; pull requests welcome.
| Detector | Status |
|---|---|
| Grammarly | ✅ 0% on three of four essays (10% on one run with an older version) |
| GPTZero | ✅ 0% AI · 98% human (Spanish) · English: next milestone (what we tried) |
| ZeroGPT | ✅ 0% in Spanish and English, with stage 4 (selection) where needed |
| QuillBot | not usable in Spanish: it scored the AI original 100% human |
Each detector runs its own model, so a version that passes one may not pass another; the first essay passes all three at once. Measurements on more detectors and more kinds of text are the contribution we need most.
Is it free? Do I need an OpenAI key or any account? Free and keyless. The model downloads once and runs on your computer.
Does it change what my text says?
It is built not to: tries that lose a concept, change a quote or invent a reference are
rejected, check.py compares concepts and negations, and you reread every paragraph.
Does it add typos on purpose, like other "humanizers"? No. It changes who wrote the sentences and their rhythm, not the spelling.
Are the results consistent? Three of four essays reached 0% in Grammarly, and the latest one passes Grammarly, GPTZero and ZeroGPT at once. The pieces that can be deterministic are (the joining is seeded; ZeroGPT gives the same score for the same text), output that copies the original is refused, and 48 tests run on every change on Ubuntu, macOS and Windows. Detectors drift over time, which is why every session carries controls.
Does the selection step send my text anywhere? The tool never does. Measuring is your step, in your detector, as with any text you check.
Do I need a GPU? No. It runs on CPU, at low priority, so your computer stays usable.
Made for text you sign and answer for: brand content, outreach, documentation, emails, drafts written with AI help. Don't use it to hand in graded work as your own where AI is banned or must be disclosed. That problem isn't technical; it's academic honesty.
humanizar-es/
├── SKILL.md the skill for agents
├── install.py installs the skill (install.sh: shortcut for macOS/Linux)
├── scripts/
│ ├── install_model.py downloads the model (once)
│ ├── rewrite.py stages 1, 2 and 4: rewrite, guard fidelity, candidates
│ ├── check.py stage 2: concepts and negations, original vs rewrite
│ └── join.py stage 3: rebuild the rhythm of each paragraph
├── examples/ worked examples in Spanish and English
├── references/ every measurement, and how to measure
└── tests/ 48 tests on Ubuntu, macOS and Windows (no network, no model)
The old script names (hip.py, unir.py, verificar_fidelidad.py, instalar_hip.py)
still work.
What's missing most is evidence: the pipeline measured on more texts, more languages
and more detectors, always with a human control and the AI original. Open an issue or a
PR with the numbers in references/evidence.md.
python3 -m unittest discover -s tests -v
Code and docs: MIT, © ervin-mo. The HIP method and adapter are by Xu et al.
(2026); the base model is Alibaba's Qwen3-4B-Base. Both are Apache-2.0 and downloaded
separately: see THIRD_PARTY.md. If you use this in your work, cite the
repo (CITATION.cff) and the HIP paper.