DOCX Skill
An Apache-2.0 toolkit for producing, editing, and reading Microsoft Word (.docx) files. Written from scratch against the public ECMA-376 / ISO/IEC 29500 specification and built on permissively-licensed tooling (python-docx MIT, lxml BSD-3-Clause, optional external binaries pandoc and soffice) so it can be reused in commercial projects without restriction.
Decision matrix
| Situation |
Path |
Read first |
| No source file — build a document from a prompt / data |
Author from scratch with python-docx |
create.md |
You have a .docx template to fill in or lightly modify |
Placeholder replacement via python-docx, keeps styles |
edit.md → Workflow A — python-docx in-place edit |
| Deep structural edits, new sections, custom XML, unusual layouts |
Explode → edit XML → assemble |
edit.md → Workflow B — Explode → edit XML → assemble |
You only need the text / structure / metadata out of a .docx |
Extraction pipeline |
read.md |
| Need a PDF preview for QA |
scripts/render_pdf.py via LibreOffice |
see QA below |
If the task mixes several of these, do them in this order: read → plan → edit/create → validate.
One-time environment setup
Bundled runtime: when the MIMO_PYTHON environment variable is set, skip uv/python3 and pip installs entirely — run every command below with uv run replaced by "$MIMO_PYTHON" (e.g. "$MIMO_PYTHON" scripts/extract_text.py input.docx). This skill's Python dependencies are preinstalled in that interpreter; pip console scripts are unavailable, so always go through "$MIMO_PYTHON" -m <module>. A bundled LibreOffice is exposed as MIMO_SOFFICE and picked up automatically by the scripts here.
All scripts include PEP 723 inline metadata, so uv run resolves dependencies automatically — no manual install step needed. Just run:
uv run scripts/extract_text.py input.docx
If you don't use uv, install dependencies once:
python3 -m pip install --upgrade python-docx lxml
# Optional but recommended:
# LibreOffice (for docx → pdf preview): brew install --cask libreoffice (macOS)
# apt-get install -y libreoffice (Debian/Ubuntu)
# Poppler (for pdf → image, QA loop): brew install poppler
Alternatively, if this skill lives in a persistent workspace you can uv init a project, uv add python-docx lxml, and run scripts with uv run scripts/... from the project root — this gives you a lockfile and reproducible environment.
All scripts here use the standard library plus python-docx. No proprietary dependencies.
Common commands
# 1. Extract plain text (best for "what does this file say?" questions)
uv run scripts/extract_text.py input.docx > input.txt
# 2. Explode a .docx into readable XML for structural surgery
uv run scripts/explode.py input.docx exploded/
# 3. Assemble an exploded directory into a fresh .docx
uv run scripts/assemble.py exploded/ output.docx
# 4. Render a .docx as PDF (used for visual QA)
uv run scripts/render_pdf.py output.docx # writes output.pdf next to it
# 5. Well-formedness check (ZIP integrity + parseable XML + python-docx open)
uv run scripts/audit.py output.docx
# 6. Accept every tracked change without needing Word/LibreOffice
uv run scripts/resolve_revisions.py reviewed.docx clean.docx
# 7. Add a comment to an exploded directory
uv run scripts/annotate.py exploded/ "Please check" --author "Reviewer" --anchor "text"
Every script is a small, self-contained Python file. Read the top of the file for full CLI options.
Authoring principles
Word is a flowing document format, not a slide surface. Users expect it to look like something a human wrote in Word — not a design tool trying to reinvent typography. Keep that in mind:
- Rely on named styles. Use
Heading 1, Heading 2, Normal, Title, Quote, List Bullet, List Number, Caption. They are what makes Word's ToC, navigation pane, and cross-references work.
- One idea per paragraph. Long paragraphs are fine; run-on paragraphs are not. Break at logical boundaries.
- Structure first, prose second. Draft the heading tree, then write inside it. Reviewers scan headings before words.
- Tables for tabular data only. Do not use tables to fake multi-column layouts — export to PDF and users see the borders through the layout.
- Line length is set by page margins, not by hard breaks. Never insert manual line breaks to control wrapping.
- Use fields, not literal text, for things that change — page numbers, dates, ToC, cross-references.
python-docx supports field codes via low-level XML (see edit.md).
- Every image needs alt text — accessibility, and Word screams at you in review mode when it's missing.
Typography defaults (safe starting point)
| Element |
Font |
Size |
Weight |
Notes |
| Title |
Calibri Light |
28pt |
Bold |
Centered or left, one line |
| Heading 1 |
Calibri Light |
18pt |
Bold |
Space before 12pt |
| Heading 2 |
Calibri Light |
14pt |
Bold |
Space before 10pt |
| Heading 3 |
Calibri |
12pt |
Bold |
Space before 6pt |
| Body |
Calibri |
11pt |
Regular |
Line spacing 1.15, space after 6pt |
| Caption |
Calibri |
9pt |
Italic |
Muted gray #595959 |
| Code / mono |
Consolas |
10pt |
Regular |
Left-aligned, no first-line indent |
Change the palette for the topic — muted navy #1F3A5F for legal/finance, warm charcoal #2E2A26 for editorial. Avoid pure #000000 for body text; #1F1F1F reads softer on print.
Page setup (A4 vs Letter)
Ask the user which one to use. If you cannot ask, default to the region implied by the language (Chinese/European → A4, US English → Letter). Margins:
| Size |
Width × Height |
Standard margins (T/B/L/R) |
| A4 |
21.0 × 29.7 cm |
2.54 / 2.54 / 3.18 / 3.18 cm |
| Letter |
8.5 × 11.0 in |
1.00 / 1.00 / 1.25 / 1.25 in |
QA checklist — always run before declaring done
Assume something is wrong. Word files fail silently: a broken relationship, an unclosed <w:p>, a missing style — Word will still open the file but strip content or throw a "content had problems" warning. Verify explicitly.
- Open cleanly — no repair prompt.
uv run python -c "import docx; docx.Document('output.docx')" # loads without exceptions
- Text integrity — no placeholder residue.
uv run scripts/extract_text.py output.docx | grep -Ei "TODO|TBD|\{\{|lorem|xxxx"
Grep must return nothing.
- Visual sanity — render a PDF, open the first and last pages, scan for:
- Widowed headings alone at the bottom of a page.
- Tables split awkwardly across pages.
- Images pushed to their own page because they exceeded content width.
- Missing page numbers, wrong header/footer content.
uv run scripts/render_pdf.py output.docx
- Style hygiene — every heading uses a real style, not just bold+large text:
uv run python -c "
import docx; d = docx.Document('output.docx')
for p in d.paragraphs:
if p.text and p.style.name == 'Normal' and p.runs and p.runs[0].bold:
print('possible fake heading:', p.text[:80])"
If any of these fail, fix and re-run — don't paper over.
What is out of scope
.doc (legacy Word 97-2003) — this skill only targets .docx (Office Open XML). Convert .doc to .docx with LibreOffice first: soffice --headless --convert-to docx old.doc.
- Live collaborative editing — the Word online API is a separate concern; here we produce and modify files.
- Macros / VBA — do not generate
.docm files. If the user asks for automation, offer a Python script that regenerates the doc instead.
Where each detail lives
- Creating from scratch:
create.md — headings, paragraphs, styles, tables, images, page setup, headers/footers, tables of contents.
- Editing / templating:
edit.md — placeholder replacement, section swap, raw XML surgery, tracked changes, comments.
- Reading / extracting:
read.md — plain-text export, structural walk, metadata, table extraction.
- Scripts:
scripts/ — self-contained CLI utilities used by all of the above.
1---2name: docx-official3description: Use this skill whenever a Microsoft Word (.docx) file is being produced, opened, transformed, or read. That includes: drafting reports, letters, contracts, RFPs, technical documents, or any long-form written deliverable; extracting text or structure from an existing Word file; filling a Word template with values; converting Word to PDF or plain text; splitting or merging documents; inspecting styles, headings, sections, tables, images, comments, or tracked changes. Trigger on mentions of 'Word doc', 'DOCX', 'Office document', a filename ending in .docx, or requests like 'turn this into a Word report'.4license: Apache-2.0 — see LICENSE for terms and third-party attributions5---67# DOCX Skill89An Apache-2.0 toolkit for producing, editing, and reading Microsoft Word (`.docx`) files. Written from scratch against the public [ECMA-376 / ISO/IEC 29500](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/) specification and built on permissively-licensed tooling (`python-docx` MIT, `lxml` BSD-3-Clause, optional external binaries `pandoc` and `soffice`) so it can be reused in commercial projects without restriction.1011## Decision matrix1213| Situation | Path | Read first |14|-----------|------|------------|15| No source file — build a document from a prompt / data | Author from scratch with `python-docx` | [`create.md`](create.md) |16| You have a `.docx` template to fill in or lightly modify | Placeholder replacement via `python-docx`, keeps styles | [`edit.md`](edit.md) → *Workflow A — `python-docx` in-place edit* |17| Deep structural edits, new sections, custom XML, unusual layouts | Explode → edit XML → assemble | [`edit.md`](edit.md) → *Workflow B — Explode → edit XML → assemble* |18| You only need the text / structure / metadata out of a `.docx` | Extraction pipeline | [`read.md`](read.md) |19| Need a PDF preview for QA | `scripts/render_pdf.py` via LibreOffice | see *QA* below |2021If the task mixes several of these, do them in this order: **read → plan → edit/create → validate**.2223## One-time environment setup2425> **Bundled runtime:** when the `MIMO_PYTHON` environment variable is set, skip `uv`/`python3` and pip installs entirely — run every command below with `uv run` replaced by `"$MIMO_PYTHON"` (e.g. `"$MIMO_PYTHON" scripts/extract_text.py input.docx`). This skill's Python dependencies are preinstalled in that interpreter; pip console scripts are unavailable, so always go through `"$MIMO_PYTHON" -m <module>`. A bundled LibreOffice is exposed as `MIMO_SOFFICE` and picked up automatically by the scripts here.2627All scripts include [PEP 723](https://peps.python.org/pep-0723/) inline metadata, so `uv run` resolves dependencies automatically — no manual install step needed. Just run:2829```bash30uv run scripts/extract_text.py input.docx31```3233If you don't use `uv`, install dependencies once:3435```bash36python3 -m pip install --upgrade python-docx lxml37# Optional but recommended:38# LibreOffice (for docx → pdf preview): brew install --cask libreoffice (macOS)39# apt-get install -y libreoffice (Debian/Ubuntu)40# Poppler (for pdf → image, QA loop): brew install poppler41```4243Alternatively, if this skill lives in a persistent workspace you can `uv init` a project, `uv add python-docx lxml`, and run scripts with `uv run scripts/...` from the project root — this gives you a lockfile and reproducible environment.4445All scripts here use the standard library plus `python-docx`. No proprietary dependencies.4647## Common commands4849```bash50# 1. Extract plain text (best for "what does this file say?" questions)51uv run scripts/extract_text.py input.docx > input.txt5253# 2. Explode a .docx into readable XML for structural surgery54uv run scripts/explode.py input.docx exploded/5556# 3. Assemble an exploded directory into a fresh .docx57uv run scripts/assemble.py exploded/ output.docx5859# 4. Render a .docx as PDF (used for visual QA)60uv run scripts/render_pdf.py output.docx # writes output.pdf next to it6162# 5. Well-formedness check (ZIP integrity + parseable XML + python-docx open)63uv run scripts/audit.py output.docx6465# 6. Accept every tracked change without needing Word/LibreOffice66uv run scripts/resolve_revisions.py reviewed.docx clean.docx6768# 7. Add a comment to an exploded directory69uv run scripts/annotate.py exploded/ "Please check" --author "Reviewer" --anchor "text"70```7172Every script is a small, self-contained Python file. Read the top of the file for full CLI options.7374## Authoring principles7576Word is a **flowing** document format, not a slide surface. Users expect it to look like something a human wrote in Word — not a design tool trying to reinvent typography. Keep that in mind:77781. **Rely on named styles.** Use `Heading 1`, `Heading 2`, `Normal`, `Title`, `Quote`, `List Bullet`, `List Number`, `Caption`. They are what makes Word's ToC, navigation pane, and cross-references work.792. **One idea per paragraph.** Long paragraphs are fine; run-on paragraphs are not. Break at logical boundaries.803. **Structure first, prose second.** Draft the heading tree, then write inside it. Reviewers scan headings before words.814. **Tables for tabular data only.** Do not use tables to fake multi-column layouts — export to PDF and users see the borders through the layout.825. **Line length is set by page margins, not by hard breaks.** Never insert manual line breaks to control wrapping.836. **Use fields, not literal text, for things that change** — page numbers, dates, ToC, cross-references. `python-docx` supports field codes via low-level XML (see `edit.md`).847. **Every image needs alt text** — accessibility, and Word screams at you in review mode when it's missing.8586## Typography defaults (safe starting point)8788| Element | Font | Size | Weight | Notes |89|----------------|---------------|------|--------|-------|90| Title | Calibri Light | 28pt | Bold | Centered or left, one line |91| Heading 1 | Calibri Light | 18pt | Bold | Space before 12pt |92| Heading 2 | Calibri Light | 14pt | Bold | Space before 10pt |93| Heading 3 | Calibri | 12pt | Bold | Space before 6pt |94| Body | Calibri | 11pt | Regular| Line spacing 1.15, space after 6pt |95| Caption | Calibri | 9pt | Italic | Muted gray `#595959` |96| Code / mono | Consolas | 10pt | Regular| Left-aligned, no first-line indent |9798Change the palette for the topic — muted navy `#1F3A5F` for legal/finance, warm charcoal `#2E2A26` for editorial. Avoid pure `#000000` for body text; `#1F1F1F` reads softer on print.99100## Page setup (A4 vs Letter)101102Ask the user which one to use. If you cannot ask, default to the region implied by the language (Chinese/European → A4, US English → Letter). Margins:103104| Size | Width × Height | Standard margins (T/B/L/R) |105|--------|-------------------|-----------------------------|106| A4 | 21.0 × 29.7 cm | 2.54 / 2.54 / 3.18 / 3.18 cm |107| Letter | 8.5 × 11.0 in | 1.00 / 1.00 / 1.25 / 1.25 in |108109## QA checklist — always run before declaring done110111**Assume something is wrong.** Word files fail silently: a broken relationship, an unclosed `<w:p>`, a missing style — Word will still open the file but strip content or throw a "content had problems" warning. Verify explicitly.1121131. **Open cleanly** — no repair prompt.114 ```bash115 uv run python -c "import docx; docx.Document('output.docx')" # loads without exceptions116 ```1172. **Text integrity** — no placeholder residue.118 ```bash119 uv run scripts/extract_text.py output.docx | grep -Ei "TODO|TBD|\{\{|lorem|xxxx"120 ```121 Grep must return nothing.1223. **Visual sanity** — render a PDF, open the first and last pages, scan for:123 - Widowed headings alone at the bottom of a page.124 - Tables split awkwardly across pages.125 - Images pushed to their own page because they exceeded content width.126 - Missing page numbers, wrong header/footer content.127 ```bash128 uv run scripts/render_pdf.py output.docx129 ```1304. **Style hygiene** — every heading uses a real style, not just bold+large text:131 ```bash132 uv run python -c "133 import docx; d = docx.Document('output.docx')134 for p in d.paragraphs:135 if p.text and p.style.name == 'Normal' and p.runs and p.runs[0].bold:136 print('possible fake heading:', p.text[:80])"137 ```138139If any of these fail, fix and re-run — don't paper over.140141## What is out of scope142143- **`.doc` (legacy Word 97-2003)** — this skill only targets `.docx` (Office Open XML). Convert `.doc` to `.docx` with LibreOffice first: `soffice --headless --convert-to docx old.doc`.144- **Live collaborative editing** — the Word online API is a separate concern; here we produce and modify files.145- **Macros / VBA** — do not generate `.docm` files. If the user asks for automation, offer a Python script that regenerates the doc instead.146147## Where each detail lives148149- **Creating from scratch**: [`create.md`](create.md) — headings, paragraphs, styles, tables, images, page setup, headers/footers, tables of contents.150- **Editing / templating**: [`edit.md`](edit.md) — placeholder replacement, section swap, raw XML surgery, tracked changes, comments.151- **Reading / extracting**: [`read.md`](read.md) — plain-text export, structural walk, metadata, table extraction.152- **Scripts**: [`scripts/`](scripts/) — self-contained CLI utilities used by all of the above.