
Word Document
- 673 installs
- 7 repo stars
- Updated August 2, 2026
- practicalswan/agent-skills
word-document is a Claude agent skill at version 1.2 that automates creation, editing, and verification of Word .docx files using OOXML-aware workflows with MCP or native automation fallbacks for developers producing Off
About
word-document is a practicalswan/agent-skills skill at version 1.2 (last updated 2026-04-25) for automating Microsoft Word .docx files from a coding agent. The skill follows OOXML-aware workflows to create, edit, and verify documents, with an MCP Fallback to Native Automation pattern when Office MCP servers are unavailable. Version 1.2 added a Verification Protocol with skill-specific pass/fail checks, one pressure-test scenario, and a measurable success metric, plus guidance for parallel subagent dispatch on 200k+ context windows. Developers reach for word-document when users need programmatic .docx generation, structured edits, or post-edit validation instead of manual Word macros. Symptom-to-action triggers and two-stage review wording standardize how agents confirm document integrity before handoff.
- OOXML-compatible Word (.docx) automation for agent-driven create/edit workflows
- MCP Fallback → Native Automation path when Office MCP servers are unavailable
- Verification Protocol with skill-specific pass/fail checks, one pressure-test scenario, and a measurable success metric
- Guidance to use native parallel subagent dispatch and large context windows where the host supports them
- Symptom → action activation triggers plus standardized two-stage review wording
Word Document by the numbers
- 673 all-time installs (skills.sh)
- +9 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #141 of 688 Office & Documents skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/practicalswan/agent-skills --skill word-documentAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 673 |
|---|---|
| repo stars | ★ 7 |
| Security audit | 3 / 3 scanners passed |
| Last updated | August 2, 2026 |
| Repository | practicalswan/agent-skills ↗ |
How do you automate Word docx creation from a coding agent?
Automate creation, editing, and verification of Word (.docx) files from your coding agent using OOXML-aware workflows with MCP or native fallbacks.
Who is it for?
Developers automating Word report generation or structured .docx edits who need OOXML correctness checks and MCP-to-native fallback paths.
Skip if: Developers who only need plain Markdown README files, Excel spreadsheets, or PDF-only output without Word OOXML structure.
When should I use this skill?
The user asks to create, edit, or verify a Word .docx file, Office document, or OOXML-based report from an agent.
What you get
Verified .docx files with OOXML-correct structure and documented pass/fail verification results.
- verified .docx file
- verification pass/fail report
By the numbers
- Skill version 1.2 last updated 2026-04-25
- Verification Protocol includes one pressure-test scenario and measurable success metric
Files
Word Document Workflows
Tech Stack Target / Version: Word desktop or python-docx automation with current OOXML-compatible workflows.Use this skill when .docx layout and document structure matter, not just the raw text.
- Leverage native parallel subagent dispatch and 200k+ context windows where available.
Current MCP Reality
Microsoft publicly documents a Word MCP server in the Microsoft 365 Agents Toolkit preview, but tool availability still depends on the host. In GitHub Copilot you may see Word-specific tools; in other clients they may be missing. If direct Word MCP access is unavailable, use the included local script workflow.
Activation Conditions
Use symptom -> action triggers: when one matches, apply this skill and verify with the protocol below.
- Creating or editing
.docxreports, memos, or structured deliverables - Applying headings, tables, images, or styles
- Reviewing or extracting document structure
- Preparing Word output before a later PDF conversion
Practical Workflow
1. Confirm whether the client exposes Word MCP capabilities. 2. Start with structure: title, headings, sections, tables. 3. Apply styling consistently only after the structure is right. 4. Validate comments, footnotes, and references before export. 5. Use the local generator script when MCP access is unavailable.
MCP Fallback – Native Automation
When MCP is unavailable, use native automation: python-docx for .docx, direct OOXML inspection for unsupported structures, and PDF export checks when layout matters. Preserve styles, tables, headers, footers, comments, tracked-change expectations, and metadata, then reopen or parse the document before claiming success.
Anti-Patterns
- Writing for the author instead of the reader: It bakes in unstated context and leaves the actual audience unsure what to do next.
- Skipping concrete examples or commands: Abstract guidance is easy to approve and hard to apply correctly.
- Letting links, screenshots, or versions drift: Polished formatting does not help if the instructions are no longer true.
Verification Protocol
Before claiming "skill applied successfully":
1. Pass/fail: The Word Document artifact type, target format, and required output fidelity are stated before editing. 2. Pass/fail: MCP availability is checked and the native automation fallback path is named when MCP is absent. 3. Pass/fail: The produced file or formula is opened, parsed, rendered, or otherwise validated locally. 4. Pressure-test scenario: Apply the workflow to a file with formatting, metadata, or conversion edge cases and verify nothing important is lost. 5. Success metric: Zero unverified document claims; the artifact itself is the evidence.
Document Checklist
- [ ] Heading hierarchy is clear
- [ ] Tables are readable and consistently styled
- [ ] Comments or review notes are intentional
- [ ] Placeholder text is removed
- [ ] The final document was re-opened or otherwise verified after generation
References & Resources
Documentation
- DOCX Formatting Reference - Practical formatting notes and document structure guidance
Scripts
- DOC Template Generator - Local fallback for generating Word-ready document structures
Examples
- Report Generation Example - Example report workflow for
.docxoutput
<!-- PORTABILITY:START -->
Cross-Client Portability
This skill is written to stay usable across GitHub Copilot, Claude Code, Codex, and Gemini CLI.
- GitHub Copilot: keep the folder in a Copilot-visible skill or plugin path, or wrap the workflow as project instructions if the host does not support portable skill folders directly.
- Claude Code: keep the folder in a local skills directory or a compatible plugin or marketplace source.
- Codex: install or sync the folder into
$CODEX_HOME/skills/<skill-name>and restart Codex after major changes. - Gemini CLI: this repository generates a project command named
/skills:word-documentfrom this skill. Rebuild commands withpython scripts/export-gemini-skill.py word-documentand then run/commands reloadinside Gemini CLI.
<!-- PORTABILITY:END -->
<!-- MCP:START -->
MCP Availability And Fallback
Preferred MCP Server: Word Document MCP
- Fallback prompt: "Use the Word Document Workflows skill without MCP. Rely on the local
SKILL.md, bundled references or scripts, and manual verification. Show the exact commands, evidence, and final checks you used before concluding." - Use
python-docx, Word desktop, or document export scripts when the MCP surface is unavailable. - Re-open or render the document locally so formatting, comments, and pagination are verified before delivery.
<!-- MCP:END -->
Related Skills
- documentation-authoring: Use it when the workflow also needs drafting structured technical or product documents.
- documentation-patterns: Use it when the workflow also needs reusable documentation structures and templates.
- documentation-quality: Use it when the workflow also needs documentation review standards and quality gates.
- documentation-verification: Use it when the workflow also needs final documentation validation before publishing.
Changelog
[2026-04-25] - Version 1.2 Verification Protocol Refresh
Added
- Added a
Verification Protocolsection with skill-specific pass/fail checks, one pressure-test scenario, and a measurable success metric. - Added guidance to leverage native parallel subagent dispatch and 200k+ context windows where available.
- Added the shared
MCP Fallback ? Native Automationsection for Office-style workflows.
Changed
- Updated
SKILL.mdfrontmatter toversion: "1.2"andlast_updated: 2026-04-25. - Reframed activation guidance toward symptom -> action triggers and standardized two-stage review wording where applicable.
[2026-04-24] - Version 1.1 Refresh
Changed
- Updated the SKILL frontmatter version to
1.1for the 2026-04-24 catalog refresh.
All notable changes to this skill will be documented in this file.
[2026-04-24] - Skill Refresh
Changed
- Standardized the SKILL frontmatter with version metadata, last-updated date, tags, and a concise catalog description.
- Reformatted the portability and MCP guidance with a preferred server line, a copy-paste fallback prompt, and consistent bullet lists.
- Added a catalog-standard Anti-Patterns section and refreshed the Related Skills links at the end of the skill.
- Added a Tech Stack Target / Version note so Word automation guidance is tied to current OOXML-compatible workflows.
[2026-04-04] - Cross-Client Portability Refresh
Changed
- Added a standard portability note covering GitHub Copilot, Claude Code, Codex, and Gemini CLI.
- Documented the preferred MCP server surface for this skill and a local no-MCP fallback workflow.
Tested
- Validated
SKILL.mdfrontmatter, portability sections, and Gemini export readiness withpython scripts/validate-skills.py.
[2026-03-09] - Workspace Modernization
Changed
- Rewrote the skill to describe Word MCP access as host-specific instead of assuming stable wrapper commands
- Repositioned the local document generator as the fallback path when Word MCP tools are unavailable
[2026-02-28] - Description Rewrite and Cross-References
Changed
- Rewrote the skill description to concise activation-focused wording
- Improved keyword specificity to reduce overlap with related skills
Added
- Added the related-skills cross-reference table
[2026-02-19] - Word MCP Extraction
Changed
- Split Word workflow guidance out of the former shared office-documents skill into a Word-specific skill
- Replaced library-first guidance with MCP-oriented document workflows
- Updated activation triggers around
.docx, Word documents, and Word MCP use cases
Added
- Added Word-specific references, examples, and local document-generation support
- Added coverage for document structure, formatting, tables, and review-oriented workflows
Fixed
- Reduced ambiguity between generic office-document handling and Word-specific document tasks
Professional Word Report Generation Example
Complete example of generating a multi-section business report using the docx npm package.
Output Structure
1. Title Page — company logo, report title, subtitle, date, author
2. Table of Contents — auto-generated from headings
3. Executive Summary — narrative overview
4. Key Metrics Table — formatted data table with alternating row colors
5. Quarterly Breakdown — detail section with sub-tables
6. Chart Placeholder — described image placeholder
7. Appendix — supplementary data, methodology notes---
Style Configuration
Reusable style object for consistent branding across reports.
const REPORT_STYLES = {
colors: {
primary: "1F4E79", // dark blue
primaryLight: "D6E4F0", // light blue background
accent: "2E75B6", // medium blue
text: "333333",
textLight: "666666",
headerBg: "1F4E79",
headerText: "FFFFFF",
altRowBg: "F2F7FB",
borderColor: "B4C6E0",
success: "28A745",
warning: "FFC107",
danger: "DC3545",
},
fonts: {
heading: "Calibri Light",
body: "Calibri",
monospace: "Consolas",
},
sizes: {
title: 52, // 26pt
subtitle: 28, // 14pt
heading1: 32, // 16pt
heading2: 26, // 13pt
heading3: 22, // 11pt
body: 22, // 11pt
small: 18, // 9pt
caption: 16, // 8pt
},
spacing: {
afterHeading1: 240, // 12pt
afterHeading2: 160,
afterParagraph: 120, // 6pt
lineSpacing: 276, // 1.15x
},
page: {
marginTop: 1440, // 1 inch in twips
marginBottom: 1440,
marginLeft: 1440,
marginRight: 1440,
headerMargin: 720,
footerMargin: 720,
},
};---
Complete Report Code
import fs from "fs";
import {
Document, Packer, Paragraph, TextRun, ImageRun,
Header, Footer, PageNumber, NumberFormat,
Table, TableRow, TableCell,
AlignmentType, HeadingLevel, TabStopType,
BorderStyle, ShadingType, WidthType, VerticalAlign,
TableOfContents, PageOrientation, SectionType,
convertInchesToTwip, LevelFormat,
} from "docx";
const S = REPORT_STYLES; // alias for brevity
// ─── Helper: Create a styled paragraph ──────────────────────────────
function styledParagraph(text, options = {}) {
return new Paragraph({
spacing: { after: S.spacing.afterParagraph, line: S.spacing.lineSpacing },
...options,
children: [
new TextRun({
text,
font: S.fonts.body,
size: S.sizes.body,
color: S.colors.text,
...(options.run || {}),
}),
],
});
}
// ─── Helper: Create a table cell ────────────────────────────────────
function cell(text, options = {}) {
const isHeader = options.header || false;
return new TableCell({
width: options.width || { size: 0, type: WidthType.AUTO },
shading: options.shading || (isHeader
? { fill: S.colors.headerBg, type: ShadingType.SOLID, color: "auto" }
: undefined),
verticalAlign: VerticalAlign.CENTER,
margins: {
top: 40, bottom: 40, left: 80, right: 80,
},
children: [
new Paragraph({
alignment: options.alignment || (isHeader ? AlignmentType.CENTER : AlignmentType.LEFT),
children: [
new TextRun({
text: String(text),
bold: isHeader,
font: S.fonts.body,
size: isHeader ? S.sizes.body : S.sizes.body,
color: isHeader ? S.colors.headerText : S.colors.text,
}),
],
}),
],
});
}
// ─── Helper: Data table with alternating rows ───────────────────────
function dataTable(headers, rows, columnWidths) {
const headerRow = new TableRow({
tableHeader: true,
children: headers.map((h, i) =>
cell(h, {
header: true,
width: columnWidths?.[i] ? { size: columnWidths[i], type: WidthType.DXA } : undefined,
alignment: AlignmentType.CENTER,
})
),
});
const dataRows = rows.map((row, rowIdx) =>
new TableRow({
children: row.map((value, colIdx) =>
cell(value, {
width: columnWidths?.[colIdx] ? { size: columnWidths[colIdx], type: WidthType.DXA } : undefined,
shading: rowIdx % 2 === 1
? { fill: S.colors.altRowBg, type: ShadingType.SOLID, color: "auto" }
: undefined,
alignment: typeof value === "number" ? AlignmentType.RIGHT : AlignmentType.LEFT,
})
),
})
);
return new Table({
rows: [headerRow, ...dataRows],
width: { size: 100, type: WidthType.PERCENTAGE },
});
}
// ─── Helper: Section divider ────────────────────────────────────────
function sectionDivider() {
return new Paragraph({
spacing: { before: 200, after: 200 },
border: { bottom: { style: BorderStyle.SINGLE, size: 1, color: S.colors.borderColor, space: 8 } },
children: [],
});
}
// ─── Section 1: Title Page ──────────────────────────────────────────
function buildTitlePage() {
// For a real logo, replace with: fs.readFileSync("logo.png")
const logoPlaceholder = styledParagraph("[Company Logo]", {
alignment: AlignmentType.CENTER,
spacing: { before: 2400, after: 600 },
run: { size: S.sizes.subtitle, color: S.colors.textLight, italics: true },
});
return [
logoPlaceholder,
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 200 },
children: [
new TextRun({
text: "Annual Performance Report",
font: S.fonts.heading,
size: S.sizes.title,
bold: true,
color: S.colors.primary,
}),
],
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 400 },
children: [
new TextRun({
text: "Fiscal Year 2025 — Q1 through Q4",
font: S.fonts.heading,
size: S.sizes.subtitle,
color: S.colors.accent,
}),
],
}),
sectionDivider(),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 120 },
children: [
new TextRun({
text: "Prepared by: Analytics Department",
font: S.fonts.body,
size: S.sizes.body,
color: S.colors.textLight,
}),
],
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 120 },
children: [
new TextRun({
text: `Date: ${new Date().toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" })}`,
font: S.fonts.body,
size: S.sizes.body,
color: S.colors.textLight,
}),
],
}),
new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new TextRun({
text: "CONFIDENTIAL",
font: S.fonts.body,
size: S.sizes.small,
bold: true,
color: S.colors.danger,
}),
],
}),
];
}
// ─── Section 2: Table of Contents ───────────────────────────────────
function buildTableOfContents() {
return [
new Paragraph({
text: "Table of Contents",
heading: HeadingLevel.HEADING_1,
spacing: { after: 300 },
}),
new TableOfContents("Table of Contents", {
hyperlink: true,
headingStyleRange: "1-3",
}),
];
}
// ─── Section 3: Executive Summary ───────────────────────────────────
function buildExecutiveSummary() {
return [
new Paragraph({
text: "Executive Summary",
heading: HeadingLevel.HEADING_1,
}),
styledParagraph(
"This report presents a comprehensive analysis of organizational performance across all four quarters of Fiscal Year 2025. Key findings indicate strong growth in digital channels, improved operational efficiency, and expanding market share in the Asia-Pacific region."
),
styledParagraph(
"Total revenue reached $48.2M, representing a 12.4% year-over-year increase. Operating margins improved by 2.1 percentage points to 23.7%, driven by process automation initiatives and strategic vendor consolidation."
),
new Paragraph({
text: "Key Highlights",
heading: HeadingLevel.HEADING_2,
}),
styledParagraph("Revenue grew 12.4% YoY to $48.2M, exceeding the $45M target.", {
numbering: { reference: "report-bullets", level: 0 },
}),
styledParagraph("Customer acquisition cost decreased by 18% through optimized digital campaigns.", {
numbering: { reference: "report-bullets", level: 0 },
}),
styledParagraph("Employee satisfaction score improved to 4.3/5.0 (up from 3.9).", {
numbering: { reference: "report-bullets", level: 0 },
}),
styledParagraph("Three new enterprise clients onboarded, adding $6.1M in annual recurring revenue.", {
numbering: { reference: "report-bullets", level: 0 },
}),
];
}
// ─── Section 4: Key Metrics ─────────────────────────────────────────
function buildMetricsSection() {
const metricsHeaders = ["Metric", "Q1", "Q2", "Q3", "Q4", "YoY Change"];
const metricsData = [
["Revenue ($M)", "10.8", "11.5", "12.1", "13.8", "+12.4%"],
["Operating Margin", "22.1%", "23.0%", "24.2%", "25.5%", "+2.1pp"],
["Customer Count", "1,240", "1,385", "1,510", "1,678", "+35.3%"],
["NPS Score", "62", "65", "68", "71", "+9pts"],
["Employee Headcount", "342", "358", "371", "389", "+13.7%"],
["Churn Rate", "3.2%", "2.8%", "2.5%", "2.1%", "-1.1pp"],
];
return [
new Paragraph({
text: "Key Performance Metrics",
heading: HeadingLevel.HEADING_1,
}),
styledParagraph(
"The following table summarizes core business metrics tracked across all quarters."
),
dataTable(metricsHeaders, metricsData, [2800, 1400, 1400, 1400, 1400, 1600]),
new Paragraph({ spacing: { after: 200 }, children: [] }),
];
}
// ─── Section 5: Quarterly Breakdown ─────────────────────────────────
function buildQuarterlyBreakdown() {
const regionHeaders = ["Region", "Revenue ($M)", "Growth", "Margin"];
const regionData = [
["North America", "22.4", "+8.2%", "26.1%"],
["Europe", "12.8", "+11.5%", "22.3%"],
["Asia-Pacific", "9.6", "+24.1%", "19.8%"],
["Latin America", "3.4", "+15.7%", "18.2%"],
];
return [
new Paragraph({
text: "Quarterly Breakdown",
heading: HeadingLevel.HEADING_1,
}),
new Paragraph({
text: "Revenue by Region",
heading: HeadingLevel.HEADING_2,
}),
styledParagraph(
"Regional performance showed strong gains across all territories, with Asia-Pacific leading growth at 24.1%."
),
dataTable(regionHeaders, regionData, [2800, 2200, 1800, 1800]),
new Paragraph({ spacing: { after: 300 }, children: [] }),
new Paragraph({
text: "Product Line Performance",
heading: HeadingLevel.HEADING_2,
}),
styledParagraph(
"The SaaS platform remains the primary revenue driver at 62% of total revenue, while professional services grew 19% driven by implementation engagements with new enterprise clients."
),
];
}
// ─── Section 6: Chart Placeholder ───────────────────────────────────
function buildChartPlaceholder() {
return [
new Paragraph({
text: "Visual Analytics",
heading: HeadingLevel.HEADING_1,
}),
styledParagraph(
"The following charts illustrate revenue trends and regional distribution."
),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 400, after: 200 },
border: {
top: { style: BorderStyle.DASHED, size: 1, color: S.colors.borderColor },
bottom: { style: BorderStyle.DASHED, size: 1, color: S.colors.borderColor },
left: { style: BorderStyle.DASHED, size: 1, color: S.colors.borderColor },
right: { style: BorderStyle.DASHED, size: 1, color: S.colors.borderColor },
},
children: [
new TextRun({
text: "[Chart Placeholder: Revenue Trend — Line chart showing Q1–Q4 revenue growth]",
font: S.fonts.body,
size: S.sizes.body,
color: S.colors.textLight,
italics: true,
}),
],
}),
new Paragraph({ spacing: { after: 200 }, children: [] }),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 200, after: 400 },
border: {
top: { style: BorderStyle.DASHED, size: 1, color: S.colors.borderColor },
bottom: { style: BorderStyle.DASHED, size: 1, color: S.colors.borderColor },
left: { style: BorderStyle.DASHED, size: 1, color: S.colors.borderColor },
right: { style: BorderStyle.DASHED, size: 1, color: S.colors.borderColor },
},
children: [
new TextRun({
text: "[Chart Placeholder: Regional Distribution — Pie chart of revenue by region]",
font: S.fonts.body,
size: S.sizes.body,
color: S.colors.textLight,
italics: true,
}),
],
}),
styledParagraph(
"Note: Replace chart placeholders with actual chart images using ImageRun. Generate charts externally (e.g., Chart.js rendered to PNG via canvas) and embed with the ImageRun API.",
{ run: { size: S.sizes.small, italics: true, color: S.colors.textLight } }
),
];
}
// ─── Section 7: Appendix ────────────────────────────────────────────
function buildAppendix() {
return [
new Paragraph({
text: "Appendix",
heading: HeadingLevel.HEADING_1,
}),
new Paragraph({
text: "A. Methodology",
heading: HeadingLevel.HEADING_2,
}),
styledParagraph(
"Financial data was sourced from the ERP system (SAP S/4HANA) and reconciled against audited quarterly filings. Customer metrics were extracted from the CRM (Salesforce) with a data freshness cutoff of December 31, 2025."
),
styledParagraph(
"Year-over-year calculations compare FY2025 figures against FY2024 actuals. Operating margin is calculated as (Revenue - COGS - OpEx) / Revenue."
),
new Paragraph({
text: "B. Definitions",
heading: HeadingLevel.HEADING_2,
}),
styledParagraph("NPS (Net Promoter Score): Percentage of promoters minus detractors on a 0-10 scale.", {
numbering: { reference: "report-bullets", level: 0 },
}),
styledParagraph("ARR (Annual Recurring Revenue): Annualized value of active subscription contracts.", {
numbering: { reference: "report-bullets", level: 0 },
}),
styledParagraph("Churn Rate: Percentage of customers who cancelled in a given quarter.", {
numbering: { reference: "report-bullets", level: 0 },
}),
new Paragraph({
text: "C. Data Sources",
heading: HeadingLevel.HEADING_2,
}),
styledParagraph("SAP S/4HANA — Financial transactions and GL data", {
numbering: { reference: "report-bullets", level: 0 },
}),
styledParagraph("Salesforce CRM — Customer records, pipeline, and activity logs", {
numbering: { reference: "report-bullets", level: 0 },
}),
styledParagraph("Workday HCM — Employee headcount and satisfaction surveys", {
numbering: { reference: "report-bullets", level: 0 },
}),
styledParagraph("Google Analytics — Web traffic and conversion metrics", {
numbering: { reference: "report-bullets", level: 0 },
}),
];
}
// ─── Header and Footer ─────────────────────────────────────────────
function buildHeader() {
return new Header({
children: [
new Paragraph({
children: [
new TextRun({
text: "Acme Corp",
font: S.fonts.heading,
size: S.sizes.small,
bold: true,
color: S.colors.primary,
}),
new TextRun({ text: "\t" }),
new TextRun({
text: "Annual Performance Report — FY2025",
font: S.fonts.body,
size: S.sizes.caption,
color: S.colors.textLight,
}),
],
tabStops: [{ type: TabStopType.RIGHT, position: 9026 }],
border: {
bottom: { style: BorderStyle.SINGLE, size: 1, color: S.colors.borderColor, space: 4 },
},
}),
],
});
}
function buildFooter() {
return new Footer({
children: [
new Paragraph({
alignment: AlignmentType.CENTER,
border: {
top: { style: BorderStyle.SINGLE, size: 1, color: S.colors.borderColor, space: 4 },
},
children: [
new TextRun({
text: "CONFIDENTIAL | ",
font: S.fonts.body,
size: S.sizes.caption,
color: S.colors.textLight,
}),
new TextRun({
text: "Page ",
font: S.fonts.body,
size: S.sizes.caption,
color: S.colors.textLight,
}),
new TextRun({
children: [PageNumber.CURRENT],
font: S.fonts.body,
size: S.sizes.caption,
color: S.colors.text,
}),
new TextRun({
text: " of ",
font: S.fonts.body,
size: S.sizes.caption,
color: S.colors.textLight,
}),
new TextRun({
children: [PageNumber.TOTAL_PAGES],
font: S.fonts.body,
size: S.sizes.caption,
color: S.colors.text,
}),
],
}),
],
});
}
// ─── Assemble Document ──────────────────────────────────────────────
const doc = new Document({
creator: "Analytics Department",
title: "Annual Performance Report — FY2025",
description: "Comprehensive fiscal year performance analysis",
features: { updateFields: true },
numbering: {
config: [
{
reference: "report-bullets",
levels: [
{
level: 0,
format: LevelFormat.BULLET,
text: "\u2022",
alignment: AlignmentType.START,
style: {
paragraph: { indent: { left: 720, hanging: 360 } },
},
},
{
level: 1,
format: LevelFormat.BULLET,
text: "\u25E6",
alignment: AlignmentType.START,
style: {
paragraph: { indent: { left: 1440, hanging: 360 } },
},
},
],
},
],
},
styles: {
default: {
document: {
run: {
font: S.fonts.body,
size: S.sizes.body,
color: S.colors.text,
},
paragraph: {
spacing: { after: S.spacing.afterParagraph, line: S.spacing.lineSpacing },
},
},
heading1: {
run: {
font: S.fonts.heading,
size: S.sizes.heading1,
bold: true,
color: S.colors.primary,
},
paragraph: {
spacing: { before: 360, after: S.spacing.afterHeading1 },
},
},
heading2: {
run: {
font: S.fonts.heading,
size: S.sizes.heading2,
bold: true,
color: S.colors.accent,
},
paragraph: {
spacing: { before: 240, after: S.spacing.afterHeading2 },
},
},
heading3: {
run: {
font: S.fonts.heading,
size: S.sizes.heading3,
bold: true,
color: S.colors.text,
},
paragraph: {
spacing: { before: 160, after: 80 },
},
},
},
},
sections: [
// Title Page (no header/footer)
{
properties: {
page: {
margin: {
top: S.page.marginTop,
bottom: S.page.marginBottom,
left: S.page.marginLeft,
right: S.page.marginRight,
},
},
titlePage: true,
},
children: buildTitlePage(),
},
// Table of Contents
{
properties: {
type: SectionType.NEXT_PAGE,
page: {
margin: {
top: S.page.marginTop,
bottom: S.page.marginBottom,
left: S.page.marginLeft,
right: S.page.marginRight,
},
pageNumbers: { start: 1, formatType: NumberFormat.LOWER_ROMAN },
},
},
headers: { default: buildHeader() },
footers: { default: buildFooter() },
children: buildTableOfContents(),
},
// Main Content
{
properties: {
type: SectionType.NEXT_PAGE,
page: {
margin: {
top: S.page.marginTop,
bottom: S.page.marginBottom,
left: S.page.marginLeft,
right: S.page.marginRight,
},
pageNumbers: { start: 1, formatType: NumberFormat.DECIMAL },
},
},
headers: { default: buildHeader() },
footers: { default: buildFooter() },
children: [
...buildExecutiveSummary(),
...buildMetricsSection(),
...buildQuarterlyBreakdown(),
...buildChartPlaceholder(),
...buildAppendix(),
],
},
],
});
// ─── Export ──────────────────────────────────────────────────────────
async function generateReport(outputPath = "annual-report-fy2025.docx") {
const buffer = await Packer.toBuffer(doc);
fs.writeFileSync(outputPath, buffer);
console.log(`Report generated: ${outputPath}`);
}
generateReport();---
How to Use
Install
npm install docxRun
node generate-report.mjsCustomization Points
| What to Change | Where |
|---|---|
| Company branding colors | REPORT_STYLES.colors |
| Fonts | REPORT_STYLES.fonts |
| Page margins | REPORT_STYLES.page |
| Report data | metricsData, regionData arrays |
| Add a real logo | Replace logoPlaceholder with ImageRun |
| Add real charts | Render to PNG externally, embed via ImageRun |
| Change paper size | Section properties.page.size |
Adding a Real Logo
const logoBuffer = fs.readFileSync("assets/company-logo.png");
const logo = new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { before: 1200, after: 600 },
children: [
new ImageRun({
data: logoBuffer,
transformation: { width: 200, height: 60 },
type: "png",
}),
],
});Adding a Chart Image
// Pre-render your chart to PNG using Chart.js + node-canvas, or any charting library
const chartBuffer = fs.readFileSync("charts/revenue-trend.png");
const chartImage = new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new ImageRun({
data: chartBuffer,
transformation: { width: 560, height: 320 },
type: "png",
}),
],
});---
Architecture Notes
- Section-per-purpose: Title page, TOC, and main content are separate sections so each can have independent headers/footers and page numbering schemes.
- Helper functions:
cell(),dataTable(), andstyledParagraph()reduce boilerplate and enforce consistent styling. - Style configuration object: Centralizes all colors, fonts, and sizes for easy rebranding.
- `updateFields: true`: Prompts the user to update the Table of Contents when they first open the document.
- Alternating row colors: Applied via the
rowIdx % 2check indataTable()for readability.
MIT License
Copyright (c) 2026 Sithu Win San
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Word Document Formatting Reference (docx-js)
Comprehensive reference for programmatic Word document creation using the docx npm package.
Document Structure
Creating a Document
import {
Document, Packer, Paragraph, TextRun, Header, Footer,
PageNumber, NumberFormat, Table, TableRow, TableCell,
ImageRun, AlignmentType, HeadingLevel, TabStopType,
BorderStyle, ShadingType, WidthType, TableOfContents,
StyleLevel, PageOrientation, convertInchesToTwip,
LevelFormat, UnderlineType, SectionType
} from "docx";
const doc = new Document({
creator: "Author Name",
title: "Document Title",
description: "Document description",
sections: [
{
properties: { /* section properties */ },
headers: { default: new Header({ children: [] }) },
footers: { default: new Footer({ children: [] }) },
children: [ /* paragraphs, tables, etc. */ ],
},
],
});Sections
Each section can have its own page setup, headers, and footers.
const doc = new Document({
sections: [
{
properties: {
type: SectionType.NEXT_PAGE, // CONTINUOUS, EVEN_PAGE, ODD_PAGE
page: {
size: { width: 12240, height: 15840 }, // Letter size in twips
margin: {
top: convertInchesToTwip(1),
bottom: convertInchesToTwip(1),
left: convertInchesToTwip(1.25),
right: convertInchesToTwip(1.25),
},
},
},
children: [new Paragraph("Section 1 content")],
},
{
properties: {
type: SectionType.NEXT_PAGE,
page: {
size: { orientation: PageOrientation.LANDSCAPE },
},
},
children: [new Paragraph("Section 2 — landscape")],
},
],
});Headers and Footers
Three slots per section: default, first, even.
const header = new Header({
children: [
new Paragraph({
children: [
new TextRun({ text: "Company Name", bold: true, size: 18 }),
new TextRun({ text: "\t" }),
new TextRun({ text: "Confidential", italics: true, color: "888888" }),
],
tabStops: [{ type: TabStopType.RIGHT, position: 9026 }],
}),
],
});
const footer = new Footer({
children: [
new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new TextRun("Page "),
new TextRun({ children: [PageNumber.CURRENT] }),
new TextRun(" of "),
new TextRun({ children: [PageNumber.TOTAL_PAGES] }),
],
}),
],
});
// Attach to section
{
properties: {
page: {
pageNumbers: { start: 1, formatType: NumberFormat.DECIMAL },
},
},
headers: { default: header, first: firstPageHeader },
footers: { default: footer },
children: [],
}---
Paragraph Formatting
Alignment
new Paragraph({
text: "Centered text",
alignment: AlignmentType.CENTER,
// LEFT, RIGHT, JUSTIFIED, DISTRIBUTE, BOTH
});Spacing
All spacing values in half-points (1/20 of a point). Use convertInchesToTwip for inches.
new Paragraph({
text: "Spaced paragraph",
spacing: {
before: 240, // 12pt before
after: 120, // 6pt after
line: 276, // 1.15x line spacing (240 = single, 480 = double)
lineRule: "auto", // "auto", "exact", "atLeast"
},
});Indentation
new Paragraph({
text: "Indented paragraph",
indent: {
left: convertInchesToTwip(0.5),
right: convertInchesToTwip(0.25),
firstLine: convertInchesToTwip(0.5), // first-line indent
// hanging: convertInchesToTwip(0.5), // hanging indent (mutually exclusive with firstLine)
},
});Tab Stops
new Paragraph({
children: [
new TextRun("Left\tCenter\tRight"),
],
tabStops: [
{ type: TabStopType.CENTER, position: 4513 },
{ type: TabStopType.RIGHT, position: 9026 },
// TabStopType: LEFT, CENTER, RIGHT, DECIMAL, BAR
],
});---
Character Formatting
TextRun Options
new TextRun({
text: "Formatted text",
bold: true,
italics: true,
underline: { type: UnderlineType.SINGLE, color: "000000" },
// UnderlineType: SINGLE, DOUBLE, DOTTED, DASH, WAVE, THICK, NONE
strike: false,
doubleStrike: false,
subScript: false,
superScript: false,
allCaps: false,
smallCaps: false,
font: "Calibri",
size: 24, // half-points → 24 = 12pt
color: "2E74B5", // hex without #
highlight: "yellow",
// yellow, green, cyan, magenta, blue, red, darkBlue, darkCyan,
// darkGreen, darkMagenta, darkRed, darkYellow, darkGray, lightGray, black
shading: {
type: ShadingType.SOLID,
color: "FFFF00",
fill: "FFFF00",
},
characterSpacing: 20, // 1/20 of a point
});Font Embedding Considerations
docx-js references fonts by name. The rendering application must have the font installed. Stick to widely available fonts: Calibri, Arial, Times New Roman, Courier New, Segoe UI.
Hyperlinks
import { ExternalHyperlink } from "docx";
new Paragraph({
children: [
new ExternalHyperlink({
children: [
new TextRun({
text: "Visit our website",
style: "Hyperlink", // built-in hyperlink style
}),
],
link: "https://example.com",
}),
],
});---
Headings
new Paragraph({
text: "Chapter Title",
heading: HeadingLevel.HEADING_1,
// HEADING_1 through HEADING_6, TITLE
});---
Numbered and Bulleted Lists
Define Numbering
const doc = new Document({
numbering: {
config: [
{
reference: "my-numbering",
levels: [
{
level: 0,
format: LevelFormat.DECIMAL, // 1, 2, 3
text: "%1.",
alignment: AlignmentType.START,
style: { paragraph: { indent: { left: 720, hanging: 360 } } },
},
{
level: 1,
format: LevelFormat.LOWER_LETTER, // a, b, c
text: "%2)",
alignment: AlignmentType.START,
style: { paragraph: { indent: { left: 1440, hanging: 360 } } },
},
],
},
{
reference: "my-bullets",
levels: [
{
level: 0,
format: LevelFormat.BULLET,
text: "\u2022", // bullet character
alignment: AlignmentType.START,
style: { paragraph: { indent: { left: 720, hanging: 360 } } },
},
{
level: 1,
format: LevelFormat.BULLET,
text: "\u25E6", // white bullet
alignment: AlignmentType.START,
style: { paragraph: { indent: { left: 1440, hanging: 360 } } },
},
],
},
],
},
sections: [{ children: [] }],
});Use in Paragraphs
// Numbered list items
new Paragraph({
text: "First item",
numbering: { reference: "my-numbering", level: 0 },
});
new Paragraph({
text: "Sub-item",
numbering: { reference: "my-numbering", level: 1 },
});
// Bulleted list items
new Paragraph({
text: "Bullet point",
numbering: { reference: "my-bullets", level: 0 },
});---
Table Formatting
Basic Table
const table = new Table({
rows: [
new TableRow({
tableHeader: true, // mark as header row (repeats on page break)
children: [
new TableCell({
children: [new Paragraph({ text: "Header 1", bold: true })],
shading: { fill: "2E74B5", type: ShadingType.SOLID, color: "auto" },
width: { size: 3000, type: WidthType.DXA },
}),
new TableCell({
children: [new Paragraph({ text: "Header 2", bold: true })],
shading: { fill: "2E74B5", type: ShadingType.SOLID, color: "auto" },
width: { size: 3000, type: WidthType.DXA },
}),
],
}),
new TableRow({
children: [
new TableCell({ children: [new Paragraph("Row 1, Col 1")] }),
new TableCell({ children: [new Paragraph("Row 1, Col 2")] }),
],
}),
],
width: { size: 100, type: WidthType.PERCENTAGE },
});Cell Borders
new TableCell({
children: [new Paragraph("Bordered cell")],
borders: {
top: { style: BorderStyle.SINGLE, size: 1, color: "000000" },
bottom: { style: BorderStyle.SINGLE, size: 1, color: "000000" },
left: { style: BorderStyle.SINGLE, size: 1, color: "000000" },
right: { style: BorderStyle.SINGLE, size: 1, color: "000000" },
// BorderStyle: SINGLE, DOUBLE, DOTTED, DASHED, THICK, NONE, NIL
},
});Cell Shading
new TableCell({
children: [new Paragraph("Shaded cell")],
shading: {
fill: "D9E2F3",
type: ShadingType.SOLID,
color: "auto",
},
});Column Widths
// Fixed widths (DXA = 1/20 of a point)
{ width: { size: 2400, type: WidthType.DXA } }
// Percentage widths
{ width: { size: 50, type: WidthType.PERCENTAGE } }
// Auto width
{ width: { size: 0, type: WidthType.AUTO } }Merged Cells
// Horizontal merge
new TableRow({
children: [
new TableCell({
children: [new Paragraph("Merged across 3 columns")],
columnSpan: 3,
}),
],
});
// Vertical merge
new TableCell({
children: [new Paragraph("Span start")],
rowSpan: 2, // spans this row + next row
});Cell Vertical Alignment and Margins
import { VerticalAlign } from "docx";
new TableCell({
children: [new Paragraph("Centered vertically")],
verticalAlign: VerticalAlign.CENTER, // TOP, CENTER, BOTTOM
margins: {
top: convertInchesToTwip(0.05),
bottom: convertInchesToTwip(0.05),
left: convertInchesToTwip(0.1),
right: convertInchesToTwip(0.1),
},
});---
Image Handling
Inline Image
import fs from "fs";
const imageBuffer = fs.readFileSync("logo.png");
new Paragraph({
children: [
new ImageRun({
data: imageBuffer,
transformation: {
width: 200, // pixels
height: 100,
},
type: "png", // "png", "jpg", "gif", "bmp"
}),
],
});Floating Image
import { HorizontalPositionAlign, VerticalPositionAlign } from "docx";
new Paragraph({
children: [
new ImageRun({
data: imageBuffer,
transformation: { width: 150, height: 150 },
floating: {
horizontalPosition: {
align: HorizontalPositionAlign.RIGHT,
},
verticalPosition: {
align: VerticalPositionAlign.TOP,
},
wrap: {
type: "square", // "square", "tight", "topAndBottom", "none"
side: "bothSides", // "bothSides", "left", "right", "largest"
},
margins: {
top: convertInchesToTwip(0.1),
bottom: convertInchesToTwip(0.1),
left: convertInchesToTwip(0.1),
right: convertInchesToTwip(0.1),
},
},
}),
],
});---
Styles and Style Inheritance
Custom Styles
const doc = new Document({
styles: {
default: {
document: {
run: { font: "Calibri", size: 22, color: "333333" },
paragraph: { spacing: { after: 120, line: 276 } },
},
heading1: {
run: { font: "Calibri Light", size: 32, bold: true, color: "2E74B5" },
paragraph: { spacing: { before: 360, after: 120 } },
},
heading2: {
run: { font: "Calibri Light", size: 26, bold: true, color: "2E74B5" },
paragraph: { spacing: { before: 240, after: 80 } },
},
},
paragraphStyles: [
{
id: "customQuote",
name: "Custom Quote",
basedOn: "Normal",
next: "Normal",
run: { italics: true, color: "666666" },
paragraph: {
indent: { left: convertInchesToTwip(0.5) },
spacing: { before: 120, after: 120 },
},
},
],
characterStyles: [
{
id: "codeInline",
name: "Inline Code",
run: { font: "Courier New", size: 20, color: "C7254E" },
},
],
},
sections: [{ children: [] }],
});
// Using custom paragraph style
new Paragraph({ text: "A quotation", style: "customQuote" });
// Using custom character style
new TextRun({ text: "codeSnippet", style: "codeInline" });---
Page Setup
Margins and Orientation
{
properties: {
page: {
size: {
width: 12240, // 8.5" in twips
height: 15840, // 11" in twips
orientation: PageOrientation.PORTRAIT,
// PORTRAIT, LANDSCAPE
},
margin: {
top: convertInchesToTwip(1),
bottom: convertInchesToTwip(1),
left: convertInchesToTwip(1),
right: convertInchesToTwip(1),
header: convertInchesToTwip(0.5),
footer: convertInchesToTwip(0.5),
gutter: 0,
},
},
},
}Common Paper Sizes (in twips)
| Paper | Width | Height |
|---|---|---|
| Letter | 12240 | 15840 |
| A4 | 11906 | 16838 |
| Legal | 12240 | 20160 |
| A3 | 16838 | 23811 |
Page Borders
{
properties: {
page: {
borders: {
pageBorderTop: { style: BorderStyle.SINGLE, size: 3, color: "000000", space: 24 },
pageBorderBottom: { style: BorderStyle.SINGLE, size: 3, color: "000000", space: 24 },
pageBorderLeft: { style: BorderStyle.SINGLE, size: 3, color: "000000", space: 24 },
pageBorderRight: { style: BorderStyle.SINGLE, size: 3, color: "000000", space: 24 },
},
},
},
}---
Table of Contents
const doc = new Document({
features: { updateFields: true }, // prompt user to update fields on open
sections: [
{
children: [
new TableOfContents("Table of Contents", {
hyperlink: true,
headingStyleRange: "1-3", // include Heading 1–3
stylesWithLevels: [
new StyleLevel("customHeading", 1),
],
}),
new Paragraph({
text: "",
pageBreakBefore: true,
}),
new Paragraph({
text: "Introduction",
heading: HeadingLevel.HEADING_1,
}),
new Paragraph("Content under Introduction..."),
],
},
],
});---
Exporting the Document
To File (Node.js)
import { Packer } from "docx";
import fs from "fs";
const buffer = await Packer.toBuffer(doc);
fs.writeFileSync("output.docx", buffer);To Blob (Browser)
const blob = await Packer.toBlob(doc);
const url = URL.createObjectURL(blob);
// Trigger download
const a = document.createElement("a");
a.href = url;
a.download = "output.docx";
a.click();To Base64
const base64 = await Packer.toBase64String(doc);---
Quick Reference: Import Checklist
import {
Document, Packer, Paragraph, TextRun, ImageRun,
Header, Footer, PageNumber, NumberFormat,
Table, TableRow, TableCell,
AlignmentType, HeadingLevel, TabStopType,
BorderStyle, ShadingType, WidthType, VerticalAlign,
ExternalHyperlink, TableOfContents, StyleLevel,
PageOrientation, SectionType, LevelFormat,
UnderlineType, HorizontalPositionAlign, VerticalPositionAlign,
convertInchesToTwip,
} from "docx";"""
Word Document Template Generator
This script generates Microsoft Word document templates
for common business documents like reports, letters, and memos.
Usage: python scripts/doc-template-generator.py
"""
from typing import Dict, List, Any, Optional
import json
class DocumentTemplate:
"""Base class for document templates."""
def __init__(self, filename: str):
self.filename = filename
self.content = []
def add_paragraph(self, text: str, style: str = "Normal") -> Dict:
"""Add a paragraph to the document."""
return {
"type": "paragraph",
"text": text,
"style": style
}
def add_heading(self, text: str, level: int = 1) -> Dict:
"""Add a heading to the document."""
return {
"type": "heading",
"text": text,
"level": level
}
def add_table(self, headers: List[str], rows: List[List[str]]) -> Dict:
"""Add a table to the document."""
return {
"type": "table",
"headers": headers,
"rows": rows
}
def add_list(self, items: List[str], ordered: bool = False) -> Dict:
"""Add a list to the document."""
return {
"type": "list",
"items": items,
"ordered": ordered
}
class ReportTemplate(DocumentTemplate):
"""Template for formal business reports."""
def create_cover_page(self, title: str, subtitle: str, author: str, date: str) -> List[Dict]:
"""Create a cover page for the report."""
return [
self.add_heading(title, level=1),
self.add_paragraph(subtitle, "Subtitle"),
self.add_paragraph(f"Prepared by: {author}", "Author"),
self.add_paragraph(f"Date: {date}", "Date"),
self.add_paragraph("", "Normal") # Empty paragraph for spacing
]
def create_executive_summary(self, summary: str) -> List[Dict]:
"""Create an executive summary section."""
return [
self.add_heading("Executive Summary", level=2),
self.add_paragraph(summary)
]
def create_table_of_contents(self) -> Dict:
"""Create a table of contents placeholder."""
return {
"type": "table_of_contents"
}
def create_section(self, title: str, content: List[str]) -> List[Dict]:
"""Create a report section."""
section = [self.add_heading(title, level=2)]
for paragraph in content:
section.append(self.add_paragraph(paragraph))
return section
def create_findings_section(self, findings: List[Dict[str, str]]) -> List[Dict]:
"""Create a findings section with key findings."""
section = [self.add_heading("Key Findings", level=2)]
for finding in findings:
section.append(self.add_heading(finding.get("title", ""), level=3))
section.append(self.add_paragraph(finding.get("description", "")))
return section
class MemoTemplate(DocumentTemplate):
"""Template for internal memos."""
def create_memo_header(self, to: str, from_: str, date: str, subject: str) -> List[Dict]:
"""Create memo header."""
return [
self.add_paragraph("MEMORANDUM", "MemoTitle"),
self.add_paragraph(f"To: {to}", "MemoField"),
self.add_paragraph(f"From: {from_}", "MemoField"),
self.add_paragraph(f"Date: {date}", "MemoField"),
self.add_paragraph(f"Subject: {subject}", "MemoField"),
self.add_paragraph("", "Normal")
]
def create_memo_body(self, paragraphs: List[str]) -> List[Dict]:
"""Create memo body content."""
return [self.add_paragraph(p) for p in paragraphs]
class LetterTemplate(DocumentTemplate):
"""Template for formal business letters."""
def create_letter_header(self, sender_name: str, sender_address: List[str],
recipient_name: str, recipient_address: List[str],
date: str) -> List[Dict]:
"""Create letter header."""
header = [
self.add_paragraph(sender_name, "SenderName"),
self.add_paragraph("\n".join(sender_address), "SenderAddress"),
self.add_paragraph("", "Normal"),
self.add_paragraph(date, "Date"),
self.add_paragraph("", "Normal"),
self.add_paragraph(recipient_name, "RecipientName"),
self.add_paragraph("\n".join(recipient_address), "RecipientAddress"),
self.add_paragraph("", "Normal")
]
return header
def create_salutation(self, recipient_name: str) -> Dict:
"""Create letter salutation."""
return self.add_paragraph(f"Dear {recipient_name},")
def create_letter_body(self, paragraphs: List[str]) -> List[Dict]:
"""Create letter body content."""
return [self.add_paragraph(p) for p in paragraphs]
def create_closing(self, sender_name: str, sender_title: str) -> List[Dict]:
"""Create letter closing."""
return [
self.add_paragraph("Sincerely,"),
self.add_paragraph(sender_name),
self.add_paragraph(sender_title, "Title")
]
def export_mcp_commands(content: List[Dict], filename: str) -> str:
"""Export document content as MCP commands."""
commands = []
commands.append("// Activate Word document tools")
commands.append("activate_document_content_and_styling();")
commands.append("")
commands.append(f"// Create document: {filename}")
commands.append(f'mcp_word_create_document({{ filename: "{filename}" }});')
commands.append("")
for item in content:
if item["type"] == "heading":
level = item.get("level", 1)
commands.append(f'mcp_word_add_heading({{ text: "{item["text"]}", level: {level} }});')
elif item["type"] == "paragraph":
commands.append(f'mcp_word_add_paragraph({{ text: "{item["text"]}" }});')
elif item["type"] == "table":
headers = json.dumps(item["headers"])
rows = json.dumps(item["rows"])
commands.append(f'mcp_word_add_table({{ headers: {headers}, rows: {rows} }});')
elif item["type"] == "list":
items = json.dumps(item["items"])
ordered = "true" if item.get("ordered") else "false"
commands.append(f'mcp_word_add_list({{ items: {items}, ordered: {ordered} }});')
elif item["type"] == "table_of_contents":
commands.append('// Table of contents - add via Word UI or reference styles')
commands.append("")
commands.append(f"// Save document")
commands.append(f'mcp_word_save_document({{ filename: "{filename}" }});')
return "\n".join(commands)
# Example usage
def create_quarterly_report() -> str:
"""Example: Create a quarterly business report."""
report = ReportTemplate("q3_business_report.docx")
content = []
content.extend(report.create_cover_page(
title="Q3 2025 Business Report",
subtitle="Finance Division",
author="Finance Team",
date="October 2025"
))
content.append(report.create_table_of_contents())
content.append(report.add_paragraph("", "Normal")) # Page break
content.extend(report.create_executive_summary(
"Q3 showed strong performance with 20% revenue growth year-over-year, "
"driven primarily by expansion in the APAC region. Operating margins improved "
"to 33% through cost optimization initiatives."
))
content.extend(report.create_section("Financial Highlights", [
"Revenue reached $1.8M, representing a 20% increase compared to Q3 2024.",
"Gross margin expanded to 45%, a 3 percentage point improvement.",
"Operating income grew to $540K, up 25% year-over-year."
]))
content.extend(report.create_section("Regional Performance", [
"APAC region led growth with a 35% increase, driven by new market entries.",
"Americas showed steady growth of 15% with strong performance in key accounts.",
"EMEA exceeded targets with 12% growth despite challenging market conditions."
]))
content.extend(report.create_findings_section([
{
"title": "Strong Revenue Growth",
"description": "Revenue growth of 20% YoY exceeded expectations, driven by "
"successful product launches and market expansion."
},
{
"title": "Margin Expansion",
"description": "Gross margin improved by 3 percentage points through "
"strategic sourcing and operational efficiencies."
},
{
"title": "Market Share Gains",
"description": "Gained market share in key segments, particularly in "
"APAC where new product offerings resonated with customers."
}
]))
return export_mcp_commands(content, report.filename)
def create_internal_memo() -> str:
"""Example: Create an internal memo."""
memo = MemoTemplate("all_hands_meeting.docx")
content = []
content.extend(memo.create_memo_header(
to="All Staff",
from_="Executive Team",
date="October 15, 2025",
subject="Q3 All-Hands Meeting"
))
content.extend(memo.create_memo_body([
"Please join us for our quarterly all-hands meeting on Friday, October 20th "
"at 2:00 PM in the main conference room.",
"Agenda items include:",
"Q3 business review and financial results",
"Product roadmap updates",
"Employee recognition and awards",
"Q&A session with leadership",
"Light refreshments will be served. Please RSVP by Wednesday, October 18th.",
"We look forward to seeing you there!"
]))
return export_mcp_commands(content, memo.filename)
if __name__ == "__main__":
print("=" * 80)
print("Word Document Template Generator")
print("=" * 80)
print()
print("Example 1: Quarterly Business Report")
print("-" * 80)
print(create_quarterly_report())
print()
print("=" * 80)
print("Example 2: Internal Memo")
print("-" * 80)
print(create_internal_memo())
Related skills
How it compares
Pick word-document for agent-driven .docx with OOXML verification; use draw-io when the deliverable is architecture diagrams rather than Word reports.
FAQ
What file format does word-document target?
word-document automates Microsoft Word .docx files using OOXML-aware workflows. Agents can create new documents, apply structured edits, and run verification checks before delivering the final file.
What changed in word-document version 1.2?
word-document version 1.2 added a Verification Protocol with pass/fail checks, one pressure-test scenario, a measurable success metric, and MCP Fallback to Native Automation guidance for Office-style workflows.
Does word-document work without an Office MCP server?
word-document includes an MCP Fallback to Native Automation section so agents can still create and verify .docx files when Office MCP tooling is unavailable, following the same OOXML workflow steps.
Is Word Document safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.