---
name: docx
description: Create, read, and edit Word documents (.docx) via python-docx and pandoc
metadata:
  activation:
    keywords: [word document, docx, word doc, .docx]
    patterns:
      - "(?i)\\b(create|write|edit|read|open|convert|generate)\\b.{0,30}\\b(word|docx|document)\\b"
      - "(?i)\\b(report|memo|letter|template|proposal|resume|cv)\\b.{0,20}\\b(word|docx|\\.docx)\\b"
      - "(?i)\\.docx\\b"
    # Auto-inject when the user uploads a Word doc — the agent loop
    # scores the current turn's attachments against this list, so
    # "summarize this" + report.docx attached triggers without needing
    # the user to spell out "docx".
    extensions: [docx]
    mimes:
      - application/vnd.openxmlformats-officedocument.wordprocessingml.document
  requires:
    tools: [shell]
    packages: [docx]  # dist: python-docx, imports as `docx`
---

# Word Document (.docx) Workflows

## Overview

A `.docx` file is a ZIP archive of XML files (OOXML format). Choose the right tool for each task.

## Quick Reference

| Task | Tool | Install |
|------|------|---------|
| Read/extract text | `pandoc` | `choco install pandoc` / `brew` / `apt` |
| Create new document | `python-docx` | `pip install python-docx` |
| Edit existing (simple) | `python-docx` | `pip install python-docx` |
| Edit existing (precise) | Unpack ZIP → edit XML → repack | Built-in `zipfile` |
| Convert .doc → .docx | LibreOffice headless | System package |
| Convert to PDF | LibreOffice headless | System package |

## Reading Content

Pandoc is a standalone binary — install via system package manager (`choco install pandoc`, `brew install pandoc`, `apt install pandoc`), not pip.

```bash
# Extract text with pandoc (preserves structure)
pandoc document.docx -t markdown -o output.md

# Extract with tracked changes visible
pandoc --track-changes=all document.docx -o output.md

# Quick text dump with python
python -c "
from docx import Document
doc = Document('document.docx')
for p in doc.paragraphs:
    print(p.text)
"
```

## Creating New Documents

Use `python-docx` for programmatic creation:

```python
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH

doc = Document()

# Title
doc.add_heading('Document Title', level=0)

# Paragraph with formatting
p = doc.add_paragraph()
run = p.add_run('Bold text ')
run.bold = True
p.add_run('and normal text.')

# Table
table = doc.add_table(rows=2, cols=3, style='Table Grid')
table.cell(0, 0).text = 'Header 1'

# Image
doc.add_picture('image.png', width=Inches(4))

# Page break
doc.add_page_break()

doc.save('output.docx')
```

### Key patterns

- **Headings**: `doc.add_heading('Title', level=1)` (0=Title, 1-9=Heading levels)
- **Lists**: `doc.add_paragraph('Item', style='List Bullet')` or `'List Number'`
- **Tables**: Always set a style (`'Table Grid'`, `'Light Shading'`, etc.)
- **Fonts**: Set via `run.font.name`, `run.font.size = Pt(12)`
- **Colors**: `run.font.color.rgb = RGBColor(0, 0, 255)`
- **Alignment**: `paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER`
- **Page size**: Use `section.page_width`, `section.page_height` (in EMU: 914400 = 1 inch)

### Page setup

```python
from docx.shared import Inches
section = doc.sections[0]
section.page_width = Inches(8.5)   # US Letter
section.page_height = Inches(11)
section.top_margin = Inches(1)
section.bottom_margin = Inches(1)
section.left_margin = Inches(1)
section.right_margin = Inches(1)
```

## Editing Existing Documents

### Simple edits (python-docx)

```python
from docx import Document

doc = Document('existing.docx')

# Replace text in paragraphs
for p in doc.paragraphs:
    if 'OLD_TEXT' in p.text:
        for run in p.runs:
            run.text = run.text.replace('OLD_TEXT', 'NEW_TEXT')

# Add content at end
doc.add_paragraph('New paragraph at the end.')

doc.save('modified.docx')
```

**Limitations of python-docx**: Does not support tracked changes, comments, advanced headers/footers, or some complex formatting. For those, use XML editing.

### Precise XML editing (advanced)

For edits that python-docx cannot handle:

```python
import zipfile
import shutil
from pathlib import Path
from lxml import etree  # pip install lxml

# 1. Unpack
src = Path('document.docx')
work_dir = Path('unpacked')
with zipfile.ZipFile(src) as zf:
    zf.extractall(work_dir)

# 2. Edit XML (e.g., word/document.xml)
ns = {'w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'}
tree = etree.parse(str(work_dir / 'word' / 'document.xml'))
# ... modify tree ...
tree.write(str(work_dir / 'word' / 'document.xml'), xml_declaration=True, encoding='UTF-8')

# 3. Repack (preserve original ZIP structure)
with zipfile.ZipFile('output.docx', 'w', zipfile.ZIP_DEFLATED) as zf:
    for file_path in work_dir.rglob('*'):
        if file_path.is_file():
            zf.write(file_path, file_path.relative_to(work_dir))
```

Key XML namespaces:
- `w:` — `http://schemas.openxmlformats.org/wordprocessingml/2006/main`
- `r:` — `http://schemas.openxmlformats.org/officeDocument/2006/relationships`
- `wp:` — `http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing`

## Converting Formats

```bash
# .doc to .docx
libreoffice --headless --convert-to docx document.doc

# .docx to PDF
libreoffice --headless --convert-to pdf document.docx

# .docx to HTML
pandoc document.docx -o output.html
```

## Best Practices

- **Always set page size explicitly** — defaults vary by locale (A4 vs US Letter)
- **Prefer python-docx for new documents** — cleaner API, fewer errors
- **Use XML editing only for precise modifications** — tracked changes, comments, complex formatting
- **Test output** — open generated files in Word/LibreOffice to verify rendering
- **Preserve relationships** — when editing XML, don't break `_rels` files
- **Back up originals** — always save to a new filename when editing
