I work on HumanPen, a document-level AI humanizer, so treat this as a builder writing about their own problem, not a neutral survey. Most of the engineering below applies to anything that rewrites prose inside real office files, whatever the rewrite is for.
The naive pipeline is three steps: extract the text, send it to a model, paste the result back. Fine for a blog post. It falls apart the moment the input is a paper with citations, tables, cross-references and a table of contents.
Why the round trip is lossy
A .docx is a zip of XML parts: the body in word/document.xml, footnotes, headers, numbering, styles and embedded objects each in their own part, wired together by a relationship graph and integer ids.
Inside the body a sentence is almost never one node. Word splits a paragraph into runs whenever any property changes. Italicise one species name, insert a citation from Zotero, and one sentence becomes five runs, two of them inside a field.
Flatten that to a string and here is what goes in the bin:
- Field codes. A TOC entry, a cross-reference ("see Table 2"), an auto figure number and a citation-manager citation are all an instruction plus a cached result. Flatten them and the cache becomes the permanent value. The document stops updating, and nobody notices until a table gets reordered.
- Run-level meaning. Superscripts, subscripts, italic conventions that carry semantics in a scientific paper. Equations are not text at all, they are OMML.
- Containers. Table cells, captions, footnote references that point into another part by id. Extraction hands back a caption and a body paragraph as two adjacent lines with nothing marking which is which, so the caption gets rewritten as prose.
- Geometry, in PPTX. Text lives in shapes with fixed size. A rewrite that comes back longer overflows the box, and you find out by opening the deck.
None of this appears in a diff of the extracted text. It appears when the author opens the file.
The conclusion we ended up with: the document is the data structure, and the text is a view of it. Rewriting happens in place at paragraph granularity, and everything the model has no business touching is fenced off before a prompt is built. That fence covers in-text citations, reference entries, footnotes, TOC fields, cross-references, figure numbering, formulas, code, tables and captions.
There is a second fence, on content rather than structure: numbers, dates, units, proper names and terminology are constrained, and so are negation, causality and claim strength. "Association" must not come back as "causation". "No significant difference" must not come back missing "significant". A rewrite that reads beautifully and inverts a finding is worse than no rewrite at all.
Chunking: fixed-length splitting is the easy wrong answer
Long documents have to be split, and splitting on a token count cuts paragraphs and arguments in half. That is the obvious problem. The less obvious one is what happens after the split.
Process each chunk independently and they drift. Chunk 3 settles on "participants", chunk 9 prefers "subjects". One expands an acronym on every use, the next assumes it was introduced already. Every chunk is locally fine and the document reads like three people wrote it, which is a funny outcome for a tool whose job is to make text read as one person's.
Two changes fix most of it: split on semantic boundaries so a chunk is a unit of argument rather than a unit of length, and give every chunk shared source context so it knows what the rest of the document already decided. Chunks still run in parallel. They are just not independent, and that is where the quality lives.
The payoff: the whole file goes in at once, and nobody pastes section 4.3 into a text box for the eleventh time.
Report-guided rewriting: matching PDF highlights back to source paragraphs
This is the part I find most interesting, and as far as the survey below goes, nobody else ships it end to end.
An author gets a Turnitin or iThenticate AI Writing Report on a 10,000-word paper, and roughly 2,800 words come back highlighted. Rewriting all 10,000 changes text that was already fine and hands the author a whole document to re-check.
So you need to pull highlighted spans out of a report PDF and find them in the source file. That is not a string match:
- The report is a rendering, not the source. Its text layer is laid out in lines and the highlighting is drawn as graphics over that layout, so recovering "which characters are highlighted" means intersecting geometry with the text layer.
- The text differs from the original. Line-end hyphenation, ligatures, smart quotes and running heads all block exact comparison.
- Highlights ignore paragraph boundaries. A flagged span often starts mid-sentence and trails off two sentences later.
That last one drives a design decision. Rewrite half a paragraph and you get a paragraph in two voices, plus a sentence whose subject was introduced in the half you left alone. So a partial match is expanded to the complete paragraph, and the paragraph is the smallest rewrite unit.
Because matching is heuristic, the matched scope is shown for confirmation before the job starts, and unconfirmed content stays out of scope. Guessing wrong on a fuzzy match, silently, is much worse than asking. One related trap: an AI Writing Report is not a Similarity Report. Different document, different classifications, and treating one as the other produces confident nonsense.
One thing we refuse to do: inject grammar or spelling errors to move a detector. It makes the paper worse, and the author is the one who has to defend it.
The agent surface, and why documents fit MCP well
The same operations ship three ways: an MCP server, an Agent Skill (a folder with a SKILL.md, no server), and a plain HTTP API. One account, one credit balance across all three.
Documents are an unusually good MCP fit for a boring reason: the payload never has to enter the model's context. The tool takes a path, uploads the file, and answers with a path. A 40-page paper costs no tokens. In the paste-box workflow the agent carries the whole document through its own context window twice.
claude mcp add humanpen -s user -e HUMANPEN_API_KEY=hp_your_key -- npx -y humanpen-mcp
The selective-rewrite feature is one argument:
{
"name": "humanize_document",
"arguments": {
"document_path": "/abs/path/paper.docx",
"report_path": "/abs/path/turnitin-ai-report.pdf",
"strategy": "balanced"
}
}
Pass report_path and only the flagged passages are in scope. Leave it out and the whole document is. A separate free tool parses the report and returns the overall percentage plus the flagged passages, which is enough to decide whether to spend anything at all.
One protocol-level lesson worth stealing: jobs take minutes, tool calls should not. Each call waits about 55 seconds, then returns a job_id and tells the agent to poll check_job. The work continues server-side either way. A tool that blocks for six minutes gets killed by somebody's client timeout, and the user has no idea whether their credits were spent.
The survey, trimmed to what matters technically
From a comparison of 10 humanizers I keep up to date, reviewed against official pages on 2026-08-10. Limits are each product's highest plan.
| Product | Per-request / per-file input limit | File in, same file out | Format preservation |
|---|---|---|---|
| HumanPen | 100 MB/file, no word limit | DOCX → DOCX, PPTX → PPTX | Structure, citations, tables, layout, styles protected |
| Undetectable.ai | 10,000 characters/operation | Paste box | No DOCX/PPTX round-trip promise |
| WriteHuman | 3,000 words/request | Paste box | Not a stated core capability |
| Walter Writes | 2,000 words/request | Text box, extension, API/MCP | No public same-format promise |
| StealthGPT | 20,000 words/request | Some plans import files | Import yes, no layout-preserving output promise |
| HIX Bypass | Unlimited input | Paste box / API | Not a stated core capability |
| Humbot | Unlimited input | Text box | No format-preservation promise |
| Phrasly | 5,000 words/process | In-platform Doc Editor | Editor yes, no DOCX/PPTX round-trip promise |
| HumanizeAI.pro | Unlimited per process | Upload .txt/.docx/.pdf/.md | Upload yes, no promise the file keeps formatting |
| Caktus AI | Not publicly listed | Plain text only | No file upload on the humanizer page |
The line I would put on a poster: file upload is not the same as file preservation. Accepting a .docx tells you nothing about whether headers, footnotes, fields, tables, captions and slide layouts come back. Test the whole upload, process, download, open loop yourself, on a document that has a TOC and a cross-reference in it.
What I am not claiming
No detection-score comparison appears above, on purpose. Detectors change models without telling anyone, any "we score X% lower than Y" number is stale within weeks, and every vendor in that table can produce a flattering screenshot. Structure preservation is checkable by opening the file. Score claims are not, so I would rather not make them.
Honest limits today: English DOCX and PPTX in, same format out, and the output still needs a human read. If a fresh report still flags passages, re-running is free until the report drops under 20%, a policy that exists precisely because one pass is not guaranteed.
The full 10-tool comparison is on GitHub in eight languages, and the MCP and Skill repos are Apache-2.0 if you want the client side. Happy to argue about chunking strategy in the comments.
Top comments (0)