跳到正文
FunCoding

docx

Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). For CREATING new documents (report, memo, letter, résumé, contract from scratch), call the built-in tool `renderDocx` instead — it renders Markdown to .docx in milliseconds without forking Node.js. This skill remains authoritative for EDITING existing .docx (unpack/edit XML/pack), tracked changes, comments, image manipulation, find-and-replace, and conversions. Triggers include: "Word doc", "word document", ".docx", or requests to edit/extract/restructure existing Word files. Do NOT use for PDFs, spreadsheets, or general coding tasks unrelated to document generation.

Star
1,157
许可证
Apache-2.0
最近提交
2026年10月13日

mateclaw-server/src/main/resources/skills/docx/SKILL.md

在 GitHub 上查看

Important: All scripts/ paths are relative to this skill directory. Use run_skill_script tool to execute scripts, or run with: cd {this_skill_dir} && python scripts/...

DOCX creation, editing, and analysis

Quick Start — Pick the Right Tool

TaskRecommended Tool
Create a new document (report / résumé / contract / memo)renderDocx() — millisecond render, no subprocess
Edit an existing .docx (content / formatting)unpack → edit XML → pack workflow below
Add tracked changes / commentsunpack → edit XML → pack workflow below
GB/T 9704 official documentwriteGongwen() (BmacClaw only)

Call the in-process Java tool — no Node.js install, no fork, no disk round-trip:

renderDocx(
  markdown="# Title\n\nBody paragraph...",
  filename="monthly-report",
  pageSize="A4"
)

Returns a clickable link of the form [monthly-report.docx](/api/v1/files/generated/<uuid>) valid for 10 minutes. The user clicks it to download — no follow-up Agent step needed.

renderDocx supports headings (# ## ###), bold (**text**), bullet lists (- item), numbered lists (1. item), pipe-style tables, and plain paragraphs. For images, headers/footers, or precise OOXML control, fall back to the docx-js workflow below.

Prerequisites

  • python-docx (pip install python-docx): direct structure reading and light editing (paragraphs, styles, tables)
  • docx (npm install -g docx): new document creation
  • LibreOffice (soffice): .doc -> .docx conversion, tracked-changes acceptance, and PDF export
  • pandoc: text extraction
  • pdftoppm (poppler-utils): document-to-image workflows
  • If pdftoppm is unavailable, a Python fallback path may use pdf2image.
  • On Windows, dependencies must be installed and available in PATH; if missing, report the dependency issue and stop (do not keep retrying).

Overview

A .docx file is a ZIP archive containing XML files.

Quick Reference

TaskApproach
Read/analyze contentpandoc or unpack for raw XML
Create new documentUse docx-js - see Creating New Documents below
Edit existing documentUnpack → edit XML → repack - see Editing Existing Documents below

Converting .doc to .docx

Legacy .doc files must be converted before editing:

python scripts/office/soffice.py --headless --convert-to docx document.doc

Reading Content

Option A: python-docx (recommended for structured access)

Install: pip install python-docx. Gives direct access to paragraphs, styles, tables, and metadata without unpacking ZIP.

from docx import Document

doc = Document("document.docx")

# Paragraphs with styles
for para in doc.paragraphs:
    print(f"[{para.style.name}] {para.text}")

# Tables
for i, table in enumerate(doc.tables):
    print(f"Table {i+1}:")
    for row in table.rows:
        print([cell.text for cell in row.cells])

# Inline styles within a paragraph
for para in doc.paragraphs:
    for run in para.runs:
        print(f"  run: bold={run.bold} italic={run.italic} text={run.text!r}")

Use python-docx when you need to read or lightly modify content. Fall back to the unpack/XML workflow for complex structural changes.

Option B: pandoc (plain text extraction)

# Text extraction with tracked changes
pandoc --track-changes=all document.docx -o output.md

# Raw XML access
python scripts/office/unpack.py document.docx unpacked/

Converting to Images

python scripts/office/soffice.py --headless --convert-to pdf document.docx
pdftoppm -jpeg -r 150 document.pdf page

Accepting Tracked Changes

To produce a clean document with all tracked changes accepted (requires LibreOffice):

python scripts/accept_changes.py input.docx output.docx

Creating New Documents

Generate .docx files with JavaScript, then validate. Install: npm install -g docx

Setup

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

const doc = new Document({ sections: [{ children: [/* content */] }] });
Packer.toBuffer(doc).then(buffer => fs.writeFileSync("doc.docx", buffer));

Validation

After creating the file, validate it. If validation fails, unpack, fix the XML, and repack.

python scripts/office/validate.py doc.docx

Page Size

// CRITICAL: docx-js defaults to A4, not US Letter
// Always set page size explicitly for consistent results
sections: [{
  properties: {
    page: {
      size: {
        width: 12240,   // 8.5 inches in DXA
        height: 15840   // 11 inches in DXA
      },
      margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } // 1 inch margins
    }
  },
  children: [/* content */]
}]

Common page sizes (DXA units, 1440 DXA = 1 inch):

PaperWidthHeightContent Width (1" margins)
US Letter12,24015,8409,360
A4 (default)11,90616,8389,026

Landscape orientation: docx-js swaps width/height internally, so pass portrait dimensions and let it handle the swap:

size: {
  width: 12240,   // Pass SHORT edge as width
  height: 15840,  // Pass LONG edge as height
  orientation: PageOrientation.LANDSCAPE  // docx-js swaps them in the XML
},
// Content width = 15840 - left margin - right margin (uses the long edge)

Styles (Override Built-in Headings)

Use Arial as the default font (universally supported). Keep titles black for readability.

const doc = new Document({
  styles: {
    default: { document: { run: { font: "Arial", size: 24 } } }, // 12pt default
    paragraphStyles: [
      // IMPORTANT: Use exact IDs to override built-in styles
      { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true,
        run: { size: 32, bold: true, font: "Arial" },
        paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } }, // outlineLevel required for TOC
      { id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true,
        run: { size: 28, bold: true, font: "Arial" },
        paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },
    ]
  },
  sections: [{
    children: [
      new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun("Title")] }),
    ]
  }]
});

Lists (NEVER use unicode bullets)

// CORRECT - use numbering config with LevelFormat.BULLET
const doc = new Document({
  numbering: {
    config: [
      { reference: "bullets",
        levels: [{ level: 0, format: LevelFormat.BULLET, text: "\u2022", alignment: AlignmentType.LEFT,
          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },
      { reference: "numbers",
        levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT,
          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },
    ]
  },
  sections: [{
    children: [
      new Paragraph({ numbering: { reference: "bullets", level: 0 },
        children: [new TextRun("Bullet item")] }),
      new Paragraph({ numbering: { reference: "numbers", level: 0 },
        children: [new TextRun("Numbered item")] }),
    ]
  }]
});

// Each reference creates INDEPENDENT numbering
// Same reference = continues (1,2,3 then 4,5,6)
// Different reference = restarts (1,2,3 then 1,2,3)

Tables

CRITICAL: Tables need dual widths - set both columnWidths on the table AND width on each cell.

// CRITICAL: Use ShadingType.CLEAR (not SOLID) to prevent black backgrounds
const border = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" };
const borders = { top: border, bottom: border, left: border, right: border };

new Table({
  width: { size: 9360, type: WidthType.DXA }, // Always use DXA
  columnWidths: [4680, 4680], // Must sum to table width (DXA: 1440 = 1 inch)
  rows: [
    new TableRow({
      children: [
        new TableCell({
          borders,
          width: { size: 4680, type: WidthType.DXA }, // Also set on each cell
          shading: { fill: "D5E8F0", type: ShadingType.CLEAR }, // CLEAR not SOLID
          margins: { top: 80, bottom: 80, left: 120, right: 120 },
          children: [new Paragraph({ children: [new TextRun("Cell")] })]
        })
      ]
    })
  ]
})

Width rules:

  • Always use WidthType.DXA - never WidthType.PERCENTAGE
  • Table width must equal the sum of columnWidths
  • Cell width must match corresponding columnWidth

Images

// CRITICAL: type parameter is REQUIRED
new Paragraph({
  children: [new ImageRun({
    type: "png", // Required: png, jpg, jpeg, gif, bmp, svg
    data: fs.readFileSync("image.png"),
    transformation: { width: 200, height: 150 },
    altText: { title: "Title", description: "Desc", name: "Name" } // All three required
  })]
})

Page Breaks

// PageBreak must be inside a Paragraph
new Paragraph({ children: [new PageBreak()] })

Table of Contents

// Headings must use HeadingLevel ONLY - no custom styles
new TableOfContents("Table of Contents", { hyperlink: true, headingStyleRange: "1-3" })

Headers/Footers

sections: [{
  properties: {
    page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } }
  },
  headers: {
    default: new Header({ children: [new Paragraph({ children: [new TextRun("Header")] })] })
  },
  footers: {
    default: new Footer({ children: [new Paragraph({
      children: [new TextRun("Page "), new TextRun({ children: [PageNumber.CURRENT] })]
    })] })
  },
  children: [/* content */]
}]

Critical Rules for docx-js

  • Set page size explicitly - docx-js defaults to A4
  • Landscape: pass portrait dimensions - docx-js swaps width/height internally
  • Never use \n - use separate Paragraph elements
  • Never use unicode bullets - use LevelFormat.BULLET with numbering config
  • PageBreak must be in Paragraph
  • ImageRun requires type
  • Always set table width with DXA - never use WidthType.PERCENTAGE
  • Tables need dual widths - columnWidths array AND cell width
  • Use ShadingType.CLEAR - never SOLID for table shading
  • TOC requires HeadingLevel only
  • Override built-in styles - use exact IDs: "Heading1", "Heading2", etc.
  • Include outlineLevel - required for TOC (0 for H1, 1 for H2, etc.)

Editing Existing Documents

Follow all 3 steps in order.

Step 1: Unpack

python scripts/office/unpack.py document.docx unpacked/

Extracts XML, pretty-prints, merges adjacent runs, and converts smart quotes to XML entities. Use --merge-runs false to skip run merging.

Step 2: Edit XML

Edit files in unpacked/word/. See XML Reference below for patterns.

Use "MateClaw" as the author for tracked changes and comments, unless the user explicitly requests a different name.

CRITICAL: Use smart quotes for new content:

<w:t>Here&#x2019;s a quote: &#x201C;Hello&#x201D;</w:t>
EntityCharacter
&#x2018;' (left single)
&#x2019;' (right single / apostrophe)
&#x201C;" (left double)
&#x201D;" (right double)

Adding comments: Use comment.py to handle boilerplate:

python scripts/comment.py unpacked/ 0 "Comment text with &amp; and &#x2019;"
python scripts/comment.py unpacked/ 1 "Reply text" --parent 0  # reply to comment 0
python scripts/comment.py unpacked/ 0 "Text" --author "Custom Author"

Then add markers to document.xml (see Comments in XML Reference).

Step 3: Pack

python scripts/office/pack.py unpacked/ output.docx --original document.docx

Validates with auto-repair, condenses XML, and creates DOCX. Use --validate false to skip.

Auto-repair will fix:

  • durableId >= 0x7FFFFFFF (regenerates valid ID)
  • Missing xml:space="preserve" on <w:t> with whitespace

Common Pitfalls

  • Replace entire <w:r> elements: When adding tracked changes, replace the whole <w:r>...</w:r> block.
  • Preserve <w:rPr> formatting: Copy the original run's <w:rPr> block into your tracked change runs.

XML Reference

Schema Compliance

  • Element order in <w:pPr>: <w:pStyle>, <w:numPr>, <w:spacing>, <w:ind>, <w:jc>, <w:rPr> last
  • Whitespace: Add xml:space="preserve" to <w:t> with leading/trailing spaces
  • RSIDs: Must be 8-digit hex (e.g., 00AB1234)

Tracked Changes

Insertion:

<w:ins w:id="1" w:author="MateClaw" w:date="2025-01-01T00:00:00Z">
  <w:r><w:t>inserted text</w:t></w:r>
</w:ins>

Deletion:

<w:del w:id="2" w:author="MateClaw" w:date="2025-01-01T00:00:00Z">
  <w:r><w:delText>deleted text</w:delText></w:r>
</w:del>

Inside <w:del>: Use <w:delText> instead of <w:t>, and <w:delInstrText> instead of <w:instrText>.

Minimal edits - only mark what changes:

<!-- Change "30 days" to "60 days" -->
<w:r><w:t>The term is </w:t></w:r>
<w:del w:id="1" w:author="MateClaw" w:date="...">
  <w:r><w:delText>30</w:delText></w:r>
</w:del>
<w:ins w:id="2" w:author="MateClaw" w:date="...">
  <w:r><w:t>60</w:t></w:r>
</w:ins>
<w:r><w:t> days.</w:t></w:r>

Deleting entire paragraphs - mark the paragraph mark as deleted:

<w:p>
  <w:pPr>
    <w:rPr>
      <w:del w:id="1" w:author="MateClaw" w:date="2025-01-01T00:00:00Z"/>
    </w:rPr>
  </w:pPr>
  <w:del w:id="2" w:author="MateClaw" w:date="2025-01-01T00:00:00Z">
    <w:r><w:delText>Entire paragraph content being deleted...</w:delText></w:r>
  </w:del>
</w:p>

Rejecting another author's insertion:

<w:ins w:author="Jane" w:id="5">
  <w:del w:author="MateClaw" w:id="10">
    <w:r><w:delText>their inserted text</w:delText></w:r>
  </w:del>
</w:ins>

Restoring another author's deletion:

<w:del w:author="Jane" w:id="5">
  <w:r><w:delText>deleted text</w:delText></w:r>
</w:del>
<w:ins w:author="MateClaw" w:id="10">
  <w:r><w:t>deleted text</w:t></w:r>
</w:ins>

Comments

After running comment.py, add markers to document.xml:

CRITICAL: <w:commentRangeStart> and <w:commentRangeEnd> are siblings of <w:r>, never inside <w:r>.

<w:commentRangeStart w:id="0"/>
<w:r><w:t>commented text</w:t></w:r>
<w:commentRangeEnd w:id="0"/>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="0"/></w:r>

Images

  1. Add image file to word/media/
  2. Add relationship to word/_rels/document.xml.rels:
<Relationship Id="rId5" Type=".../image" Target="media/image1.png"/>
  1. Add content type to [Content_Types].xml:
<Default Extension="png" ContentType="image/png"/>
  1. Reference in document.xml:
<w:drawing>
  <wp:inline>
    <wp:extent cx="914400" cy="914400"/>  <!-- EMUs: 914400 = 1 inch -->
    <a:graphic>
      <a:graphicData uri=".../picture">
        <pic:pic>
          <pic:blipFill><a:blip r:embed="rId5"/></pic:blipFill>
        </pic:pic>
      </a:graphicData>
    </a:graphic>
  </wp:inline>
</w:drawing>

相似的 Skill

精选

pdf

提取文本和表格、合并拆分、填写表单,也能对扫描件做 OCR。

ANanthropics/skills181k近 7 天新增 1,119 个 star

精选

canvas-design

按设计理念生成海报和视觉作品,输出 PNG 或 PDF。

ANanthropics/skills181k近 7 天新增 1,119 个 star

精选

docx

创建和编辑 Word 文档,支持目录、页码、页眉等排版。

ANanthropics/skills181k近 7 天新增 1,119 个 star

精选

doc-coauthoring

按步骤协作撰写技术方案、提案和决策文档,逐轮修改。

ANanthropics/skills181k近 7 天新增 1,119 个 star

精选

xlsx

读写 Excel 和 CSV,处理公式、格式、图表与数据清洗。

ANanthropics/skills181k近 7 天新增 1,119 个 star

精选

pptx

生成、读取和修改演示文稿,也能合并拆分幻灯片。

ANanthropics/skills181k近 7 天新增 1,119 个 star