Read, edit, or create Microsoft Word `.docx` files. Trigger this skill whenever the user mentions a Word document, .docx file, contract, report, brief, memo, or asks to extract text, modify an existing doc, generate one from a brief, or audit tracked changes. Three execution paths: text-and-structure extraction, in-place edit-by-run (preserves styles), and create-from-scratch with python-docx. Falls back to OOXML unzip-and-patch for layout work python-docx cannot reach.
78
100%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Work with Microsoft Word .docx files. The format is OOXML — a zip container
holding XML parts (word/document.xml, styles.xml, numbering.xml, headers,
footers, relationships). Treat structure as primary; rendered text is a view.
Pick one path up front. The right path depends only on what is on disk before you start.
| You have | Goal | Path |
|---|---|---|
Existing .docx | Read text/structure | A. Inspect |
Existing .docx | Modify content while keeping styles | B. Edit-in-place |
| Nothing or a brief | Build a new doc | C. Create from scratch |
If the user hands you a doc and asks for changes, default to path B and treat the input as the visual style baseline. Only choose path C when the user says "start fresh" or there is no input.
Dump structure as JSON for inspection without mutating anything.
python {baseDir}/scripts/inspect_docx.py /path/to/doc.docxOutput schema:
{
"paragraphs": [{"index": 0, "text": "...", "style": "Heading 1"}, ...],
"tables": [[["row0,col0", "row0,col1"], ...], ...],
"sections": 1,
"has_tracked_changes": false
}Use this whenever you need to see what is in the doc before deciding how to edit. The output is stable and machine-readable — diff two inspect outputs to verify a round-trip preserved everything you intended.
Two sub-strategies; pick by how invasive the edit is.
When the change is "swap this string" or "fill these placeholders": mutate runs in place. This preserves all theme/style/font settings.
python {baseDir}/scripts/edit_docx.py input.docx ops.json --out output.docxops.json is a list of operations:
[
{"op": "replace_run", "para": 0, "run": 0, "text": "Q3 Review"},
{"op": "replace_text", "find": "{{CLIENT}}", "with": "Acme Corp"}
]Edit at the run level, not the paragraph level — replacing whole paragraph text drops formatting. If a placeholder spans multiple runs (often happens when the original template applied bold/italic mid-word), the helper script collapses runs into the first one and clears the rest.
python-docx exposes paragraphs, tables, and runs but has limited support for
page layout, numbering definitions, and tracked changes. For those, unzip the
.docx, patch word/document.xml and adjacent parts, and repack:
mkdir _unpacked && (cd _unpacked && unzip -q ../input.docx)
# edit _unpacked/word/document.xml
(cd _unpacked && zip -q -r ../output.docx . -x "*.DS_Store")Rules when patching XML:
defusedxml.ElementTree or lxml, not stdlib xml.etree.ElementTree.
ET drops or rewrites namespace prefixes (w:, r:) in ways Word refuses to
load.xml:space="preserve" on <w:t> elements that hold leading or
trailing whitespace.[Content_Types].xml must list every part type. Removing a header without
also removing its override entry yields a "repair" prompt in Word.numbering.xml; bullet/number changes must
patch the numbering ID, not just the visible text.When done, validate by opening in LibreOffice headless before declaring success — silent failures are common.
python {baseDir}/scripts/create_docx.py spec.json --out out.docxspec.json describes content declaratively:
{
"metadata": {"title": "Q3 Review", "author": "Wei E."},
"body": [
{"kind": "heading", "level": 1, "text": "Q3 Review"},
{"kind": "paragraph", "text": "Revenue +18% YoY."},
{"kind": "table", "rows": [["Metric", "Value"], ["Revenue", "$2.1M"]]}
]
}For programmatic use call python-docx directly:
from docx import Document
doc = Document()
doc.add_heading("Q3 Review", level=1)
doc.add_paragraph("Revenue +18% YoY.")
table = doc.add_table(rows=2, cols=2)
table.rows[0].cells[0].text = "Metric"
doc.save("out.docx")See references/python_docx.md for paragraphs, styles, numbering, tables, headers/footers, and section breaks.
Tracked changes are stored in word/document.xml as <w:ins> and <w:del>
elements. python-docx does not expose them as first-class objects — the
inspect helper sets has_tracked_changes: true when any w:ins or w:del
element is found, and you must resolve them by patching XML directly. Treat
docs with tracked changes as read-only until reviewers accept or reject the
revisions.
| Symptom | Cause | Fix |
|---|---|---|
| Word reports "needs repair" | Removed a header part but left override in [Content_Types].xml | Strip the override entry too |
| Text replacement drops bold/italic | Replaced paragraph.text instead of editing runs | Use op: replace_run |
| Numbering restarts unexpectedly | Edited a list item across two abstractNum definitions | Patch numbering.xml; rebuild numbering IDs |
| Smart-quote characters render as garbage | XML read with stdlib ET dropped namespaces | Switch to defusedxml or lxml |
| Long string overflows | Cell width is fixed in the template | Either shorten or compute auto-fit before save |
.docx (OOXML WordprocessingML). It does not handle
.doc (legacy binary) or Google Docs. Convert via LibreOffice or Word
export first..docm / VBA. The runtime sandbox does not
execute embedded code, and security scanners flag mixed content..docx, hand off to LibreOffice headless or a
separate PDF skill. This skill stops at .docx.94ac35e
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.