claude/skills/docx/SKILL.md
Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks
npx skillsauth add lanej/dotfiles docxInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A user may ask you to create, edit, or analyze the contents of a .docx file. A .docx file is essentially a ZIP archive containing XML files and other resources that you can read or edit. You have different tools and workflows available for different tasks.
Use "Text extraction" or "Raw XML access" sections below
Use "Creating a new Word document" workflow
Your own document + simple changes Use "Basic OOXML editing" workflow
Someone else's document Use "Redlining workflow" (recommended default)
Legal, academic, business, or government docs Use "Redlining workflow" (required)
If you just need to read the text contents of a document, you should convert the document to markdown using pandoc. Pandoc provides excellent support for preserving document structure and can show tracked changes:
# Convert document to markdown with tracked changes
pandoc --track-changes=all path-to-file.docx -o output.md
# Options: --track-changes=accept/reject/all
You need raw XML access for: comments, complex formatting, document structure, embedded media, and metadata. For any of these features, you'll need to unpack a document and read its raw XML contents.
python ooxml/scripts/unpack.py <office_file> <output_directory>
word/document.xml - Main document contentsword/comments.xml - Comments referenced in document.xmlword/media/ - Embedded images and media files<w:ins> (insertions) and <w:del> (deletions) tagsWhen creating a new Word document from scratch, use docx-js, which allows you to create Word documents using JavaScript/TypeScript.
docx-js.md (~500 lines) completely from start to finish. NEVER set any range limits when reading this file. Read the full file content for detailed syntax, critical formatting rules, and best practices before proceeding with document creation.When editing an existing Word document, use the Document library (a Python library for OOXML manipulation). The library automatically handles infrastructure setup and provides methods for document manipulation. For complex scenarios, you can access the underlying DOM directly through the library.
ooxml.md (~600 lines) completely from start to finish. NEVER set any range limits when reading this file. Read the full file content for the Document library API and XML patterns for directly editing document files.python ooxml/scripts/unpack.py <office_file> <output_directory>python ooxml/scripts/pack.py <input_directory> <office_file>The Document library provides both high-level methods for common operations and direct DOM access for complex scenarios.
This workflow allows you to plan comprehensive tracked changes using markdown before implementing them in OOXML. CRITICAL: For complete tracked changes, you must implement ALL changes systematically.
Batching Strategy: Group related changes into batches of 3-10 changes. This makes debugging manageable while maintaining efficiency. Test each batch before moving to the next.
Principle: Minimal, Precise Edits
When implementing tracked changes, only mark text that actually changes. Repeating unchanged text makes edits harder to review and appears unprofessional. Break replacements into: [unchanged text] + [deletion] + [insertion] + [unchanged text]. Preserve the original run's RSID for unchanged text by extracting the <w:r> element from the original and reusing it.
Example - Changing "30 days" to "60 days" in a sentence:
# BAD - Replaces entire sentence
'<w:del><w:r><w:delText>The term is 30 days.</w:delText></w:r></w:del><w:ins><w:r><w:t>The term is 60 days.</w:t></w:r></w:ins>'
# GOOD - Only marks what changed, preserves original <w:r> for unchanged text
'<w:r w:rsidR="00AB12CD"><w:t>The term is </w:t></w:r><w:del><w:r><w:delText>30</w:delText></w:r></w:del><w:ins><w:r><w:t>60</w:t></w:r></w:ins><w:r w:rsidR="00AB12CD"><w:t> days.</w:t></w:r>'
Get markdown representation: Convert document to markdown with tracked changes preserved:
pandoc --track-changes=all path-to-file.docx -o current.md
Identify and group changes: Review the document and identify ALL changes needed, organizing them into logical batches:
Location methods (for finding changes in XML):
Batch organization (group 3-10 related changes per batch):
Read documentation and unpack:
ooxml.md (~600 lines) completely from start to finish. NEVER set any range limits when reading this file. Pay special attention to the "Document Library" and "Tracked Change Patterns" sections.python ooxml/scripts/unpack.py <file.docx> <dir>Implement changes in batches: Group changes logically (by section, by type, or by proximity) and implement them together in a single script. This approach:
Suggested batch groupings:
For each batch of related changes:
a. Map text to XML: Grep for text in word/document.xml to verify how text is split across <w:r> elements.
b. Create and run script: Use get_node to find nodes, implement changes, then doc.save(). See "Document Library" section in ooxml.md for patterns.
Note: Always grep word/document.xml immediately before writing a script to get current line numbers and verify text content. Line numbers change after each script run.
Pack the document: After all batches are complete, convert the unpacked directory back to .docx:
python ooxml/scripts/pack.py unpacked reviewed-document.docx
Final verification: Do a comprehensive check of the complete document:
pandoc --track-changes=all reviewed-document.docx -o verification.md
grep "original phrase" verification.md # Should NOT find it
grep "replacement phrase" verification.md # Should find it
When the target is a Google Doc (published via gspace drive_files_upsert with convert_to_google_format: true), use python-docx instead of docx-js. python-docx produces cleaner conversion output for Google's import pipeline.
Critical: python-docx's default paragraph spacing is zero, which renders as wall-of-text in Google Docs. Always set spacing explicitly.
uv run --with python-docx python3 - <<'EOF'
from docx import Document
from docx.shared import Pt
doc = Document()
# Set document-level defaults — always do this first
style = doc.styles['Normal']
style.paragraph_format.space_after = Pt(8)
style.paragraph_format.line_spacing = Pt(14)
def h1(doc, text):
p = doc.add_heading(text, level=1)
p.paragraph_format.space_before = Pt(0)
p.paragraph_format.space_after = Pt(10)
def h2(doc, text):
p = doc.add_heading(text, level=2)
p.paragraph_format.space_before = Pt(16)
p.paragraph_format.space_after = Pt(6)
def body(doc, text):
p = doc.add_paragraph(text)
p.paragraph_format.space_after = Pt(8)
def bullet(doc, text):
p = doc.add_paragraph(text, style='List Bullet')
p.paragraph_format.space_after = Pt(4)
def bold_field(doc, label, rest):
p = doc.add_paragraph()
p.paragraph_format.space_after = Pt(6)
p.add_run(label).bold = True
p.add_run(rest)
# Build document...
h1(doc, "Title")
h2(doc, "Section")
body(doc, "Paragraph text.")
bold_field(doc, "Term", " — definition text.")
bullet(doc, "List item")
doc.save("/tmp/output.docx")
EOF
Then publish:
# Upload and convert to Google Doc in-place (preserves file ID on re-runs)
gspace drive_files_upsert \
local_path=/tmp/output.docx \
name="Document Title" \
parent_folder_id=FOLDER_ID \
convert_to_google_format=true
| Element | space_before | space_after | line_spacing | |---------|-------------|-------------|--------------| | H1 | 0 | Pt(10) | (heading default) | | H2 | Pt(16) | Pt(6) | (heading default) | | Body paragraph | (default) | Pt(8) | Pt(14) | | Bold field entry | (default) | Pt(6) | Pt(14) | | Bullet | (default) | Pt(4) | Pt(14) |
.md paths. Use plain text names only, or full URLs if the remote documents have them.drive_files_upsert matches by filename within the folder. Use a stable name to update in-place rather than creating duplicates.To visually analyze Word documents, convert them to images using a two-step process:
Convert DOCX to PDF:
soffice --headless --convert-to pdf document.docx
Convert PDF pages to JPEG images:
pdftoppm -jpeg -r 150 document.pdf page
This creates files like page-1.jpg, page-2.jpg, etc.
Options:
-r 150: Sets resolution to 150 DPI (adjust for quality/size balance)-jpeg: Output JPEG format (use -png for PNG if preferred)-f N: First page to convert (e.g., -f 2 starts from page 2)-l N: Last page to convert (e.g., -l 5 stops at page 5)page: Prefix for output filesExample for specific range:
pdftoppm -jpeg -r 150 -f 2 -l 5 document.pdf page # Converts only pages 2-5
IMPORTANT: When generating code for DOCX operations:
Required dependencies (install if not available):
sudo apt-get install pandoc (for text extraction)npm install -g docx (for creating new documents)sudo apt-get install libreoffice (for PDF conversion)sudo apt-get install poppler-utils (for pdftoppm to convert PDF to images)pip install defusedxml (for secure XML parsing)devops
DORA engineering metrics project at ~/src/dora. Load when: querying DORA BigQuery views (deployment frequency, lead time, change failure rate, alerts, review time) from any project; joining against DORA.unified_identity or DORA_clean.* views from any project; running the data pipeline (just refresh, just download-*, just upload-*); making OpenTofu infrastructure changes to DORA tables or views; working with team attribution, team identity, or engineer roster data.
development
Data pipeline architecture patterns and best practices, including medallion/three-layer architecture (Raw/Staging/Enriched or Bronze/Silver/Gold), YAML-based schema management, and ETL workflow patterns. Use when designing or implementing data pipelines, working with data warehouse layers, or managing table schemas in YAML.
data-ai
Delegate research and context-gathering tasks to a sub-agent to protect the primary context window. Use when the user asks to "research X", "look into X", "find out about X", "gather context on X", or any investigative framing where answering requires 2+ searches or multiple sources. Also use proactively before starting substantive work when prior context is unknown. Never run research inline — always delegate.
documentation
--- name: qmd-math description: Math notation conventions for Quarto/EPQ documents rendered via lualatex. Use when: writing or adding a formula, equation, or mathematical expression to a .qmd file; asked about display math, inline math, or LaTeX notation in a QMD/Quarto context; defining a where-clause or variable definitions for an equation; converting prose variable descriptions into structured math notation; fixing math that renders badly in a PDF; using \lvert, \begin{aligned}, \tfrac, \text