How to Use the docx Skill to Create Word Documents Programmatically

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 file at 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 – Runs schema validation against Microsoft Office Open XML schemas and auto-repairs broken relationship IDs.
  • unpack.py – Extracts the ZIP archive, prettifies XML, merges adjacent text runs, and converts smart quotes for reliable find-and-replace operations.
  • 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:

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:

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:

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

The 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:

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

The pack.py script automatically runs 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 script in 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:

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), 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 for extraction, manual or scripted XML editing, and pack.py for repackaging with automatic validation.
  • Quality assurance is handled by validate.py for schema compliance and 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.

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.

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), 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 (located at skills/docx/scripts/office/pack.py) is responsible for re-assembling unpacked XML directories into .docx files and optionally running validation. validate.py (at 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →