BundledProductivityVersion 1.1.0

Docx Skill: Create, Edit, and Review Word Documents with Hermes Agent

Create, read, edit, template, and review Word .docx files.

Written by Neura Market from the official Hermes Agent documentation for Docx. Commands, paths, and version numbers are reproduced from the source unchanged.

Read the official documentation

The Docx skill turns Hermes Agent into a Word document workshop. You hand it a JSON spec and it produces a .docx; you point it at an existing file and it reads, edits, templates, and reviews it. This is the tool to reach for when a user asks for a report, letter, or contract, or when you need to pull text, styles, or images out of a .docx without opening Word.

What it does

The skill wraps python-docx in a set of small command-line scripts. Each script does one job and prints JSON to stdout, so you can chain them together or inspect results programmatically. You can create documents from a structured spec, read back their content and structure, edit text and formatting, fill templates with data, review tracked changes, manage comments, and check the health of a .docx package.

It handles the common building blocks of a Word document: paragraphs, headings, lists, tables, images, headers and footers, and custom styles. It also understands the parts of a document that usually require manual Word work: tracked changes (insertions and deletions), comments, table of contents fields, and "Page X of Y" footers. The skill does not render documents to PDF, and it does not touch legacy .doc files.

Before you start

You need Python 3.10 or newer with python-docx installed. The import name is docx, and lxml comes along with it. Install it with:

pip install python-docx

For adding comments, the skill uses the native API on python-docx 1.2 and newer, and falls back to an XML approach on older versions. Both paths are automatic, so you do not need to configure anything.

If you plan to embed images, the image files must already exist locally and be in PNG or JPEG format. The skill does not fetch or convert images for you.

All helper scripts live in a scripts/ directory next to the skill file. You run them with the terminal tool. Every script supports --help, and each prints JSON to stdout.

How to run the scripts

The skill ships with seven scripts. Here is the full set of entry points:

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

Each script has a specific purpose. docx_create.py builds a new document from a JSON spec. docx_read.py extracts information from an existing document. docx_edit.py modifies a document in place or writes a new one. docx_template.py fills placeholders. docx_revisions.py lists and resolves tracked changes. docx_comments.py manages comments. docx_validate.py checks the package health.

Quick reference

The table below summarizes the most common operations. You will use these commands constantly, so keep it handy.

TaskCommand
Create from JSON specdocx_create.py spec.json out.docx
Full text (body+tables+headers/footers)docx_read.py f.docx --text
Heading outline + table shapesdocx_read.py f.docx --structure
Styles actually useddocx_read.py f.docx --styles
Extract embedded imagesdocx_read.py f.docx --images outdir/
Detect tracked changes/commentsdocx_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 celldocx_edit.py set-cell f.docx --table 0 --row 1 --col 2 --text X
Insert paragraph before index Ndocx_edit.py insert f.docx --index N --text X --style Normal
Delete paragraph Ndocx_edit.py delete f.docx --index N
Apply style to paragraph Ndocx_edit.py style f.docx --index N --style "Heading 1"
Merge equal-format adjacent runsdocx_edit.py normalize f.docx -o out.docx
Insert TOC field before para Ndocx_edit.py toc f.docx --index N -o out.docx
"Page X of Y" footer fieldsdocx_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 revisionsdocx_revisions.py accept-all f.docx -o out.docx (or reject-all)
Accept / reject one revisiondocx_revisions.py accept f.docx --id 3 -o out.docx
List comments (+anchored text)docx_comments.py list f.docx
Add comment anchored to textdocx_comments.py add f.docx --target "phrase" --text "note" --author You
Delete comment by iddocx_comments.py delete f.docx --id 0
Health-check the packagedocx_validate.py f.docx (exit 1 on errors)

Creating a document

To create a document, you first write a JSON spec file using write_file, then run docx_create.py with that spec and an output path. The spec is the blueprint for the entire document.

The spec supports these top-level keys:

  • page: page size and margins in millimeters.
  • header and footer: strings that appear on every page.
  • footer_page_numbers: adds a "Page X of Y" field footer.
  • styles: custom paragraph styles with font, size, bold/italic, and hex color.
  • blocks: the content of the document, in order.

Each block can be one of several types:

  • heading: with a level from 1 to 9.
  • paragraph: either a plain text string or a runs list where each run can set bold, italic, or underline.
  • bullet_list and numbered_list: for lists.
  • table: with a header row (rendered bold), rows, and an optional built-in table style such as Table Grid.
  • image: with a path and optional width_mm.
  • toc: a Table of Contents field.
  • page_break: forces a page break.

The full spec format is documented at the top of scripts/docx_create.py. When you are unsure about a key or value, read that header comment first.

Reading a document

docx_read.py extracts information from an existing .docx. You must pass exactly one mode flag. The modes are:

  • --text: returns body paragraphs, all table cell text, and header/footer text as JSON.
  • --structure: returns the heading outline plus paragraph, table, and section counts.
  • --styles: lists the styles actually used in the document.
  • --images DIR: copies every file under word/media/ out of the package into the given directory.
  • --revisions: detects tracked changes and comments.

Use --text when you need the full content, --structure when you need an outline, and --styles when you need to confirm which styles are applied. The --images mode is handy when you need to extract embedded pictures.

Editing an existing document

docx_edit.py is the workhorse for modifications. It supports several subcommands:

  • replace: walks the body, tables (including nested ones), headers, and footers, and replaces text while preserving run formatting. Add --body-only to skip headers and footers. Pass -o out.docx to keep the original file; omit it to edit in place.
  • set-cell: sets the text of a specific table cell. The command takes --table, --row, --col, and --text.
  • insert: inserts a new paragraph before a given index. The --style option sets the paragraph style.
  • delete: removes the paragraph at the given index.
  • style: applies a style to the paragraph at the given index.
  • normalize: merges adjacent runs with identical formatting. Run this first on documents that came out of heavy Word editing, so later find-replace matches reliably.
  • toc: inserts a Table of Contents field before a given paragraph index.
  • page-numbers: adds "Page X of Y" footer fields.

Paragraph indices for insert, delete, style, and toc refer to the body order shown by --structure or --text. Count from zero.

Reviewing tracked changes

docx_revisions.py handles tracked changes. The list subcommand reports every insertion (w:ins) and deletion (w:del) anywhere in the body, tables, headers, or footers. Each entry includes the id, author, date, and affected text.

To resolve changes in bulk, use accept-all or reject-all. To handle a single revision, use accept --id N or reject --id N. Accepting keeps insertions and drops deleted text; rejecting does the reverse. Always write the result to a new file with -o out.docx so you can compare.

Managing comments

docx_comments.py works with comments. The list subcommand returns each comment's id, author, date, body text, and the document text it is anchored to.

To add a comment, use add --target "some phrase" --text "note" --author You. The comment anchors to the first occurrence of that phrase. The script splits runs as needed and preserves formatting. To remove a comment, use delete --id N, which removes the comment and its markers without touching the document text.

Filling templates

Templating is straightforward. Put {{name}}-style tokens in the document, then run docx_template.py with a JSON object of values. The script replaces each token with its corresponding value.

Use --strict to fail when tokens remain unfilled. The JSON output lists filled counts and unfilled_tokens either way, so you can check the result programmatically.

Verifying your work

Always re-read the output after any operation. Run docx_read.py out.docx --text and check that the expected strings appear and old strings are gone. After accept/reject, docx_revisions.py list should return [] (or only the ids you intentionally left). After comment surgery, docx_comments.py list should reflect the change, and --text output must be unchanged.

Run docx_validate.py out.docx on anything you produced via revision or comment surgery. It exits 0 with "ok": true on a healthy package. For templates run with --strict, or check unfilled_tokens == []. Use --structure to confirm the heading outline and table shapes, and --styles to confirm custom styles applied.

Converting to PDF

The skill does not render PDFs. When LibreOffice is installed, you can convert headlessly with:

soffice --headless --convert-to pdf --outdir outdir/ file.docx

Check availability first with 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.

When not to use it

This skill is not for legacy .doc files, .odt files, or WYSIWYG layout work. If the user needs precise visual positioning or pixel-perfect design, a different tool is required. For PDF output, you need LibreOffice installed separately.

Limits and gotchas

Several pitfalls can trip you up. Knowing them in advance saves debugging time.

  • Tokens split across runs. Word often fragments text into several runs. The replace helpers collapse matched runs, and the replacement inherits the first run's formatting. Running docx_edit.py normalize first reduces fragmentation for all later edits.
  • Revision coverage. docx_revisions.py resolves run-level insertions and deletions, which are the overwhelming majority. Paragraph-mark and table-row revisions, format-change records, and moves are detected by --revisions but not auto-resolved. See references/revisions-and-comments.md and 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 the toc/footer_page_numbers spec options write field codes. Word or 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.py verifies 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 like Heading 1, List Bullet, List Number, and Table Grid exist in the default template. Custom styles must be declared in the create spec first.
  • Numbered lists restart. List Number relies 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-cell uses cell.text = ..., which resets runs in that cell to plain formatting.
  • Encoding. All JSON specs and 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.xml corrupts files easily. Use patch or write_file only for the JSON inputs, never on the .docx itself.

What pairs with this

The Docx skill sits alongside other productivity skills in the Hermes Agent bundle. The related skills are pdf, xlsx, and powerpoint. Use them together to handle a full suite of office documents: generate a report in Word, convert it to PDF, or pull data from a spreadsheet to fill a template.

Skills the docs pair this with

More Productivity skills