# How to Work with DOCX Files Using Claude Skills: A Complete Guide

> Learn to work with DOCX files using Claude Skills. This guide covers high-level JavaScript creation and low-level Python OOXML editing for advanced Word document manipulation.

- Repository: [Composio/awesome-claude-skills](https://github.com/composiohq/awesome-claude-skills)
- Tags: how-to-guide
- Published: 2026-08-29

---

**Claude Skills provides a dual-language toolkit for Microsoft Word documents, combining high-level JavaScript creation via docx-js with low-level Python OOXML editing for tracked changes, comments, and complex manipulations.**

The ComposioHQ/awesome-claude-skills repository delivers a complete stack for handling `.docx` files programmatically. Whether you need to generate new Word documents from scratch or perform surgical edits with revision tracking on existing contracts, the architecture splits cleanly between **creation** (JavaScript/TypeScript) and **editing** (Python).

## Creating New DOCX Files with JavaScript

For generating fresh documents, the toolkit uses the **docx-js** library—a thin wrapper around the Office Open XML (OOXML) format. The implementation resides in [`document-skills/docx/docx-js.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/document-skills/docx/docx-js.md).

Before writing code, read the full tutorial to understand required components and style overrides. Then instantiate a `Document`, populate it with `Paragraph` and `TextRun` objects, and pack the buffer:

```javascript
const { Document, Packer, Paragraph, TextRun, HeadingLevel } = require('docx');
const fs = require('fs');

const doc = new Document({
    sections: [{
        children: [
            new Paragraph({ 
                heading: HeadingLevel.TITLE, 
                children: [new TextRun("Report Title")] 
            }),
            new Paragraph({ 
                children: [new TextRun("First paragraph of the report.")] 
            })
        ]
    }]
});

Packer.toBuffer(doc).then(buffer => 
    fs.writeFileSync("Report.docx", buffer)
);

```

The `Packer.toBuffer()` method (or `toBlob()` for browsers) handles the OOXML serialization automatically.

## Reading and Analyzing Existing DOCX Files

### Text Extraction with Pandoc

For quick plain-text analysis while preserving tracked changes, use **Pandoc** to convert the document to Markdown:

```bash
pandoc --track-changes=all path/to/file.docx -o output.md

```

This approach, documented in [`document-skills/docx/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/document-skills/docx/SKILL.md) (lines 31-40), is fastest when you only need readable content.

### Raw XML Access

When you need comments, custom formatting, or embedded media, unpack the archive and edit XML directly:

```bash
python ooxml/scripts/unpack.py <office_file.docx> <out_dir>

```

Key XML parts include [`word/document.xml`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/word/document.xml), [`word/comments.xml`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/word/comments.xml), and `word/media/`. This low-level access is required for surgical edits that preserve complex formatting.

## Editing DOCX Files with Python and OOXML

For modifying existing documents—especially those requiring **tracked changes**—use the Python **Document** class implemented in [`document-skills/docx/ooxml/scripts/document.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/document-skills/docx/ooxml/scripts/document.py). This class abstracts the OOXML boilerplate, automatically managing temporary unpacked copies, relationships, and content-type entries.

### Basic Editing Workflow

```python
from scripts.document import Document

# Unpack first (one time)

# python ooxml/scripts/unpack.py source.docx workdir

doc = Document('workdir', author="Alice", initials="AL", track_revisions=True)

# Example: change "30 days" to "45 days" while preserving formatting

node = doc["word/document.xml"].get_node(tag="w:r", contains="30 days")
rpr = node.getElementsByTagName("w:rPr")[0].toxml() if node.getElementsByTagName("w:rPr") else ""

replacement = f'''
<w:r w:rsidR="00AB12CD">{rpr}<w:t>within </w:t></w:r>
<w:del><w:r>{rpr}<w:delText>30</w:delText></w:r></w:del>
<w:ins><w:r>{rpr}<w:t>45</w:t></w:r></w:ins>
<w:r w:rsidR="00AB12CD">{rpr}<w:t> days</w:t></w:r>
'''

doc["word/document.xml"].replace_node(node, replacement)
doc.save()  # Validates and repacks automatically

```

The `Document` constructor accepts `track_revisions=True` to enable redlining mode, ensuring all modifications follow the OOXML revision tracking specification.

## Implementing Tracked Changes (Redlining)

Claude Skills enforces a strict "minimal, precise edit" policy for tracked changes:

- Surround only the *changed* text with `<w:del>` (deletion) or `<w:ins>` (insertion) tags.
- Preserve the original `<w:r>` elements for unchanged runs to maintain RSIDs (revision save IDs) and styling integrity.

Batch your edits (3-10 changes per batch) to keep debugging manageable, then call `doc.save()` once to validate against XML schemas and repack the ZIP archive.

## Adding Comments and Replies

Attach comments to specific content ranges using the `add_comment` method:

```python

# Find nodes marking the change span

start_node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id":"1"})
end_node   = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id":"2"})

doc.add_comment(
    start=start_node, 
    end=end_node, 
    text="Why this change?"
)
doc.save()

```

This modifies both [`word/document.xml`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/word/document.xml) (comment range markers) and [`word/comments.xml`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/word/comments.xml) (the comment content).

## Inserting Images and Media

Images require placement in `word/media/` plus relationship entries in `word/_rels/document.xml.rels` and content-type declarations in `[Content_Types].xml`. The Python helper automates this boilerplate:

```python
from PIL import Image
import shutil, os

# 1. Copy image to media directory

media_dir = os.path.join(doc.unpacked_path, 'word/media')
os.makedirs(media_dir, exist_ok=True)
shutil.copy('logo.png', os.path.join(media_dir, 'image1.png'))

# 2. Calculate EMUs (English Metric Units: inches × 914400)

img = Image.open(os.path.join(media_dir, 'image1.png'))
width_emus = int(6.5 * 914400)
height_emus = int(width_emus * img.size[1] / img.size[0])

# 3. Add relationship (rid generated automatically)

rels = doc['word/_rels/document.xml.rels']
rid = rels.get_next_rid()
rels.append_to(rels.dom.documentElement,
    f'<Relationship Id="{rid}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.png"/>')

# 4. Register content type

doc['[Content_Types].xml'].append_to(
    doc['[Content_Types].xml'].dom.documentElement,
    '<Default Extension="png" ContentType="image/png"/>'
)

# 5. Insert drawing markup at specific location

node = doc["word/document.xml"].get_node(tag="w:p", line_number=100)

# ... (drawing XML insertion code)

```

See [`document-skills/docx/ooxml.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/document-skills/docx/ooxml.md) (lines 44-70) for the complete drawing markup template.

## Converting DOCX to Images for Visual Inspection

For AI visual verification or human review, convert documents to JPEGs via PDF:

```bash

# Convert to PDF

soffice --headless --convert-to pdf document.docx

# Extract pages as images

pdftoppm -jpeg -r 150 document.pdf page

```

This workflow, detailed in [`document-skills/docx/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/document-skills/docx/SKILL.md) (lines 56-81), produces 150 DPI JPEGs suitable for previewing layout changes.

## Required Dependencies

Install these tools before working with DOCX files using Claude Skills:

| Tool | Purpose | Install Command |
|------|---------|-----------------|
| **pandoc** | Text extraction | `sudo apt-get install pandoc` |
| **docx** (npm) | JavaScript creation | `npm install -g docx` |
| **LibreOffice** | PDF conversion | `sudo apt-get install libreoffice` |
| **poppler-utils** | PDF to image (`pdftoppm`) | `sudo apt-get install poppler-utils` |
| **defusedxml** | Secure XML parsing | `pip install defusedxml` |

## Summary

- **Use JavaScript** (`docx-js`) via [`document-skills/docx/docx-js.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/document-skills/docx/docx-js.md) when creating new documents from templates or scratch.
- **Use Python** (`Document` class in [`ooxml/scripts/document.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/ooxml/scripts/document.py)) when editing existing files with tracked changes, comments, or image insertions.
- **Unpack first** using [`ooxml/scripts/unpack.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/ooxml/scripts/unpack.py) before Python editing, then let `doc.save()` handle repacking and validation.
- **Preserve formatting** during edits by extracting existing `<w:rPr>` run properties and re-injecting them into replacement XML.
- **Validate changes** against OOXML schemas in `ooxml/scripts/validation/` to ensure Microsoft Word compatibility.

## Frequently Asked Questions

### How do I preserve tracked changes when converting DOCX to Markdown?

Use Pandoc with the `--track-changes=all` flag: `pandoc --track-changes=all input.docx -o output.md`. This preserves insertion and deletion markup in the Markdown output, allowing Claude to see the edit history even in plain text format.

### Can I edit a DOCX file without unpacking it first?

No. The Python OOXML workflow requires unpacking the ZIP archive first using `python ooxml/scripts/unpack.py <file.docx> <directory>`. The `Document` class then operates on the unpacked XML files and repacks them automatically when you call `doc.save()`.

### What is the difference between `w:delText` and `w:t` in tracked changes?

Use `<w:delText>` inside `<w:del>` elements to mark deleted content, and `<w:t>` inside `<w:ins>` elements for inserted content. This distinction allows Microsoft Word to render deletions with strikethrough while correctly identifying new text as insertions.

### How do I calculate image dimensions for OOXML?

OOXML uses English Metric Units (EMUs), where 1 inch = 914,400 EMUs. Calculate width in EMUs as `inches * 914400`, then derive height proportionally: `height_emus = width_emus * (original_height / original_width)`. Always use integer values for the final attributes.