manuscript-tools
A QA toolkit for German Markdown manuscripts. Validates style, sanitizes encoding, converts quotation marks, and measures readability.
Installation
pip install manuscript-tools
Or as project dependency:
poetry add manuscript-tools
Commands
| Command | Description |
|---|---|
ms-check |
Style checks (6 core rules, --strict adds 3 prose rules) |
ms-sanitize |
Fix encoding, strip invisible chars, normalize Unicode |
ms-quotes |
Convert quotation marks to German typographic style „ " ‚ ' |
ms-dashes |
Rewrite faked dashes (--, spaced hyphen) to a real dash (--to em|en) |
ms-umlauts |
Rewrite ASCII umlauts (fuer to für) from a curated word list |
ms-format |
Fix broken bold/italic caused by line-wrapping formatters |
ms-metrics |
Word counts, sentence analysis, Flesch-DE readability score |
ms-validate |
Full QA pipeline (sanitize + quotes + formatting + check + readability) |
Quick start
# Full QA pipeline
ms-validate manuscript/
# Style check only (core rules)
ms-check manuscript/
# Style check with prose analysis (filler words, passive voice, sentence length)
ms-check manuscript/ --strict
# Readability report
ms-metrics manuscript/
# Fix quotation marks (dry-run)
ms-quotes manuscript/ --dry-run
# Fix broken bold/italic formatting (dry-run)
ms-format manuscript/ --dry-run
# Rewrite -- and spaced hyphens to en-dashes (German typography, dry-run)
ms-dashes manuscript/ --to en --dry-run
# Rewrite ASCII umlauts like "fuer" and "Uebung" (dry-run)
ms-umlauts manuscript/ --dry-run
File selection
Not limited to Markdown. Directories are scanned with the glob **/*.md by default; a single file passed as argument is processed as-is, regardless of extension:
# Single file: no glob filter applied
ms-check brief.txt
# Directory with other extensions: override the glob
ms-sanitize docs/ --include '**/*.txt'
ms-check kapitel/ --include '**/*.tex' --exclude '**/build/**'
Files must be UTF-8 text (txt, tex, rst, html, ...) — binary formats like docx or pdf are not supported. The broken-formatting rule checks Markdown **/* markers; for non-Markdown files it is harmless, or disable it via disable = ["broken-formatting"] in the configuration.
Example
A manuscript with typical artifacts from AI tools, copy-paste, or code formatters — line 1 contains an invisible zero-width space (U+200B) after "Test":
Das ist ein Test mit unsichtbarem Zeichen.
Er sagte: "Hallo Welt" und ging.
Dies ist ein **
wichtiger Satz** im Text.
ms-check reports every problem with file, line, and rule — invisible characters are named by codepoint:
$ ms-check kapitel-01.md
FAIL: kapitel-01.md:1 [no-invisible-chars] Unsichtbare Unicode-Zeichen gefunden: U+200B ZERO WIDTH SPACE
FAIL: kapitel-01.md:3 [non-german-quotes] Nicht-deutsche Anführungszeichen gefunden
FAIL: kapitel-01.md:5 [broken-formatting] Oeffnendes ** am Zeilenende (Formatierung gebrochen)
------------------------------------------------------------
Dateien: 1, Woerter: 21
Status: FEHLER (1 Dateien, 3 Verstoss(e))
Fix step by step — every fixer supports --dry-run (preview) and writes .bak backups:
$ ms-sanitize kapitel-01.md
CLEANED: kapitel-01.md
$ ms-quotes kapitel-01.md
FIXED: kapitel-01.md (1 Ersetzung(en))
$ ms-format kapitel-01.md
FIXED: kapitel-01.md (1 bold, 0 italic)
$ ms-check kapitel-01.md
OK: kapitel-01.md (20 Woerter)
Status: OK
Result:
Das ist ein Test mit unsichtbarem Zeichen.
Er sagte: „Hallo Welt“ und ging.
Dies ist ein **wichtiger Satz** im Text.
Or run the whole pipeline in one go: ms-validate kapitel-01.md --fix.
Rules
Core (always active):
no-dashes, no-invisible-chars, no-repeated-words, no-double-spaces, non-german-quotes, broken-formatting
Prose (with --strict or ms-validate):
max-sentence-length, filler-words-de, passive-voice-de
Opt-in (via rules = [...] in the configuration):
faked-dashes — flags -- and spaced hyphens standing in for a real dash. By design it contradicts no-dashes (one forbids dashes, the other demands correctly typed ones), so enable one and disable the other. ms-dashes --to em|en rewrites the findings:
Er kam -- wie immer -- viel zu spaet. # before
Er kam – wie immer – viel zu spaet. # after ms-dashes --to en
Seiten 12 - 15 behandeln das Thema. # numeric ranges stay untouched
[x](https://img.shields.io/badge/a--b) # URLs and badge slugs stay untouched
ascii-umlauts — flags ASCII umlaut spellings (fuer, Uebung) from a curated word list; ms-umlauts rewrites them. Deliberately not a pattern: German is full of legitimate ae/oe/ue sequences ("Frauen", "Goethe", "Aerobic"), so only vetted whole words are touched — zero false positives by construction. Extend the list per project via umlaut-words-extra = ["oekologie"]. ss to ß is out of scope (context-dependent, Swiss orthography conflict).
Das waere natuerlich schoen fuer alle. # before
Das wäre natürlich schön für alle. # after ms-umlauts
Goethe traf die Frauen beim Feuer. # names and diphthongs stay untouched
Custom rules are simple callables with the signature (text: str, path: Path) -> list[StyleViolation]. See the Wiki for a step-by-step tutorial.
Configuration
Configure via [tool.manuscript-tools] in your pyproject.toml:
[tool.manuscript-tools]
rules = ["max-sentence-length"] # merge with defaults
disable = ["passive-voice-de"] # remove from active set
max-sentence-words = 30 # default: 40
flesch-target = [65, 80] # warn if outside range
filler-words-extra = ["definitiv", "absolut"] # extend filler list
umlaut-words-extra = ["oekologie"] # extend the ascii-umlauts word list
No config = all defaults. rules merges with defaults (union). disable removes from the active set and takes precedence over rules. See the Wiki for details.
Readability
ms-metrics computes the Flesch-DE reading ease score (Amstad, 1978) with German-optimized syllable counting. Score interpretation:
| Score | Level | Typical use |
|---|---|---|
| 80-100 | Very easy | Children's books |
| 60-80 | Easy to medium | Fiction, non-fiction |
| 30-60 | Difficult | Journalism, academic |
| 0-30 | Very difficult | Legal, scientific |
Development
git clone https://github.com/astrapi69/manuscript-tools.git
cd manuscript-tools
make install-dev
make ci # lint + format check + 226 tests
Documentation
Full documentation is available in the Wiki:
- Installation and Setup
- Usage
- Writing Custom Rules
- Integration into Projects
- Publishing to PyPI
- Development and CI
- FAQ
- Quick Start for Book Projects
- Configuration
License
BSD 3-Clause. See LICENSE.
Release files for manuscript-tools 0.11.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| manuscript_tools-0.11.0.tar.gz | 35.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| manuscript_tools-0.11.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 75.1 kB
Release files / manuscript_tools-0.11.0.tar.gz
| Download URL | manuscript_tools-0.11.0.tar.gz |
|---|---|
| Size | 35.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bbac2dd36830f36e150b82e16a94cb76bba21cc37078b4e8c4f1a41d8f701651
|
|
BLAKE2b-256 checksum How to use checksums |
965639c4f507d2ea2963419c5f451d368971fd20ba0323137e6c91dc5b24a729
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.11.13 Linux/7.0.0-28-generic
|
Release files / manuscript_tools-0.11.0-py3-none-any.whl
| Download URL | manuscript_tools-0.11.0-py3-none-any.whl |
|---|---|
| Size | 39.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1b854f7b2d7f2c84239dad0746fd2ce8901ea7622df9b6aa9354fa8d133ab066
|
|
BLAKE2b-256 checksum How to use checksums |
8599be6c346053cbb31bd04af43faad28eb2ba5c71c46d2ef14a3b409b7656fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.11.13 Linux/7.0.0-28-generic
|