10 KiB
name, description, version, author, license, platforms, metadata
| name | description | version | author | license | platforms | metadata | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| docx | Create, read, edit, template, and review Word .docx files. | 1.1.0 | Nous Research | MIT |
|
|
Docx Skill
Create, read, edit, and template Microsoft Word .docx files with
python-docx via small CLIs. It handles text, styles, lists, tables,
images, headers/footers, {{token}} templating, tracked changes
(list/accept/reject), comments (list/add/delete), TOC and page-number
fields, and package health checks. It does not render documents itself
(PDF needs LibreOffice — see Converting to PDF) or edit legacy .doc.
When to Use
- The user asks to generate a Word document (report, letter, contract).
- You need the text, outline, styles, or embedded images of a
.docx. - You must change an existing
.docx: replace text, edit table cells, insert/delete paragraphs, apply styles, merge fragmented runs. - You have a
.docxtemplate with{{placeholders}}to fill from data. - The document has tracked changes to review, accept, or reject.
- You need to read reviewers' comments, or add/delete comments.
- A
.docxwon't open or behaves oddly and you need corruption triage. - The document needs a table of contents or "Page X of Y" footers.
- Not for:
.doc(legacy),.odt, or WYSIWYG layout work.
Prerequisites
- Python 3.10+ with
python-docxinstalled:pip install python-docx(import name isdocx; lxml comes with it). - Comments
adduses the native API on python-docx >= 1.2 and an XML fallback on older versions — both are automatic. - For image blocks: the image files must exist locally (PNG/JPEG).
How to Run
All helpers live in scripts/ next to this file. Run them with the
terminal tool; each supports --help and prints JSON to stdout.
python scripts/docx_create.py spec.json out.docx
python scripts/docx_read.py out.docx --text
python scripts/docx_edit.py replace out.docx --find old --replace new
python scripts/docx_template.py tpl.docx values.json filled.docx
python scripts/docx_revisions.py list out.docx
python scripts/docx_comments.py list out.docx
python scripts/docx_validate.py out.docx
Quick Reference
| Task | Command |
|---|---|
| Create from JSON spec | docx_create.py spec.json out.docx |
| Full text (body+tables+headers/footers) | docx_read.py f.docx --text |
| Heading outline + table shapes | docx_read.py f.docx --structure |
| Styles actually used | docx_read.py f.docx --styles |
| Extract embedded images | docx_read.py f.docx --images outdir/ |
| Detect tracked changes/comments | docx_read.py f.docx --revisions |
| Find/replace (formatting kept) | docx_edit.py replace f.docx --find A --replace B -o out.docx |
| Set a table cell | docx_edit.py set-cell f.docx --table 0 --row 1 --col 2 --text X |
| Insert paragraph before index N | docx_edit.py insert f.docx --index N --text X --style Normal |
| Delete paragraph N | docx_edit.py delete f.docx --index N |
| Apply style to paragraph N | docx_edit.py style f.docx --index N --style "Heading 1" |
| Merge equal-format adjacent runs | docx_edit.py normalize f.docx -o out.docx |
| Insert TOC field before para N | docx_edit.py toc f.docx --index N -o out.docx |
| "Page X of Y" footer fields | docx_edit.py page-numbers f.docx |
Fill {{tokens}} |
docx_template.py tpl.docx values.json out.docx --strict |
| List revisions (id/author/date/text) | docx_revisions.py list f.docx |
| Accept / reject all revisions | docx_revisions.py accept-all f.docx -o out.docx (or reject-all) |
| Accept / reject one revision | docx_revisions.py accept f.docx --id 3 -o out.docx |
| List comments (+anchored text) | docx_comments.py list f.docx |
| Add comment anchored to text | docx_comments.py add f.docx --target "phrase" --text "note" --author You |
| Delete comment by id | docx_comments.py delete f.docx --id 0 |
| Health-check the package | docx_validate.py f.docx (exit 1 on errors) |
Procedure
- Create. Write a JSON spec with
write_file, then runscripts/docx_create.py. The spec supports:page(size + margins in mm),header/footerstrings,footer_page_numbers(adds a "Page X of Y" field footer),styles(custom paragraph styles with font, size, bold/italic, hexcolor), andblocks—heading(level 1-9),paragraph(eithertextor arunslist where each run may setbold/italic/underline),bullet_list,numbered_list,table(headerrow rendered bold,rows, optional built-in tablestylesuch asTable Grid),image(path, optionalwidth_mm),toc(Table of Contents field), andpage_break. The full spec format is documented at the top ofscripts/docx_create.py. - Read. Use
scripts/docx_read.pywith exactly one mode flag.--textreturns body paragraphs, all table cell text, and header/footer text as JSON.--structurereturns the heading outline plus paragraph/table/section counts.--images DIRcopies every file underword/media/out of the package. - Edit. Use
scripts/docx_edit.py.replacewalks body, tables (nested included), headers and footers, and preserves run formatting; add--body-onlyto skip headers/footers. Pass-o out.docxto keep the original; omit it to edit in place. Paragraph indices forinsert/delete/style/tocrefer to--structure/--textbody order. Runnormalizefirst on documents that came out of heavy Word editing — it merges adjacent runs with identical formatting so later find-replace matches reliably. - Review revisions.
docx_revisions.py listreports everyw:insandw:del(id, author, date, affected text) anywhere in body, tables, headers, or footers.accept-all/reject-allresolve them in bulk;accept/reject --id Nhandles a single revision. Accept keeps insertions and drops deleted text; reject does the reverse. - Comments.
docx_comments.py listreturns each comment's id, author, date, body text, and the document text it is anchored to.add --target "some phrase"anchors a new comment to the first occurrence of that phrase (runs are split as needed; formatting is preserved).delete --id Nremoves the comment and its markers without touching document text. - Template. Put
{{name}}-style tokens in the document. Runscripts/docx_template.pywith a JSON object of values. Use--strictto fail when tokens remain unfilled; the JSON output listsfilledcounts andunfilled_tokenseither way. - Verify (always): re-read the output with
--textor--structure, and rundocx_validate.pyon anything you produced via revision/comment surgery.
Converting to PDF
No script needed. When LibreOffice is installed, convert headlessly:
soffice --headless --convert-to pdf --outdir outdir/ file.docx
Check availability first (command -v soffice || command -v libreoffice). If neither exists, tell the user PDF conversion is
unavailable in this environment rather than improvising — python-docx
cannot render PDFs, and layout fidelity requires a real renderer.
Pitfalls
- Tokens split across runs. Word often fragments text into several
runs. The replace helpers collapse matched runs (replacement inherits
the first run's formatting); running
docx_edit.py normalizefirst reduces fragmentation for all later edits. - Revision coverage.
docx_revisions.pyresolves run-level insertions and deletions (the overwhelming majority). Paragraph-mark and table-row revisions, format-change records, and moves are detected by--revisionsbut not auto-resolved — seereferences/revisions-and-comments.mdand hand those to Word. - Comment threading. Replies and "resolved" status live in
commentsExtended.xml, which this skill ignores; comments it adds are plain top-level comments. - Field results are computed by Word.
toc,page-numbers, and thetoc/footer_page_numbersspec options write field codes. Word/LibreOffice populates the actual entries and numbers when the file is opened (Word may prompt to update fields); python-docx never computes them, so placeholder text shows until then. - Validation is a health check, not schema validation.
docx_validate.pyverifies the zip, required parts, relationship targets, image magic bytes, and referenced styles. It is NOT XSD validation — a file can pass and still contain XML Word dislikes. - Style names must exist. Applying a style that isn't defined in the
document raises
KeyError. Built-ins likeHeading 1,List Bullet,List Number,Table Gridexist in the default template; custom styles must be declared in the create spec first. - Numbered lists restart.
List Numberrelies on Word's default numbering; separate lists in one document may continue numbering instead of restarting. Warn users needing precise multi-list numbering. - Cell writes replace formatting.
set-cellusescell.text = ..., which resets runs in that cell to plain formatting. - Encoding. All JSON specs/values files are read as UTF-8 explicitly; never rely on locale defaults when writing your own glue code.
- Don't unzip-and-sed the XML. Edit through the scripts (or
python-docx); raw text substitution in
document.xmlcorrupts files easily. Usepatch/write_fileonly for the JSON inputs, never on the.docxitself.
Verification
- After create/edit/template, run
docx_read.py out.docx --textand check the expected strings appear (and old strings are gone). - After accept/reject,
docx_revisions.py listshould return[](or only the ids you intentionally left); after comment surgery,docx_comments.py listshould reflect the change and--textoutput must be unchanged. docx_validate.py out.docxexits 0 with"ok": trueon a healthy package — run it after any revision/comment/field manipulation.- For templates run with
--strict, or checkunfilled_tokens == []. - Structure checks:
--structureshould show the expected heading outline and table shapes;--stylesconfirms custom styles applied.