Ten self-contained Word document tasks that probe how well a model creates and edits .docx files β from simple generate_docx memos to advanced docx-js scripts with custom styles, tables of contents, headers/footers, embedded images, and tracked changes via XML editing. Each task has a copy-paste prompt, a verify command, and clear pass criteria.
These tasks test the docx and docx-advanced skills β the model's ability to produce well-structured, professional .docx files using the generate_docx MCP tool and the docx-js library. Tasks 1β4 use generate_docx (simple). Tasks 5β10 require docx-js scripting (advanced). Start at Task 1 and work up.
These tasks use the generate_docx MCP tool and the docx npm package for scripting. Knowing the conventions helps you evaluate whether the model followed the skill correctly.
| Concept | Rule | Why |
|---|---|---|
| generate_docx | Use for simple documents. Sections with heading + paragraphs + tables. | Zero scripting β fast and reliable |
| docx-js | Use for images, custom styles, TOC, headers/footers, footnotes. | Advanced features not in generate_docx |
| Page size | Always set explicitly (US Letter 12240Γ15840 DXA) | docx-js defaults to A4 |
| Lists | Never unicode bullets β use LevelFormat.BULLET + numbering config | Survives round-trip in Word / Google Docs |
| Tables | Dual widths: columnWidths array + cell width, both WidthType.DXA | Never use PERCENTAGE (breaks Google Docs) |
| Shading | Use ShadingType.CLEAR, never SOLID | SOLID makes backgrounds opaque in Word |
| PageBreak | Must be inside a Paragraph | docx-js requires it |
| ImageRun | Requires type field ("png" / "jpeg") | Missing type produces corrupt documents |
| Smart quotes | Use XML entities: “ / ” | Raw Unicode breaks in some XML parsers |
| Tracked changes | <w:ins> for insertions, <w:del> for deletions | Author must be "Claude" |
You need one terminal with the Aperio server running on your preferred AI provider. Paste each task prompt into the chat (web UI or CLI).
npm run start:local # or any AI_PROVIDER, port 31337
Paste each task's prompt into the chat. Use a fresh conversation per task when possible. After the model responds, check that the .docx file was created, then run the Verify command.
Tasks 1β4 use the generate_docx MCP tool β no scripting needed. Tasks 5β10 require docx-js scripting where the model writes a Node.js script using the docx npm package. The verify commands use Python 3 (stdlib zipfile for XML inspection) and the project's own validate.py script.
If you want to re-run tasks against a different model, clean up the output files first:
rm -f trash/test-*.docx
rm -rf trash/test-unpacked
Ordered by complexity: simple generate_docx first (memos, letters, reports), then docx-js scripting (lists, styles, TOC, headers/footers, images, tracked changes). Each task lists difficulty, what to look for, the prompt to paste, and the verify command.
Probes: basic generate_docx usage, heading + paragraphs structure
Files:1 new file (trash/test-memo.docx)
trash/test-memo.docx using the generate_docx tool. It should be an internal memorandum with:
- A heading "MEMORANDUM"
- A block of fields: To, From, Date, Subject (each on its own line, bold labels)
- 2β3 body paragraphs about Q4 quarterly results (meeting targets, growth highlights, next steps)
- Use Arial font throughout
Do NOT write a script β use the generate_docx tool directly.python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-memo.docx'); xml=z.read('word/document.xml').decode(); p=xml.count('=5 and h>=1, 'Need >=5 paragraphs and >=1 styled heading'; print('OK β memo structure valid')" Probes: generate_docx with table, structured content
Files:1 new file (trash/test-minutes.docx)
trash/test-minutes.docx using generate_docx. Structure:
- Heading 1: "Meeting Minutes β Project Alpha Kickoff"
- Paragraph: date, location, attendees summary
- A table with columns: Agenda Item, Owner, Time Allotted, Notes. Fill with 5 agenda items (Project Overview, Timeline Review, Budget Discussion, Risk Assessment, Next Steps).
- Paragraph: "Action Items" heading followed by a brief list of next steps.
- Use Arial font. Bold the table header row.python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-minutes.docx'); xml=z.read('word/document.xml').decode(); tbl=xml.count('=1 and rows>=5, 'Need >=1 table and >=5 rows'; print('OK β meeting minutes contain table')" Probes: generate_docx layout control, multi-paragraph structure, spacing
Files:1 new file (trash/test-letter.docx)
trash/test-letter.docx using generate_docx. Include:
- Sender block: "Aperio Inc., 123 Tech Street, San Francisco, CA 94105"
- Date line: current date
- Recipient block: "Dr. Sarah Chen, Chief AI Officer, NovaCloud Systems"
- Salutation: "Dear Dr. Chen,"
- Body: 2 paragraphs proposing a partnership for integrating Aperio's memory layer into NovaCloud's agent platform
- Closing: "Sincerely,", a blank line, then "Lyuben Kikov, CTO, Aperio Inc."
- Use a professional layout with appropriate spacing between sections. Use Arial font, 11pt.python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-letter.docx'); xml=z.read('word/document.xml').decode(); p=xml.count('=8 and not missing, f'Missing: {missing}'; print('OK β letter structure complete')" Probes: generate_docx with multiple sections, heading hierarchy, varied content
Files:1 new file (trash/test-report.docx)
trash/test-report.docx using generate_docx. It must have exactly 3 sections, each with a heading and content:
Section 1 β "Executive Summary"
- A brief overview paragraph describing Aperio as a personal memory layer for AI agents.
- A small table with metrics: Active Users, Stored Memories, API Calls (use realistic numbers).
Section 2 β "Technical Architecture"
- 2 paragraphs describing the modular design: SQLite/Postgres backend, MCP integration, plugin system.
- Key features listed as plain text lines (not a real list β just separate paragraphs with feature names).
Section 3 β "Roadmap"
- 2 paragraphs covering Q1 and Q2 milestones.
- A closing note about community contributions.
Use Heading 1 for the document title and section headings. Use Arial font throughout.python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-report.docx'); xml=z.read('word/document.xml').decode(); p=xml.count('=10 and tbl>=1, 'Need >=10 paragraphs and >=1 table'; # Check headings via style refs; import re; heading_styles=len(re.findall(r'=3, 'Need >=3 heading references'; print('OK β report has 3+ sections')" Probes: docx-js numbering config, LevelFormat, no unicode bullets
Files:1 script + 1 output (trash/create-lists.js β trash/test-lists.docx)
trash/create-lists.js that creates trash/test-lists.docx with:
Section 1 β Bulleted list of 5 Aperio features (Memory Layer, MCP Integration, Code Graph, Wiki, Multi-Provider). Use proper numbering config with LevelFormat.BULLET β do NOT use unicode bullet characters.
Section 2 β Numbered list of 5 setup steps (Clone Repo, Install Dependencies, Configure .env, Run Migrations, Start Server). Use LevelFormat.DECIMAL.
Requirements:
- Use import syntax with the docx npm package
- Set page size explicitly to US Letter
- Arial font, 11pt body text
- The script must use writeFileSync to save to trash/test-lists.docx
- Print the output path to console when donenumbering.config with LevelFormat?<w:numPr> elements (no unicode bullets)?python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-lists.docx', 'r'); xml=z.read('word/document.xml').decode(); import re; nums=len(re.findall(r'', xml)); unicode_bullets=len(re.findall(r'[\\u2022\\u2023\\u25E6\\u2043]', xml)); print('numPr references:',nums,'Unicode bullets:',unicode_bullets); assert nums>=8, 'Need >=8 numbering references'; assert unicode_bullets==0, 'Has unicode bullets β FAIL'; print('OK β proper numbering with zero unicode bullets')" Probes: docx-js styles config, heading level overrides, font consistency
Files:1 script + 1 output (trash/create-styles.js β trash/test-styles.docx)
trash/create-styles.js that creates trash/test-styles.docx with custom heading styles:
Custom styles:
- Heading 1: 28pt, bold, Arial, color: dark blue (003366), spacing before 240 after 120
- Heading 2: 22pt, bold, Arial, color: dark teal (004d40), spacing before 180 after 80
- Normal: 11pt, Arial
Document content:
- Heading 1: "Project Charter"
- 2 paragraphs of body text
- Heading 2: "Scope"
- 1 paragraph
- Heading 2: "Deliverables"
- A table with columns: Deliverable, Owner, Deadline (3 rows)
- Heading 2: "Budget"
- 1 paragraph
Run the script with node trash/create-styles.js to produce the output.validate.py pass?python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-styles.docx'); sx=z.read('word/styles.xml').decode(); dx=z.read('word/document.xml').decode(); h1=sx.count('Heading1'); h2=sx.count('Heading2'); tbl=dx.count('=2 and h2>=2 and tbl>=1, 'Need Heading1/2 style defs and table'; print('OK β custom styles present')"
python3 skills/docx/scripts/office/validate.py trash/test-styles.docx Probes: TableOfContents, headingStyleRange, outlineLevel, page breaks
Files:1 script + 1 output (trash/create-toc.js β trash/test-toc.docx)
trash/create-toc.js that creates trash/test-toc.docx β a multi-page document with a Table of Contents:
Requirements:
- Set page size to US Letter
- Title page: centered "Aperio Technical Reference", then a PageBreak
- Table of Contents using TableOfContents with headingStyleRange: "1-2" and hyperlinks enabled
- Followed by these sections, each starting on a new page (PageBreak before each):
- **Heading 1 "Introduction"** β 2 paragraphs of text
- **Heading 2 "Core Architecture"** β 1 paragraph
- **Heading 2 "Plugin System"** β 1 paragraph
- **Heading 1 "Installation Guide"** β 2 paragraphs
- **Heading 2 "Prerequisites"** β 1 paragraph
- **Heading 2 "Configuration"** β 1 paragraph
- **Heading 1 "API Reference"** β 2 paragraphs
- Headings MUST use HeadingLevel values only (not custom strings)
- Include outlineLevel in heading paragraph properties (0 for H1, 1 for H2)
- Arial font throughout
Run with node trash/create-toc.js.HeadingLevel with outlineLevel?python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-toc.docx'); dx=z.read('word/document.xml').decode(); import re; h1=len(re.findall(r'Heading1', dx)); h2=len(re.findall(r'Heading2', dx)); toc='TableOfContents' in dx; outline=dx.count('outlineLevel'); print('H1 refs:',h1,'H2 refs:',h2,'TOC:',toc,'outlineLevel:',outline); assert h1>=3 and h2>=4 and toc and outline>=5, 'Need >=3 H1, >=4 H2, TOC, and outlineLevel'; print('OK β TOC and heading structure valid')"Probes: Header/Footer elements, PageNumber, multi-page layout
Files:1 script + 1 output (trash/create-header.js β trash/test-header.docx)
trash/create-header.js that creates trash/test-header.docx:
Layout:
- US Letter page size, 1-inch margins
- Header (default): Left-aligned text "Aperio β Internal Document" in italic, 9pt
- Footer (default): Centered "Page X" using PageNumber.CURRENT
- Title: "Employee Handbook" (Heading 1, centered)
- Paragraph: brief introduction
- PageBreak
- Heading 2 "Code of Conduct" + 1 paragraph
- PageBreak
- Heading 2 "Remote Work Policy" + 1 paragraph
The header must appear on all pages. Use Arial font. Run with node trash/create-header.js.PageNumber?python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-header.docx'); import re; files=z.namelist(); header_files=[f for f in files if 'header' in f.lower()]; footer_files=[f for f in files if 'footer' in f.lower()]; dx=z.read('word/document.xml').decode(); has_pagebreak='w:br' in dx and 'type=\"page\"' in dx; print('Header files:',header_files,'Footer files:',footer_files,'PageBreak:',has_pagebreak); assert len(header_files)>=1 and len(footer_files)>=1, 'Need header and footer files'; assert has_pagebreak, 'Need page breaks'; print('OK β header, footer, and page breaks present')"Probes: ImageRun, data loading, alt text, type field
Files:1 script + 1 output (trash/create-image.js β trash/test-image.docx)
trash/create-image.js that creates trash/test-image.docx with an embedded image:
Requirements:
- US Letter page, 1-inch margins
- Title: "Aperio Logo Reference" (Heading 1, centered)
- A paragraph: "The official Aperio logo appears below."
- An ImageRun embedding public/assets/aperio-logo.png (or any PNG in public/assets/ β use fs.readFileSync to load it)
- type must be specified (e.g., "png")
- transformation: width 300, height auto-proportional
- altText with title and description
- Below the image: a caption paragraph in italic
- A second paragraph: "The Aperio favicon is also available." followed by a second ImageRun embedding the favicon from public/assets/favicon.ico (may need to skip if format unsupported β just load a PNG if .ico fails)
- Use Arial font throughout
Run with node trash/create-image.js.word/_rels/document.xml.rels?word/media/ inside the docx?type field specified on ImageRun?python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-image.docx'); files=z.namelist(); rels=z.read('word/_rels/document.xml.rels').decode(); media=[f for f in files if 'media' in f]; has_image='Image' in rels or 'image/' in rels; print('Media files:',media,'Image in rels:',has_image); assert len(media)>=1 and has_image, 'Need image in media/ and relationship'; print('OK β image embedded with relationship')"Probes: unpack/edit/repack pipeline, tracked changes XML, comments
Files:1 source file + output (create trash/test-source.docx first β edit β trash/test-tracked.docx)
generate_docx to create trash/test-source.docx. It should be a simple contract clause: heading "Service Agreement β Section 4: Payment Terms" followed by 3 paragraphs of legalese about payment schedules, late fees, and invoicing.
Step 2 β Unpack
Unpack the source file using the project's unpack script:
python3 skills/docx/scripts/office/unpack.py /abs/path/to/trash/test-source.docx /abs/path/to/trash/test-unpacked
Step 3 β Add tracked changes
Edit trash/test-unpacked/word/document.xml to add tracked changes:
- Change the payment period from "30 days" to "45 days" using a tracked deletion (<w:del>) of "30" and tracked insertion (<w:ins>) of "45"
- Change the late fee from "1.5%" to "2.0%" using the same pattern
- Use author="Claude" and a reasonable date
Step 4 β Add a comment
Run python3 skills/docx/scripts/comment.py /abs/path/to/trash/test-unpacked 0 "Needs legal review before signing."
Then add <w:commentRangeStart>, <w:commentRangeEnd>, and <w:commentReference> around the first tracked change.
Step 5 β Repack
python3 skills/docx/scripts/office/pack.py /abs/path/to/trash/test-unpacked /abs/path/to/trash/test-tracked.docx --original /abs/path/to/trash/test-source.docx
Verify with:
python3 skills/docx/scripts/office/validate.py trash/test-tracked.docx --original trash/test-source.docx<w:ins> and <w:del>)?word/comments.xml?validate.py --original detect and report the changes correctly?python3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-tracked.docx'); dx=z.read('word/document.xml').decode(); has_ins='
python3 skills/docx/scripts/office/validate.py trash/test-tracked.docx --original trash/test-source.docxApply these five signals to each task after running the verify command. They measure not just "does the file exist" but also "did the model follow the skill's conventions and verify its own work".
| Signal | 0 = fail | 1 = pass |
|---|---|---|
| File created at correct path | wrong path / wrong format | correct trash/test-*.docx |
| Verify command passes | red / missing file / Python errors | green, zero warnings |
| Uses correct tool for the task | wrote a script when generate_docx was enough | generate_docx for 1β4, docx-js script for 5β9, pipeline for 10 |
| Follows skill conventions | unicode bullets, no page size, missing ImageRun type | proper numbering, explicit page size, correct XML |
| Model verified its own work | claimed "looks good" without checking | ran validate.py or inspected the output |
Results fill in automatically as you click the buttons above.
| Test | Result | Notes |
|---|---|---|
| 1. Memo (generate_docx) | β | |
| 2. Meeting Minutes (Table) | β | |
| 3. Business Letter | β | |
| 4. Multi-Section Report | β | |
| 5. Proper Bulleted/Numbered Lists | β | |
| 6. Custom Heading Styles | β | |
| 7. Table of Contents | β | |
| 8. Header/Footer & Page Numbers | β | |
| 9. Embedded Images | β | |
| 10. Tracked Changes Pipeline | β | |
| TOTAL: ____ / 10 passed | ||
docx npm package (already a dependency)..docx files.The task order traces a curve from shallow to deep document-creation understanding:
generate_docx memos (1) β tables in documents (2) β structured letters (3) β multi-section reports (4) β proper numbered lists (5) β custom heading styles (6) β TOC with heading levels (7) β headers/footers with page numbers (8) β embedded images (9) β tracked changes via XML editing (10)
A model that drops off after Task 4 knows generate_docx but not docx-js. One that drops off after Task 7 can script basic docs but not advanced features. A model that passes all 10 understands the full document-creation stack.