docx

Create, read, edit, template, and review Word .docx files.

  • word
  • docx
  • documents
  • office
  • templates
  • revisions
  • comments

Declared platforms: linux · macos · windows

Install
npx skills add 'https://github.com/NousResearch/hermes-agent/tree/main/skills/productivity/docx'
Download bundle ↓
main · 24fd22bScanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md
#!/usr/bin/env python3# MIT License. Part of the Hermes docx skill."""Fill {{placeholder}} tokens in a .docx from a JSON mapping. Tokens are replaced everywhere: body paragraphs, tables (including nestedtables), headers and footers. Run formatting is preserved; tokens splitacross runs are handled. Usage:  docx_template.py template.docx values.json output.docx  docx_template.py template.docx values.json output.docx --strict values.json: {"name": "Ada", "date": "2026-01-01"}  fills {{name}}, {{date}}.With --strict, exits 1 if any {{token}} remains unfilled after processing."""from __future__ import annotations import argparseimport jsonimport reimport sys from docx import Document from docx_common import iter_all_paragraphs, replace_in_paragraph TOKEN_RE = re.compile(r"\{\{\s*([A-Za-z0-9_.-]+)\s*\}\}")  def main() -> int:    ap = argparse.ArgumentParser(        description="Fill {{token}} placeholders in a .docx from JSON.")    ap.add_argument("template", help="input .docx with {{tokens}}")    ap.add_argument("values", help="JSON file of token -> value")    ap.add_argument("output", help="output .docx path")    ap.add_argument("--strict", action="store_true",                    help="fail if any token remains unfilled")    args = ap.parse_args()     with open(args.values, encoding="utf-8") as f:        values = json.load(f)     doc = Document(args.template)    filled = {}    for para in iter_all_paragraphs(doc):        # Normalize whitespace variants like {{ name }} first.        for m in set(TOKEN_RE.findall(para.text)):            if m in values:                # Replace any spacing variant with canonical token, then fill.                for variant in set(                        t.group(0) for t in TOKEN_RE.finditer(para.text)                        if t.group(1) == m):                    n = replace_in_paragraph(para, variant, str(values[m]))                    filled[m] = filled.get(m, 0) + n     remaining = sorted({m for para in iter_all_paragraphs(doc)                        for m in TOKEN_RE.findall(para.text)})    doc.save(args.output)    result = {"ok": True, "output": args.output, "filled": filled,              "unfilled_tokens": remaining}    if args.strict and remaining:        result["ok"] = False        print(json.dumps(result, ensure_ascii=False))        return 1    print(json.dumps(result, ensure_ascii=False))    return 0  if __name__ == "__main__":    sys.exit(main()) 
Referenced from SKILL.md