Tech Docx Writer

Generate deeply technical Word documents based on corporate templates. Use when the user asks to generate a specification, architecture document, or API manual by injecting content into a .docx template.

Audits

Pass

Install

openclaw skills install tech-docx-writer

Tech Doc Generator Workflow

Follow this strict pipeline to generate production-grade technical Word documents from corporate templates. Do not deviate, as python-docx has many pitfalls that this workflow avoids.

1. Explore & Read

Gather factual context from project wikis, codebases, or reference docs. Do not hallucinate content. Read the codebase files or use git log / grep / Read to ensure facts are accurate.

2. Drafting (Markdown)

Draft the content in a Markdown file (.md).

  • Use Markdown tables (|---|) for data dictionaries and API specs.
  • Write standard headings (#, ##, ###).
  • Get user approval on the Markdown content before proceeding.

3. Template Injection (Python Script)

You MUST write and execute a python script (using python-docx and lxml) to inject the Markdown into the target .docx template.

You MUST include these EXACT bulletproof functions in your script to avoid OXML bugs:

A. Bold Markdown Support

import re
def parse_inline_markdown(p, text):
    parts = re.split(r'(\*\*.*?\*\*)', text)
    for part in parts:
        if part.startswith('**') and part.endswith('**') and len(part) > 4:
            run = p.add_run(part[2:-2])
            run.bold = True
        else:
            if part:
                p.add_run(part)

B. Double Numbering Prevention

from docx.oxml.ns import qn
def remove_auto_numbering(paragraph):
    pPr = paragraph._element.find(qn('w:pPr'))
    if pPr is not None:
        numPr = pPr.find(qn('w:numPr'))
        if numPr is not None:
            pPr.remove(numPr)

def strip_heading_numbering(text):
    """Strips leading numeric parts like '3.4.1 ' from text before Word adds its own list numbering."""
    return re.sub(r'^(\d+\.)*\d*\s+', '', text)

When injecting headings, call strip_heading_numbering on the text, then call parse_inline_markdown(p, text), and finally call remove_auto_numbering(p).

C. Bulletproof Header Replacement

def update_all_headers_footers(doc, old_keyword, new_keyword):
    """Search for old_keyword within paragraph.text (handling split runs), 
    replace it, and merge into a single run to avoid breaking XML tags."""
    for section in doc.sections:
        parts = [section.header, section.first_page_header, section.even_page_header,
                 section.footer, section.first_page_footer, section.even_page_footer]
        for part in parts:
            if part is None: continue
            for p in part.paragraphs:
                if old_keyword in p.text:
                    new_text = p.text.replace(old_keyword, new_keyword)
                    for run in p.runs: run.text = ""
                    if p.runs: p.runs[0].text = new_text
                    else: p.add_run(new_text)

D. Table of Contents Update

from docx.oxml import OxmlElement
element = OxmlElement('w:updateFields')
element.set(qn('w:val'), 'true')
doc.settings.element.append(element)

4. Execution

Run the script, save the output .docx, and instruct the user to open it and update the TOC.