# How to Use the docx Skill to Create Word Documents Programmatically

> Learn to create Word documents programmatically using the docx skill. Combine JavaScript and Python to generate and edit Word files effortlessly.

- Repository: [Anthropic/skills](https://github.com/anthropics/skills)
- Tags: how-to-guide
- Published: 2026-02-16

---

**The docx skill combines JavaScript's `docx` library with Python validation scripts to generate, edit, and validate Microsoft Word files through a declarative three-layer architecture.**

The `anthropics/skills` repository provides a self-contained **docx skill** that enables programmatic creation of `.docx` files. Whether you need to generate reports from templates or build complex documents with tables and images, this skill offers a structured workflow using the open-source `docx` NPM package alongside Python utilities for validation and repair.

## Architectural Overview of the docx Skill

The docx skill follows a three-layer architecture designed to ensure cross-platform compatibility with Microsoft Word, Google Docs, and LibreOffice.

### Specification Layer

The [`SKILL.md`](https://github.com/anthropics/skills/blob/main/SKILL.md) file at [`skills/docx/SKILL.md`](https://github.com/anthropics/skills/blob/main/skills/docx/SKILL.md) defines the skill's purpose, triggers, and high-level workflows. It specifies critical conventions such as using **DXA units** (twentieths of a point) for measurements and requiring explicit page sizes to avoid default A4 formatting.

### Generation Layer

JavaScript code utilizes the `docx` NPM package to assemble document models including sections, paragraphs, tables, images, headers, footers, and tables of contents. The library writes binary `.docx` files that conform to Office Open XML standards.

### Validation & Packaging Layer

Python helper scripts in `skills/docx/scripts/office/` handle post-processing:

- **[`validate.py`](https://github.com/anthropics/skills/blob/main/validate.py)** – Runs schema validation against Microsoft Office Open XML schemas and auto-repairs broken relationship IDs.
- **[`unpack.py`](https://github.com/anthropics/skills/blob/main/unpack.py)** – Extracts the ZIP archive, prettifies XML, merges adjacent text runs, and converts smart quotes for reliable find-and-replace operations.
- **[`pack.py`](https://github.com/anthropics/skills/blob/main/pack.py)** – Re-assembles XML into a `.docx` file, optionally running validation and preserving original file metadata.

## Creating New Documents with JavaScript

### Installing Dependencies

First, install the `docx` library globally or in your project:

```bash
npm install docx

```

### Building a Complete Document Example

The following example demonstrates the strict conventions required by the skill, including dual-width table definitions, explicit page sizing, and proper list formatting:

```javascript
const {
  Document, Packer, Paragraph, TextRun, HeadingLevel,
  PageOrientation, WidthType, Table, TableRow, TableCell,
  BorderStyle, ShadingType, ImageRun, PageBreak, Header, Footer, PageNumber, TableOfContents, LevelFormat
} = require('docx');
const fs = require('fs');

const doc = new Document({
  sections: [{
    properties: {
      page: {
        size: {
          width: 12240,   // US Letter width in DXA (8.5")
          height: 15840,  // US Letter height in DXA (11")
          orientation: PageOrientation.PORTRAIT
        },
        margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }
      }
    },
    headers: {
      default: new Header({
        children: [new Paragraph({ children: [new TextRun('My Header')] })]
      })
    },
    footers: {
      default: new Footer({
        children: [new Paragraph({
          children: [new TextRun('Page '), new TextRun({ children: [PageNumber.CURRENT] })]
        })]
      })
    },
    children: [
      // Title
      new Paragraph({
        heading: HeadingLevel.HEADING_1,
        children: [new TextRun('Quarterly Report')]
      }),

      // Table of Contents (auto-generated on open)
      new Paragraph({
        children: [
          new TableOfContents('Table of Contents', {
            hyperlink: true,
            headingStyleRange: '1-3'
          })
        ]
      }),

      // Simple bullet list using LevelFormat.BULLET
      new Paragraph({
        numbering: { reference: 'bullets', level: 0 },
        children: [new TextRun('First bullet')]
      }),
      new Paragraph({
        numbering: { reference: 'bullets', level: 0 },
        children: [new TextRun('Second bullet')]
      }),

      // Table with dual width rule (columnWidths + per-cell width)
      new Table({
        width: { size: 9360, type: WidthType.DXA },        // 9.36 in total (US Letter - 2 in margins)
        columnWidths: [4680, 4680],
        rows: [
          new TableRow({
            children: [
              new TableCell({
                width: { size: 4680, type: WidthType.DXA },
                borders: { top: { style: BorderStyle.SINGLE, size: 1, color: 'CCCCCC' } },
                shading: { type: ShadingType.CLEAR, fill: 'D5E8F0' },
                margins: { top: 80, bottom: 80, left: 120, right: 120 },
                children: [new Paragraph('Header 1')]
              }),
              new TableCell({
                width: { size: 4680, type: WidthType.DXA },
                borders: { top: { style: BorderStyle.SINGLE, size: 1, color: 'CCCCCC' } },
                shading: { type: ShadingType.CLEAR, fill: 'D5E8F0' },
                margins: { top: 80, bottom: 80, left: 120, right: 120 },
                children: [new Paragraph('Header 2')]
              })
            ]
          })
        ]
      }),

      // Image with mandatory type field
      new Paragraph({
        children: [
          new ImageRun({
            type: 'png',
            data: fs.readFileSync('logo.png'),
            transformation: { width: 200, height: 150 },
            altText: { title: 'Logo', description: 'Company logo', name: 'logo' }
          })
        ]
      }),

      // Page break
      new Paragraph({ children: [new PageBreak()] }),

      // Closing paragraph
      new Paragraph('End of report.')
    ]
  }]
});

// Write the .docx file
Packer.toBuffer(doc).then(buffer => {
  fs.writeFileSync('QuarterlyReport.docx', buffer);
});

```

**Critical conventions demonstrated:**
- **Explicit page sizing**: Set to US Letter (12240×15840 DXA) rather than relying on defaults.
- **Dual-width tables**: Both `columnWidths` array and per-cell `width` properties use `WidthType.DXA`.
- **Proper list formatting**: Uses `LevelFormat.BULLET` via the `numbering` configuration instead of raw Unicode characters.
- **Image requirements**: The `type` field is mandatory for `ImageRun`.

## Editing Existing Word Documents

### Unpacking and Modifying Templates

For template-based workflows, use the Python helper scripts to manipulate existing files. First, unpack the document:

```bash
python skills/docx/scripts/office/unpack.py Template.docx unpacked/

```

The [`unpack.py`](https://github.com/anthropics/skills/blob/main/unpack.py) script normalizes smart quotes, merges adjacent text runs, and prettifies the XML structure, making it suitable for reliable find-and-replace operations.

### Repacking and Validating

After editing the XML files (for example, replacing `{{TITLE}}` with actual content), repackage the document:

```bash
python skills/docx/scripts/office/pack.py unpacked/ NewDocument.docx --original Template.docx

```

The [`pack.py`](https://github.com/anthropics/skills/blob/main/pack.py) script automatically runs [`validate.py`](https://github.com/anthropics/skills/blob/main/validate.py) to ensure schema compliance. You can skip validation with `--validate false` if you are certain the XML is clean.

## Validating Document Integrity

The [`validate.py`](https://github.com/anthropics/skills/blob/main/validate.py) script in [`skills/docx/scripts/office/validate.py`](https://github.com/anthropics/skills/blob/main/skills/docx/scripts/office/validate.py) performs schema validation against Microsoft Office Open XML standards and auto-repairs common issues such as broken relationship IDs.

For documents with tracked changes, use the accept changes helper:

```bash
python skills/docx/scripts/accept_changes.py Draft.docx Cleaned.docx

```

This script uses LibreOffice in headless mode to apply all insertions and deletions, producing a clean final document.

## Summary

- The **docx skill** provides a three-layer architecture: specification ([`SKILL.md`](https://github.com/anthropics/skills/blob/main/SKILL.md)), generation (`docx` NPM package), and validation (Python scripts).
- **New documents** are built using JavaScript with strict conventions: explicit DXA units, dual-width table definitions, and proper list formatting via `LevelFormat`.
- **Existing documents** are modified using [`unpack.py`](https://github.com/anthropics/skills/blob/main/unpack.py) for extraction, manual or scripted XML editing, and [`pack.py`](https://github.com/anthropics/skills/blob/main/pack.py) for repackaging with automatic validation.
- **Quality assurance** is handled by [`validate.py`](https://github.com/anthropics/skills/blob/main/validate.py) for schema compliance and [`accept_changes.py`](https://github.com/anthropics/skills/blob/main/accept_changes.py) for finalizing tracked changes.

## Frequently Asked Questions

### What is the docx skill in the anthropics/skills repository?

The docx skill is a self-contained module that enables programmatic generation, editing, and validation of Microsoft Word documents. It combines JavaScript generation via the `docx` NPM package with Python helper scripts for XML unpacking, schema validation, and repackaging, following strict conventions defined in [`skills/docx/SKILL.md`](https://github.com/anthropics/skills/blob/main/skills/docx/SKILL.md).

### Why must I use DXA units when creating tables with the docx skill?

DXA (twentieths of a point) is the native measurement unit in Office Open XML. The docx skill requires explicit DXA values for table widths and cell widths to ensure documents render identically across Microsoft Word, Google Docs, and LibreOffice. Using relative percentages or default units often causes layout inconsistencies or validation errors when processed by [`validate.py`](https://github.com/anthropics/skills/blob/main/validate.py).

### How do I edit an existing Word template using the docx skill helper scripts?

First, run `python skills/docx/scripts/office/unpack.py Template.docx unpacked/` to extract the ZIP archive and normalize the XML structure. Edit the extracted XML files (such as replacing placeholder text in [`document.xml`](https://github.com/anthropics/skills/blob/main/document.xml)), then repackage with `python skills/docx/scripts/office/pack.py unpacked/ NewDocument.docx --original Template.docx`. The pack script automatically runs schema validation to ensure the output is compliant.

### What is the difference between pack.py and validate.py in the docx skill?

[`pack.py`](https://github.com/anthropics/skills/blob/main/pack.py) (located at [`skills/docx/scripts/office/pack.py`](https://github.com/anthropics/skills/blob/main/skills/docx/scripts/office/pack.py)) is responsible for re-assembling unpacked XML directories into `.docx` files and optionally running validation. [`validate.py`](https://github.com/anthropics/skills/blob/main/validate.py) (at [`skills/docx/scripts/office/validate.py`](https://github.com/anthropics/skills/blob/main/skills/docx/scripts/office/validate.py)) is a dedicated schema validator that checks Office Open XML compliance, auto-repairs broken relationship IDs, and can be run independently or automatically via [`pack.py`](https://github.com/anthropics/skills/blob/main/pack.py).