Docx template fill
[COLM'26] SkillLearnBench is the first benchmark for evaluating continual learning methods that automatically generate agent skills.
npx -y skills add cxcscmu/SkillLearnBench --skill docx-template-fillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Fill Word document (.docx) templates that use placeholder syntax like {{PLACEHOLDER}}. Handles split placeholders (where Word splits a placeholder across multiple XML runs), conditional sections ({{IF_X}}...{{END_IF_X}}), and preserves formatting. Use this skill whenever the user asks to fill a Word template, generate a document from a template, or replace placeholders in a .docx file.
SKILL.md
3.5 KB, as published. Nobody here has run it
DOCX Template Fill
Core Challenge: Split Placeholders
Word internally splits text into "runs" based on formatting changes, spell-check boundaries,
or editing history. A placeholder like {{COMPANY_NAME}} may become three runs:
{{COMP + ANY_ + NAME}}. Naive per-run replacement will fail.
Strategy
-
Merge-then-replace at the run level: For each paragraph (and header/footer/table cell paragraph), concatenate all run texts, perform regex replacements on the merged string, then redistribute text back to runs — putting all text in the first run and clearing the rest. This preserves the first run's formatting.
-
Process all text containers: Paragraphs live in the document body, but also in:
- Table cells (iterate
doc.tables[*].rows[*].cells[*].paragraphs) - Section headers (
doc.sections[*].header.paragraphs) - Section footers (
doc.sections[*].footer.paragraphs)
- Table cells (iterate
-
Conditional sections: For
{{IF_KEY}}...content...{{END_IF_KEY}}:- If condition is true (value is "Yes"), remove only the markers, keep content
- If condition is false, remove markers and all content between them
- Conditionals may span a single paragraph or the markers may be in separate runs
Implementation Pattern
import re, json
from docx import Document
def replace_in_paragraph(paragraph, replacements):
"""Replace placeholders in a paragraph, handling split runs."""
full_text = "".join(run.text for run in paragraph.runs)
if not full_text:
return
new_text = full_text
for key, value in replacements.items():
new_text = new_text.replace("{{" + key + "}}", value)
if new_text != full_text:
# Put all text in first run, clear the rest (preserves first run's formatting)
for i, run in enumerate(paragraph.runs):
if i == 0:
run.text = new_text
else:
run.text = ""
def handle_conditional(paragraph, key, keep):
"""Handle {{IF_key}}...{{END_IF_key}} within a single paragraph."""
full_text = "".join(run.text for run in paragraph.runs)
pattern = r"\{\{IF_" + key + r"\}\}(.*?)\{\{END_IF_" + key + r"\}\}"
if re.search(pattern, full_text):
if keep:
new_text = re.sub(pattern, r"\1", full_text)
else:
new_text = re.sub(pattern, "", full_text)
for i, run in enumerate(paragraph.runs):
run.text = new_text if i == 0 else ""
def process_all_paragraphs(doc, func, *args):
"""Apply a function to every paragraph in the document."""
for p in doc.paragraphs:
func(p, *args)
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for p in cell.paragraphs:
func(p, *args)
for section in doc.sections:
for p in section.header.paragraphs:
func(p, *args)
for p in section.footer.paragraphs:
func(p, *args)
Workflow
- Load data (JSON) and template (docx)
- Handle conditionals first (before placeholder replacement)
- Replace all
{{KEY}}placeholders with values from data - Save the filled document