martins-humaniser
<div align="center">
<img src="assets/martins-humaniser-1024.png" alt="Martin's Humaniser logo" width="120">
# Martin's Humaniser
**Strip the AI tells out of a PDF, Word, Markdown or text file, and keep every fact.**
[](https://github.com/MPavion/martins-humaniser/actions/workflows/tests.yml)



</div>

Martin's Humaniser rewrites text that reads like a chatbot wrote it ("It's important to note...", "a rich tapestry of...", "That distinction matters.") so it reads like a person wrote it. It then checks the result: numbers, links, names and quotations must survive, and an optional second pass reviews the rewrite for invented or lost detail.
It runs three ways, all on one engine:
- **A browser app** you open from a Desktop icon. Drop files in, press a button.
- **A command line** for scripts and batches.
- **An MCP server**, so Claude Desktop, Cowork and Claude Code can call it as a tool.
It isn't an AI detector, and it can't promise that a detector will pass your text. It's an editor with a checklist. See [Limits](#limits-and-honest-caveats).
## Contents
- [Quick start](#quick-start)
- [Choosing a model](#choosing-a-model)
- [Using the app](#using-the-app)
- [What it checks](#what-it-checks)
- [Make it sound like you](#make-it-sound-like-you)
- [Command line](#command-line)
- [Using it from Claude (MCP)](#using-it-from-claude-mcp)
- [Rules and custom rules](#rules-and-custom-rules)
- [Configuration](#configuration)
- [How it rewrites](#how-it-rewrites)
- [The score](#the-score)
- [The AI assessor](#the-ai-assessor)
- [Limits and honest caveats](#limits-and-honest-caveats)
- [Privacy](#privacy)
- [Troubleshooting](#troubleshooting)
- [Updating and uninstalling](#updating-and-uninstalling)
- [Project layout](#project-layout)
- [Development](#development)
- [Credits](#credits)
## Quick start
You need Python 3.10 or newer and one way to run a model (see [Choosing a model](#choosing-a-model)). The setup script does the rest: it makes a private environment, installs the packages, puts a **Martin's Humaniser** icon on your Desktop, connects Claude Desktop if you have it, and runs a health check.
### Windows
1. Download the repository (green **Code** button, then **Download ZIP**) and unzip it, or run `git clone https://github.com/MPavion/martins-humaniser.git`.
2. Double-click **`setup.bat`**. If Python is missing, it offers to install it with winget.
3. Double-click the **Martin's Humaniser** icon on your Desktop.
That's the whole job. Running `setup.bat` again is safe. It repairs a moved or broken environment and refreshes the icon.
### macOS and Linux
```bash
git clone https://github.com/MPavion/martins-humaniser.git
cd martins-humaniser
./setup.sh
```
On macOS you get a `Martin's Humaniser.command` file on the Desktop. On Linux you get a launcher entry in your applications menu and on the Desktop. Or run `./run_gui.sh` from the folder.
### Setup options
`python scripts/install.py` takes these flags (the `.bat` and `.sh` wrappers pass them through):
| Flag | Effect |
|---|---|
| `--yes` | Don't ask questions |
| `--no-shortcut` | Skip the Desktop icon |
| `--no-mcp` | Skip the Claude Desktop connection |
| `--launch` | Open the app when setup finishes |
Check a setup at any time with `python -m ai_humanizer --doctor`. It lists what's working, what's missing and the exact fix for each problem.
## Choosing a model
The tool needs a language model to do the rewriting. Pick whichever you have. `auto` tries them in this order.
| Backend | You need | Good for | Notes |
|---|---|---|---|
| `claude-cli` | [Claude Code](https://claude.com/claude-code) installed and signed in | Most people with a Claude subscription | No API key. |
| `anthropic` | `ANTHROPIC_API_KEY` | Pay-per-use | Model set by `AI_HUMANIZER_MODEL`. |
| `ollama` | [Ollama](https://ollama.com) running, then `ollama pull llama3.1:8b` | Fully offline and private | Smaller models follow the rules less closely. |
| `openai-compatible` | LM Studio, llama.cpp or any server with an OpenAI-style API | Local or self-hosted | Set `AI_HUMANIZER_LOCAL_URL`. |
| `mock` | nothing | Trying the interface | Makes trivial swaps. Not a real humaniser. |
If nothing is available, the app tells you what to install instead of failing quietly.
## Using the app

The app has four tabs:
- **Documents**: drop in one or more files.
- **Files on this PC**: point at a folder and pick files, so the result lands next to the original.
- **Paste text**: for a quick paragraph. **Try an example** loads a sample so you can see how it works before using your own text.
- **Teach it your taste**: show it a draft and your edited version, and it learns what you cut.
Choose a level (light, standard, deep) and press **Humanise**. For each file you get:
- the AI-tell score before and after, with a plain-language band (clean, some tells, many tells, heavy)
- a check that numbers, links, emails and quotations match the original
- the tells still left, with line numbers
- downloads as `.docx`, `.pdf`, `.md` or `.txt`, plus a copy saved next to the original

### Edit before you save
The **Before and after** view is tall, highlights what changed (underlined, not colour-only, so it works if you're colourblind), and the output side is editable. Whatever you fix by hand goes into the download and the saved copy.
### Fidelity review
When the AI assessor finds details the rewrite invented, lost or changed, each one is listed with options: **keep**, **remove**, **restore the original**, or **edit this phrase** in place. Press **Apply** and the choices go into the document. You never have to hunt through the text for them.
### File handling
- PDFs come back as clean Word or PDF files. A DOCX source is edited in place, so styles, tables and page setup survive.
- Output is saved as `name.humanised.ext`. Your original is never overwritten.
- Title blocks ("Name: ...", "Date: ..."), headings and quotations are kept as they were.
## What it checks
| Check | What it does | Needs a model |
|---|---|---|
| **Tell score** | 0 to 100 pattern score before and after. Repeatable. | No |
| **Fact check** | Numbers, links, emails, names and quotations compared with the original | No |
| **AI assessor** | Scores six dimensions, blind, on original and rewrite | Yes |
| **Fidelity** | Lists invented, lost or changed details | Yes |
| **Deep check** | Finds empty claims, set-up sentences, echo endings, fake balance | Yes |
| **Voice match** | Reports how close the rewrite is to your own writing | Yes (profile) |
## Make it sound like you

**Match my voice.** Put things you wrote (txt, md, docx, pdf) in the `voice` folder. About 1,000 words or more works best. Tick **Match my voice**, or use `--voice`. The tool measures your sentence length, contractions and dashes, picks clean passages as examples, asks the model for a short description of your style, and then reports how close the rewrite is to your own numbers.
**Deep check for empty claims.** An extra pass (`--semantic`) looks for vague claims, set-up sentences, echo endings, unsupported superlatives and fake balance. Every issue must quote the text, and quotes that aren't really in the paragraph are dropped. Findings feed the repair pass.
**Teach it your taste.** Paste an AI draft and your hand-edited version in the fourth tab. It lists phrases you removed and general habits, and you tick the ones to keep. Phrases join the pattern checker. Habits join the rewrite prompt. Everything is stored in `rules/custom/`, which Git ignores. CLI: `--learn draft.txt edited.txt --save-learned`.
**Local models.** Choose `ollama` or `openai-compatible` and nothing leaves your computer.
## Command line
```bash
python -m ai_humanizer report.pdf # saves report.humanised.docx
python -m ai_humanizer post.md --level deep -o post-final.md
python -m ai_humanizer post.md --check # list tells, no rewrite
python -m ai_humanizer report.docx --pdf # also saves report.humanised.pdf
python -m ai_humanizer post.md --voice --semantic --assess
python -m ai_humanizer --learn draft.txt edited.txt --save-learned
python -m ai_humanizer --doctor # health check
python -m ai_humanizer --status # backends and rule sources
```
After `pip install -e .` the same commands are available as `martins-humaniser`.
## Using it from Claude (MCP)
The server runs on your computer over stdio, so Claude can read and write files by their paths. `setup` registers it with Claude Desktop (a backup of your config is made first). Restart Claude Desktop afterwards.
There are two ways to work:
**Claude rewrites, the server checks (no model setup needed).**
1. `humanizer_get_rules` returns the editing rules.
2. `humanizer_extract_document` reads a file.
3. Claude rewrites the text.
4. `humanizer_compare` gives the score before and after and flags any changed number, link or quotation.
5. `humanizer_save_document` writes the result.
**The server rewrites.** `humanizer_humanize_file` and `humanizer_humanize_text` use your chosen backend and return the same report.
| Tool | What it does |
|---|---|
| `humanizer_status` | Backends, rule sources, supported files |
| `humanizer_get_rules` | The rules text Claude should follow |
| `humanizer_extract_document` | File to Markdown text |
| `humanizer_lint_text` | Findings and a 0 to 100 score, no model |
| `humanizer_compare` | Before and after score, remaining tells, fact check |
| `humanizer_save_document` | Markdown text to `.docx`, `.md` or `.txt` |
| `humanizer_humanize_text` | Server-side rewrite of text |
| `humanizer_humanize_file` | Server-side rewrite of a file, saved as `<name>.humanised.<ext>` |
| `humanizer_assess_text` / `_file` / `_pair` | Blind rubric scoring and fidelity |
| `humanizer_voice_profile` | Build or show your voice profile |
| `humanizer_learn_from_edit` | Learn phrases from a draft and your edit |
| `humanizer_forget_phrase` | Remove a learned phrase |
Existing output files are only replaced with `overwrite=true`. To register by hand, `python scripts/install_mcp.py --print` shows the JSON for `claude_desktop_config.json` and the `claude mcp add` command. `--remove` takes the entry out. The connector keeps the technical name `ai-humanizer`.
## Rules and custom rules
Rules are read in this order, and later sources win:
1. `ai_humanizer/data/default_rules.md`, bundled
2. an installed Claude skill: `~/.claude/skills/humanizer/SKILL.md`, or the path in `AI_HUMANIZER_SKILL_PATH`
3. every `.md` file in `rules/custom/` (Git ignores it, so private rules stay local)
4. paths in `AI_HUMANIZER_EXTRA_RULES`
Drop a house style guide or writing SOP into `rules/custom/` and it applies to every rewrite. The editing rules come from Wikipedia's [Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing) guide, plus extra habits covering short maxims, "Without X, Y" lines, balanced pairs, contractions and the "That distinction matters" family.
## Configuration
Everything has a sensible default. Set these as environment variables if you want to change one.
| Variable | Default | Purpose |
|---|---|---|
| `AI_HUMANIZER_BACKEND` | `auto` | `auto`, `claude-cli`, `anthropic`, `ollama`, `openai-compatible`, `mock` |
| `AI_HUMANIZER_MODEL` | `claude-sonnet-5-5` | Model for the `anthropic` backend |
| `AI_HUMANIZER_CLI_MODEL` | (CLI default) | Model for `claude-cli` |
| `AI_HUMANIZER_LOCAL_MODEL` | `llama3.1:8b` | Model for `ollama` / `openai-compatible` |
| `AI_HUMANIZER_LOCAL_URL` | `http://localhost:11434` | Local server address |
| `AI_HUMANIZER_LOCAL_API_KEY` | none | Key for a local server that needs one |
| `AI_HUMANIZER_LEVEL` | `standard` | `light`, `standard`, `deep` |
| `AI_HUMANIZER_LOCALE` | `British English` | Spelling variant, for example `American English` |
| `AI_HUMANIZER_VOICE` | off | Match my voice |
| `AI_HUMANIZER_SEMANTIC` | off | Deep check for empty claims |
| `AI_HUMANIZER_ASSESSOR_BACKEND` | same as rewrite | Use a different model as judge |
| `AI_HUMANIZER_ASSESS_RUNS` | `1` | Average several assessor runs |
| `AI_HUMANIZER_WORKERS` | `3` | Parallel chunks |
| `AI_HUMANIZER_OUTPUT` | `output/` | Where saved copies go |
| `AI_HUMANIZER_VOICE_DIR` | `voice/` | Your writing samples |
| `AI_HUMANIZER_CUSTOM_RULES` | `rules/custom/` | Your private rules |
| `AI_HUMANIZER_EXTRA_RULES` | none | Extra rule files |
## How it rewrites
1. The file is split into headings, title blocks, paragraphs, lists, quotes, code and tables. Only paragraphs are rewritten. Title blocks, single-line labels and heading-like lines are kept exactly, and a rewrite that cuts most of a paragraph is refused. Quotations stay verbatim.
2. Consecutive paragraphs are grouped into chunks of about 900 words. Each chunk goes to the model with the rules, the section heading for context, and an optional sample of your own writing.
3. The model must return the same number of paragraphs. If it doesn't, the chunk is retried, then rewritten paragraph by paragraph, then kept as written.
4. The result is linted. If serious tells remain, one repair pass names them and asks for a fix.
5. Numbers, links, emails, quotations and names are compared with the original.
## The score
The score comes from `lint.py`, a set of patterns and thresholds: word tiers, stock phrases, signposting, negative parallelism, em-dash density, bold, emoji, chatbot leftovers, contractions and the structural habits below. It uses no model, so results repeat. It runs from 0 (nothing found) to 100 (saturated).
| Score | Band |
|---|---|
| under 15 | Clean |
| 15 to 34 | Some tells |
| 35 to 59 | Many tells |
| 60 and up | Heavy |
Word and phrase lists draw on Wikipedia's guide, Grammarly's and Pangram's published lists, GPTZero's vocabulary page, and two open-access studies of vocabulary change in scientific papers after ChatGPT. Single words are weak evidence (many are normal English), so ordinary words get low weight and an allowance per piece. Clusters matter more, so four or more flagged words close together raise a separate finding.
The vocabulary list was checked against Matsui (2025), "Delving Into PubMed Records" (135 terms from 15 studies, tested on 27.5 million PubMed records). The paper's data (MIT licence, `ai_humanizer/data/pubmed_terms.csv`, source in `PUBMED_TERMS_NOTICE.md`) sets the weights. A word that rose sharply and is rare in normal writing (delve, tapestry, commendable) counts most. A word that rose but is common (primarily, notably) is flagged only past a small allowance. The paper found these terms started rising in 2020, before ChatGPT, and that writers have avoided them since 2024, so the list will date.
### Ten structural habits
Beyond words, the checker looks for short general maxims; "Without X, Y" counterfactuals and repeated-word punch lines; balanced pairs; figurative verbs for abstract effects; glossary-style sentences; sentences about the argument's own structure; trailing participle clauses; lists of three beyond a normal rate; sentences that all sit in a narrow length band; and text with few concrete details. The last two need about 150 words. They're weak signals alone, and careful textbook writing triggers several of them too.
## The AI assessor
Tick **AI assessor** in the app, pass `--assess`, or use `assess=true` in the MCP tools. A model scores the original and the rewrite on six dimensions (specificity, vocabulary, structure, voice, claims, formatting). Higher means more AI-like.
- It's blind: the model isn't told which text is the rewrite.
- Every issue it lists quotes the text. Quotes that don't appear in the text are dropped.
- The overall score is calculated here from the six dimension scores.
- The fidelity check reports details the rewrite invented, lost or changed: *faithful*, *minor drift* (1 to 2 invented or changed, or 3 or more lost) or *unfaithful* (3 or more invented or changed).
- Long documents are scored on sampled passages (start, middle, end).
A model judging a model's rewrite tends to be generous. For an independent judge, set `AI_HUMANIZER_ASSESSOR_BACKEND` to a different backend and `AI_HUMANIZER_ASSESS_RUNS=3`. Read the quoted issues rather than trusting the number.
## Limits and honest caveats
- **It isn't a detector and gives no guarantee.** Detectors disagree with each other and are unreliable both ways. A low score here means the common tells are gone, not that the text is good.
- **Read the output.** A model can still invent or drop a detail. The fact check and fidelity review catch most of it, not all.
- PDF layout is approximated from extracted text. Columns, tables and footnotes may need a manual check. Scanned PDFs have no text and need OCR first.
- PDF output is a clean A4 layout built from the text. For an exact Word layout, save as DOCX.
- Lists, tables, code and quotes pass through unchanged.
- In DOCX files, text inside hyperlinks is kept as it was.
- Spelled-out numbers ("five" for 5) show up as differences in the fact check.
- The default spelling is British English. Change it with `AI_HUMANIZER_LOCALE="American English"`.
### Use it responsibly
Use it to improve your own drafts and to edit text you're entitled to edit. Don't use it to pass off AI output where a person's own work is required (exams, journal submissions with disclosure rules, and so on). Follow the rules of wherever you publish.
## Privacy
- Files are processed on your computer. Text is sent only to the backend you choose: Claude (through Claude Code or the API), or a local model that never leaves your machine.
- No telemetry, no accounts, no analytics.
- `rules/custom/`, `voice/`, `output/` and the app's saved settings are in `.gitignore`, so your private rules, writing samples and results are never committed.
- If the text is sensitive, use `ollama` or `openai-compatible` with a local model.
## Troubleshooting
| Symptom | Fix |
|---|---|
| Start with `python -m ai_humanizer --doctor` | It names the problem and the fix. |
| "No model available" in the app | Install and sign in to Claude Code, set `ANTHROPIC_API_KEY`, or start Ollama. |
| The Desktop icon does nothing | Run `setup.bat` again. It repairs the environment and the icon. |
| No Desktop icon | Run `python scripts/install.py`. OneDrive-redirected Desktops are handled. |
| I moved or renamed the folder | Close the app, then run `setup.bat` once. |
| The app says the port is busy | The launcher picks the next free port from 8501 to 8530 by itself. |
| Claude Desktop doesn't list the tool | Restart Claude Desktop. If it still doesn't, run `python scripts/install_mcp.py --print` and compare. |
| Rewrite returned the wrong number of paragraphs | The paragraph is kept as written. Try `--level light`, or a stronger model. |
| Odd characters on Windows | Set `PYTHONUTF8=1`. The launcher does this for you. |
## Updating and uninstalling
**Update:** `git pull` (or download the new ZIP over the old folder), then run `setup.bat` or `./setup.sh` again.
**Uninstall:** run `python scripts/install_mcp.py --remove`, delete the Desktop icon, then delete the folder. Nothing is installed outside the folder except the Claude Desktop config entry and the icon.
## Project layout
```
app.py Streamlit app
ai_humanizer/ the engine (lint, pipeline, backends, voice, learn, fixes, MCP server, CLI)
ai_humanizer/data/ bundled rules and word data
scripts/install.py one-step setup (environment, packages, icon, Claude Desktop, health check)
scripts/launch.py starts the app on a free port and opens the browser
scripts/install_mcp.py registers or removes the Claude Desktop connection
rules/custom/ your private rules (ignored by Git)
voice/ your writing samples (ignored by Git)
output/ saved results (ignored by Git)
tests/ pytest suite
assets/ icon and logo
docs/images/ README screenshots
```
## Development
```bash
pip install -r requirements-dev.txt
pytest
```
The suite runs without a model, using the `mock` backend. See [CONTRIBUTING.md](CONTRIBUTING.md) for the workflow and [CHANGELOG.md](CHANGELOG.md) for what's changed.
## Credits
- Pattern list based on Wikipedia's [Signs of AI writing](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing) guide (WikiProject AI Cleanup).
- Vocabulary weights use data from Matsui (2025), "Delving Into PubMed Records" (MIT). See `ai_humanizer/data/PUBMED_TERMS_NOTICE.md`.
- Assessor rubric ideas were informed by reading unslop and stop-slop (both MIT). No code was copied.
- Built with [Streamlit](https://streamlit.io), python-docx, pypdf and reportlab.
Licence: [MIT](LICENSE). Copyright (c) 2026 Martin Pavion.
TDQS
Scored across 14 tools
Most tools occupy clearly distinct slots: extract vs save vs humanize_text vs humanize_file vs lint vs assess are separable, and the text/file suffix pattern makes the scope explicit. The one real collision is humanizer_compare versus humanizer_assess_pair, which both take an original and a rewrite and both report before/after scores plus a fact-faithfulness check; the descriptions differentiate them (deterministic lint vs blind model rubric) but an agent could easily grab the wrong one.
Every tool uses the same humanizer_ prefix plus snake_case, and almost all follow a verb_noun shape (get_rules, lint_text, save_document, learn_from_edit, assess_file). The few noun-only names (status, voice_profile) are natural reads of read-only probes and do not break the pattern.
Fourteen tools sits comfortably in the sensible range for a document-rewriting pipeline, and each one maps to a real pipeline stage. It is slightly heavy because the assess_* and humanize_* families triple up across text/file/pair, which produces redundancy around the compare/assess_pair overlap.
The lifecycle is largely covered end to end: read a document, inspect and load rules, rewrite inline or as a file, lint, assess, verify facts, save, then learn from hand edits and profile the author's voice. Gaps are minor: learned rules can only be removed phrase-by-phrase (no way to list or drop a whole learned rule), and there is no tool to manage or reset the voice sample folder.