agentman-docx-style

Agentman brand styling for DOCX report generation using python-docx. Use when generating ANY Word document report. Provides mandatory RGBColor constants, table styling functions, paragraph styles, document setup, and a pre-generation checklist. Ensures every DOCX uses the Agentman warm terracotta/charcoal palette instead of Word's default blue/gray styles. Load this skill BEFORE writing any DOCX generation code.

designv1.0.0
docxpython-docxwordbrand-guidelinesdesign-systemagentmanequity-research

Skill Instructions

# Agentman DOCX Style Guide

## When to Use

Load this skill **before writing any DOCX generation code** using `python-docx`. This skill provides the complete Agentman brand implementation for Word document output.

**The brand identity is quiet confidence** — charcoal suits, not fire trucks. Carbon and warm neutrals do the heavy lifting. Terracotta appears as a rare, deliberate accent.

## STOP — Read Before Writing Any Code

Before writing a SINGLE line of DOCX generation code, you MUST:

1. **Define ALL RGBColor constants below** as the first lines of your script
2. **Set document author** to `"Agentman Equity Research Assistant"` via `doc.core_properties.author`
3. **Set document title** to `"Agentman — {Report Title}"` via `doc.core_properties.title`
4. **Display author on page 1** immediately after the report title: `"Author: Agentman Equity Research Assistant"`
5. **NEVER let Word default styles bleed through** — override every heading, body text, and table style
6. **NEVER use built-in table styles** like `'Light Grid'`, `'Medium Shading'` — apply colors manually
7. **NEVER use default heading colors** — Word defaults are blue/black, not Agentman charcoal

---

## Visual Weight Distribution

Every report must maintain this ratio:

- **70% Carbon/Charcoal** (`#141413`, `#292322`, `#3D3735`) — the backbone
- **20% Warm Neutrals** (`#F0EEE6`, `#F6EAE6`, `#E3DACC`, `#FAF9F5`, `#FFFFFF`) — warmth without color
- **10% Terracotta Accent** (`#CC785C`, `#D97757`, `#A65945`) — sparingly, max 3 per section

---

## python-docx Implementation

### Color Constants (Copy-Paste This Exactly)

```python
from docx import Document
from docx.shared import Pt, Inches, RGBColor, Cm, Emu
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL

# ============================================================
# AGENTMAN BRAND COLORS — python-docx RGBColor Constants
# ============================================================

# Primary Brand (Terracotta) — use sparingly, max 3 per section
AGENTMAN_800 = RGBColor(0x70, 0x3B, 0x2D)   # Badge text, deep emphasis (rare)
AGENTMAN_700 = RGBColor(0x8B, 0x4A, 0x38)   # Cover accent, metric box values (rare)
AGENTMAN_600 = RGBColor(0xA6, 0x59, 0x45)   # Negative emphasis text
AGENTMAN_500 = RGBColor(0xCC, 0x78, 0x5C)   # PRIMARY ACCENT — stat numbers, table header text
AGENTMAN_400 = RGBColor(0xD9, 0x77, 0x57)   # Highlight/caution text
AGENTMAN_200 = RGBColor(0xE6, 0xA8, 0x90)   # Badge borders
AGENTMAN_150 = RGBColor(0xE3, 0xDA, 0xCC)   # Table borders, separators
AGENTMAN_100 = RGBColor(0xF6, 0xEA, 0xE6)   # Table header fill (light warm tint)
AGENTMAN_75  = RGBColor(0xF0, 0xEE, 0xE6)   # Highlight row bg, callout blocks
AGENTMAN_50  = RGBColor(0xFA, 0xF9, 0xF5)   # Alternate row bg (cream)

# Text Colors (Charcoal) — 70% of visual weight
CHARCOAL_950 = RGBColor(0x14, 0x14, 0x13)   # PRIMARY BODY TEXT
CHARCOAL_900 = RGBColor(0x29, 0x23, 0x22)   # Section titles, cover title
CHARCOAL_800 = RGBColor(0x3D, 0x37, 0x35)   # Secondary text, subheadings

# Neutral (Slate)
SLATE_700    = RGBColor(0x33, 0x41, 0x55)   # Secondary text on light
SLATE_600    = RGBColor(0x47, 0x55, 0x69)   # Body text secondary, metric labels
SLATE_500    = RGBColor(0x64, 0x74, 0x8B)   # Footer, muted captions
SLATE_400    = RGBColor(0x94, 0xA3, 0xB8)   # Descriptions, meta text

# ============================================================
# BANNED — NEVER let these Word defaults through:
# Default blue headings, default black (#000000) text,
# 'Light Grid' / 'Medium Shading' / 'Colorful' table styles,
# Default hyperlink blue (#0563C1)
# ============================================================
```

### Cell Shading Helper (Copy-Paste This Exactly)

```python
def set_cell_shading(cell, hex_color):
    """Apply background shading to a DOCX table cell.

    Args:
        cell: A python-docx table cell object
        hex_color: 6-char hex string without '#' (e.g., 'F6EAE6')
    """
    shading_elm = parse_xml(
        f'<w:shd {nsdecls("w")} w:fill="{hex_color}" w:val="clear"/>'
    )
    cell._element.get_or_add_tcPr().append(shading_elm)


def set_cell_border(cell, **kwargs):
    """Set borders on a DOCX table cell.

    Usage: set_cell_border(cell, bottom={"sz": 4, "color": "E3DACC", "val": "single"})
    """
    tc = cell._element
    tcPr = tc.get_or_add_tcPr()
    tcBorders = tcPr.find(qn('w:tcBorders'))
    if tcBorders is None:
        tcBorders = parse_xml(f'<w:tcBorders {nsdecls("w")}/>')
        tcPr.append(tcBorders)
    for edge, attrs in kwargs.items():
        element = tcBorders.find(qn(f'w:{edge}'))
        if element is None:
            element = parse_xml(f'<w:{edge} {nsdecls("w")}/>')
            tcBorders.append(element)
        for key, val in attrs.items():
            element.set(qn(f'w:{key}'), str(val))
```

### Table Styling (Copy-Paste This Exactly)

```python
def style_agentman_table(table, has_header=True):
    """Apply full Agentman brand styling to a python-docx table.

    Args:
        table: A python-docx Table object
        has_header: Whether the first row is a header (default True)
    """
    # Remove any built-in style
    table.style = 'Table Grid'
    table.alignment = WD_TABLE_ALIGNMENT.CENTER

    # Set table-wide border color to warm brand
    tbl = table._tbl
    tblPr = tbl.tblPr if tbl.tblPr is not None else tbl._add_tblPr()
    borders = parse_xml(
        f'<w:tblBorders {nsdecls("w")}>'
        '  <w:top w:val="single" w:sz="4" w:space="0" w:color="E3DACC"/>'
        '  <w:left w:val="single" w:sz="4" w:space="0" w:color="E3DACC"/>'
        '  <w:bottom w:val="single" w:sz="4" w:space="0" w:color="E3DACC"/>'
        '  <w:right w:val="single" w:sz="4" w:space="0" w:color="E3DACC"/>'
        '  <w:insideH w:val="single" w:sz="4" w:space="0" w:color="E3DACC"/>'
        '  <w:insideV w:val="single" w:sz="4" w:space="0" w:color="E3DACC"/>'
        '</w:tblBorders>'
    )
    # Remove existing borders if any
    existing = tblPr.find(qn('w:tblBorders'))
    if existing is not None:
        tblPr.remove(existing)
    tblPr.append(borders)

    for row_idx, row in enumerate(table.rows):
        for cell_idx, cell in enumerate(row.cells):
            # Vertical alignment
            cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER

            if row_idx == 0 and has_header:
                # HEADER ROW — light warm fill + terracotta text
                set_cell_shading(cell, 'F6EAE6')
                for paragraph in cell.paragraphs:
                    paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
                    for run in paragraph.runs:
                        run.font.color.rgb = AGENTMAN_500
                        run.font.bold = True
                        run.font.size = Pt(11)
                        run.font.name = 'Calibri'
            else:
                # BODY ROWS — alternating white / cream
                if row_idx % 2 == 1:
                    set_cell_shading(cell, 'FFFFFF')
                else:
                    set_cell_shading(cell, 'FAF9F5')

                for paragraph in cell.paragraphs:
                    if cell_idx == 0:
                        # First column — bold labels, left-aligned
                        paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
                        for run in paragraph.runs:
                            run.font.bold = True
                            run.font.color.rgb = CHARCOAL_950
                            run.font.size = Pt(10)
                            run.font.name = 'Calibri'
                    else:
                        # Data columns — center-aligned
                        paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
                        for run in paragraph.runs:
                            run.font.color.rgb = CHARCOAL_950
                            run.font.size = Pt(10)
                            run.font.name = 'Calibri'
```

### Highlight Row Helper

```python
def highlight_table_row(table, row_idx):
    """Apply warm cream highlight to a specific row (for totals, summaries)."""
    for cell in table.rows[row_idx].cells:
        set_cell_shading(cell, 'F0EEE6')  # AGENTMAN_75
```

### Document Setup (Copy-Paste This Exactly)

```python
def create_agentman_doc(report_title):
    """Create a new Agentman-branded DOCX document with metadata."""
    doc = Document()

    # Set document metadata
    doc.core_properties.author = "Agentman Equity Research Assistant"
    doc.core_properties.title = f"Agentman — {report_title}"
    doc.core_properties.company = "Agentman (Chain of Agents, Inc.)"

    # Set default font for the document
    style = doc.styles['Normal']
    font = style.font
    font.name = 'Calibri'
    font.size = Pt(11)
    font.color.rgb = CHARCOAL_950

    # Override heading styles to prevent Word blue defaults
    for level in range(1, 5):
        heading_style = doc.styles[f'Heading {level}']
        heading_style.font.name = 'Calibri'
        heading_style.font.color.rgb = CHARCOAL_900
        heading_style.font.bold = True
        if level == 1:
            heading_style.font.size = Pt(24)
        elif level == 2:
            heading_style.font.size = Pt(18)
        elif level == 3:
            heading_style.font.size = Pt(14)
        elif level == 4:
            heading_style.font.size = Pt(12)

    # Set narrow margins
    for section in doc.sections:
        section.top_margin = Inches(0.75)
        section.bottom_margin = Inches(0.75)
        section.left_margin = Inches(0.75)
        section.right_margin = Inches(0.75)

    return doc
```

### Page 1 Cover Content (Mandatory)

```python
from datetime import date

def build_cover_page(doc, report_title, date_str=None, subtitle=None):
    """Build the mandatory Agentman cover page content.

    The title MUST start with 'Agentman —' and the author line
    MUST appear immediately after. This is non-negotiable.

    Args:
        doc: python-docx Document
        report_title: main title (prefixed with "Agentman —")
        date_str: date string, defaults to today
        subtitle: optional subtitle (e.g. "Stock Comparison Report")
    """
    if date_str is None:
        date_str = date.today().strftime('%B %d, %Y')

    # Title — must start with "Agentman —"
    title_para = doc.add_heading(f'Agentman — {report_title}', level=1)
    for run in title_para.runs:
        run.font.color.rgb = CHARCOAL_900
        run.font.name = 'Calibri'

    # Subtitle — if provided, uses smaller font with clear spacing
    if subtitle:
        sub_para = doc.add_paragraph()
        run = sub_para.add_run(subtitle)
        run.font.color.rgb = SLATE_600
        run.font.size = Pt(13)
        run.font.name = 'Calibri'

    # Author — MUST appear immediately after title, non-negotiable
    author_para = doc.add_paragraph()
    run = author_para.add_run("Author: Agentman Equity Research Assistant")
    run.font.color.rgb = SLATE_600
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    # Date line
    date_para = doc.add_paragraph()
    run = date_para.add_run(f"{date_str} | Data Source: Financial Modeling Prep")
    run.font.color.rgb = SLATE_600
    run.font.size = Pt(11)
    run.font.name = 'Calibri'

    # Terracotta accent line (horizontal rule)
    add_terracotta_rule(doc)

    return doc
```

### Section Heading with Terracotta Underline

```python
def add_section_heading(doc, text, level=2):
    """Add a section heading with Agentman charcoal text.

    Note: The terracotta underline is added via a bottom border on the paragraph.
    """
    heading = doc.add_heading(text, level=level)
    for run in heading.runs:
        run.font.color.rgb = CHARCOAL_900
        run.font.name = 'Calibri'

    # Add terracotta bottom border to the heading paragraph
    pPr = heading._element.get_or_add_pPr()
    pBdr = parse_xml(
        f'<w:pBdr {nsdecls("w")}>'
        '  <w:bottom w:val="single" w:sz="18" w:space="4" w:color="CC785C"/>'
        '</w:pBdr>'
    )
    existing = pPr.find(qn('w:pBdr'))
    if existing is not None:
        pPr.remove(existing)
    pPr.append(pBdr)

    return heading
```

### Terracotta Accent Rule

```python
def add_terracotta_rule(doc, thickness='18'):
    """Add a terracotta horizontal rule (accent line) to the document."""
    para = doc.add_paragraph()
    pPr = para._element.get_or_add_pPr()
    pBdr = parse_xml(
        f'<w:pBdr {nsdecls("w")}>'
        f'  <w:bottom w:val="single" w:sz="{thickness}" w:space="1" w:color="CC785C"/>'
        '</w:pBdr>'
    )
    pPr.append(pBdr)
    return para
```

### Body Text Helpers

```python
def add_body_text(doc, text):
    """Add a body paragraph with Agentman brand styling."""
    para = doc.add_paragraph()
    run = para.add_run(text)
    run.font.color.rgb = CHARCOAL_950
    run.font.size = Pt(11)
    run.font.name = 'Calibri'
    return para


def add_secondary_text(doc, text):
    """Add secondary/meta text in slate."""
    para = doc.add_paragraph()
    run = para.add_run(text)
    run.font.color.rgb = SLATE_600
    run.font.size = Pt(10)
    run.font.name = 'Calibri'
    return para


def add_emphasis_text(doc, text, emphasis='positive'):
    """Add emphasized text using terracotta family.

    emphasis: 'positive' (AGENTMAN_500), 'negative' (AGENTMAN_600),
              'highlight' (AGENTMAN_400), 'neutral' (CHARCOAL_950)
    """
    para = doc.add_paragraph()
    run = para.add_run(text)
    run.font.bold = True
    run.font.size = Pt(11)
    run.font.name = 'Calibri'
    if emphasis == 'positive':
        run.font.color.rgb = AGENTMAN_500
    elif emphasis == 'negative':
        run.font.color.rgb = AGENTMAN_600
    elif emphasis == 'highlight':
        run.font.color.rgb = AGENTMAN_400
    else:
        run.font.color.rgb = CHARCOAL_950
    return para
```

### Stat Block Layout (MANDATORY — Prevents Overlap)

**CRITICAL: Never use stacked paragraphs for stat blocks.** Large stat numbers (28pt+) will overlap their labels and adjacent stats when placed as sequential centered paragraphs. Always use a **table** to contain stat blocks.

```python
def add_stat_row(doc, stat_pairs):
    """Add a row of side-by-side stat blocks using a table to prevent overlap.

    Args:
        doc: python-docx Document
        stat_pairs: list of (value, label) tuples,
                    e.g. [("$264.35", "AAPL Price"), ("$303.33", "GOOGL Price")]

    Returns:
        The table object containing the stat blocks.
    """
    n = len(stat_pairs)

    # 2-row table: row 0 = stat numbers, row 1 = labels
    table = doc.add_table(rows=2, cols=n)
    table.alignment = WD_TABLE_ALIGNMENT.CENTER

    # Remove all borders (invisible table)
    tbl = table._tbl
    tblPr = tbl.tblPr if tbl.tblPr is not None else tbl._add_tblPr()
    borders = parse_xml(
        f'<w:tblBorders {nsdecls("w")}>'
        '  <w:top w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        '  <w:left w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        '  <w:bottom w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        '  <w:right w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        '  <w:insideH w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        '  <w:insideV w:val="none" w:sz="0" w:space="0" w:color="auto"/>'
        '</w:tblBorders>'
    )
    existing = tblPr.find(qn('w:tblBorders'))
    if existing is not None:
        tblPr.remove(existing)
    tblPr.append(borders)

    for i, (value, label) in enumerate(stat_pairs):
        # Row 0: large terracotta stat number
        cell_num = table.rows[0].cells[i]
        p = cell_num.paragraphs[0]
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        run = p.add_run(str(value))
        run.font.color.rgb = AGENTMAN_500
        run.font.size = Pt(28)
        run.font.bold = True
        run.font.name = 'Calibri'

        # Row 1: small slate label
        cell_lbl = table.rows[1].cells[i]
        p2 = cell_lbl.paragraphs[0]
        p2.alignment = WD_ALIGN_PARAGRAPH.CENTER
        run2 = p2.add_run(label)
        run2.font.color.rgb = SLATE_600
        run2.font.size = Pt(10)
        run2.font.name = 'Calibri'

    return table

# Usage — ALWAYS use add_stat_row for stat blocks:
# add_stat_row(doc, [("$264.35", "AAPL Price"), ("$303.33", "GOOGL Price")])
# add_stat_row(doc, [("$3.89T", "AAPL Market Cap"), ("$3.67T", "GOOGL Market Cap")])
#
# WRONG (causes overlap — NEVER do this):
#   add_stat_block(doc, "$264.35", "AAPL Price")
#   add_stat_block(doc, "$303.33", "GOOGL Price")
```

### Callout Block Helper

```python
def add_callout_block(doc, heading_text, body_text):
    """Add an Agentman callout block (warm cream background)."""
    # Create a 1x1 table to simulate a callout box
    table = doc.add_table(rows=1, cols=1)
    cell = table.rows[0].cells[0]
    set_cell_shading(cell, 'F0EEE6')  # AGENTMAN_75

    # Heading in callout
    para = cell.paragraphs[0]
    run = para.add_run(heading_text)
    run.font.color.rgb = CHARCOAL_950
    run.font.bold = True
    run.font.size = Pt(12)
    run.font.name = 'Calibri'

    # Body in callout
    para2 = cell.add_paragraph()
    run2 = para2.add_run(body_text)
    run2.font.color.rgb = SLATE_600
    run2.font.size = Pt(10)
    run2.font.name = 'Calibri'

    # Style the table borders
    set_cell_border(cell,
        top={"sz": 4, "color": "E3DACC", "val": "single"},
        bottom={"sz": 4, "color": "E3DACC", "val": "single"},
        left={"sz": 4, "color": "E3DACC", "val": "single"},
        right={"sz": 4, "color": "E3DACC", "val": "single"})

    return table
```

### Badge Helper

```python
def add_badge(paragraph, text):
    """Add an inline badge to an existing paragraph.

    All badges use the same Agentman brand colors regardless of tier.
    Tier differentiation is via text wording, not color.
    """
    run = paragraph.add_run(f"  {text}  ")
    run.font.color.rgb = AGENTMAN_800
    run.font.size = Pt(10)
    run.font.bold = True
    run.font.name = 'Calibri'
    # Note: python-docx doesn't natively support inline backgrounds,
    # so badges are best implemented as small 1-cell tables or via
    # run highlighting with set_cell_shading on a table cell.
    return run
```

### Footer Setup

```python
from docx.oxml import parse_xml
from docx.oxml.ns import nsdecls

def add_footer(doc, date_str=None):
    """Add Agentman footer to all pages."""
    from datetime import date as dt
    if date_str is None:
        date_str = dt.today().strftime('%B %d, %Y')

    for section in doc.sections:
        footer = section.footer
        footer.is_linked_to_previous = False
        para = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph()
        para.alignment = WD_ALIGN_PARAGRAPH.CENTER

        # Terracotta rule above footer
        pPr = para._element.get_or_add_pPr()
        pBdr = parse_xml(
            f'<w:pBdr {nsdecls("w")}>'
            '  <w:top w:val="single" w:sz="6" w:space="4" w:color="CC785C"/>'
            '</w:pBdr>'
        )
        pPr.append(pBdr)

        run = para.add_run(f"Agentman Equity Research Assistant · {date_str} · Data: FMP")
        run.font.color.rgb = SLATE_500
        run.font.size = Pt(8)
        run.font.name = 'Calibri'
```

### Disclaimer

```python
def add_disclaimer(doc):
    """Add the mandatory Agentman disclaimer at the end of the report."""
    doc.add_paragraph()  # spacer
    add_terracotta_rule(doc, thickness='6')
    para = doc.add_paragraph()
    para.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = para.add_run(
        "This Agentman research report is for informational purposes only "
        "and does not constitute personalized investment advice. Past performance "
        "does not guarantee future results. Investors should conduct their own "
        "due diligence and consult a licensed financial advisor. "
        "Prepared by Agentman Equity Research Assistant."
    )
    run.font.color.rgb = SLATE_500
    run.font.size = Pt(8)
    run.font.italic = True
    run.font.name = 'Calibri'
    return para
```

---

## Element-to-Color Quick Reference

| Report Element | python-docx Implementation | Color |
|---|---|---|
| Table header fill | `set_cell_shading(cell, 'F6EAE6')` | AGENTMAN_100 |
| Table header text | `run.font.color.rgb = AGENTMAN_500` | #CC785C |
| Table borders | Warm borders via `tblBorders` with `E3DACC` | AGENTMAN_150 |
| Section titles | `run.font.color.rgb = CHARCOAL_900` + bottom border | #292322 |
| Body text | `run.font.color.rgb = CHARCOAL_950` | #141413 |
| Secondary text | `run.font.color.rgb = SLATE_600` | #475569 |
| Footer text | `run.font.color.rgb = SLATE_500` | #64748B |
| Alternate row bg | `set_cell_shading(cell, 'FAF9F5')` | AGENTMAN_50 |
| Highlight row bg | `set_cell_shading(cell, 'F0EEE6')` | AGENTMAN_75 |
| Positive emphasis | `run.font.color.rgb = AGENTMAN_500; run.font.bold = True` | #CC785C |
| Negative emphasis | `run.font.color.rgb = AGENTMAN_600; run.font.bold = True` | #A65945 |
| Badges | `set_cell_shading(cell, 'F6EAE6')` + `AGENTMAN_800` text | #F6EAE6 bg + #703B2D text |
| Document metadata | `doc.core_properties.author` / `.title` | N/A |

---

## Word Default Overrides

These Word defaults MUST be overridden — they will bleed through if not explicitly styled:

| Default | What It Does | Agentman Override |
|---|---|---|
| `Heading 1` style | Blue/black heading | `CHARCOAL_900` (#292322) |
| `Heading 2` style | Blue heading | `CHARCOAL_900` (#292322) |
| Hyperlink style | Blue underline (#0563C1) | `AGENTMAN_500` (#CC785C), no underline |
| Table Style "Light Grid" | Blue-gray grid | Custom brand via `style_agentman_table()` |
| Table Style "Grid" | Black borders | `AGENTMAN_150` (#E3DACC) borders |
| Default body text | Pure black (#000000) | `CHARCOAL_950` (#141413) |
| Default bullet color | Pure black | `CHARCOAL_950` (#141413) |

---

## Banned Colors

| Color | Hex | Why Banned |
|---|---|---|
| Green (success) | #10B981 | Traffic-light aesthetic (except ✓ symbol) |
| Amber (warning) | #F59E0B | Dashboard alert feel |
| Red (error) | #EF4444 | Alarm aesthetic (except ✗ symbol) |
| Blue (info) | #3B82F6 | Generic corporate, dilutes brand |
| Navy | #1B3A5C | Corporate default, not Agentman |
| Pure black | #000000 | Use CHARCOAL_950 (#141413) instead |
| Word default blue | #0563C1 | Default hyperlink color |
| Generic grays | #333, #666, #999 | Use brand palette equivalents |
| Any gradient | N/A | Solid fills only |

---

## Overlap Prevention Rules

**Text overlap is the #1 layout defect.** Follow these rules strictly:

1. **Stat blocks MUST use `add_stat_row()` table layout.** Never place large stat number paragraphs (28pt) followed by small label paragraphs (10pt) as sequential centered paragraphs — they will overlap. Always wrap stat pairs in a table.
2. **Side-by-side content MUST use a table.** Centered paragraphs stack vertically, not horizontally. For side-by-side stat blocks, comparison columns, or any multi-column layout, use a table with invisible borders.
3. **Title + subtitle need separate elements.** Use `build_cover_page(doc, title, subtitle=...)` — never concatenate title and subtitle into one heading.
4. **Add spacing between unrelated blocks.** Insert `doc.add_paragraph()` (empty paragraph) between major sections for breathing room.

---

## Pre-Generation Checklist

Before executing ANY DOCX generation code, verify:

- [ ] **No text overlap** — Stat blocks use `add_stat_row()` table layout, title/subtitle are separate elements with adequate spacing
- [ ] **Color constants defined** — ALL RGBColor constants are in the script
- [ ] **No Word defaults** — Heading styles, table styles, body text all overridden
- [ ] **Document author set** — `doc.core_properties.author = "Agentman Equity Research Assistant"`
- [ ] **Document title set** — `doc.core_properties.title = "Agentman — {Report Title}"`
- [ ] **Page 1 author line** — "Author: Agentman Equity Research Assistant" displayed before data
- [ ] **Title starts with "Agentman —"**
- [ ] **Table headers are LIGHT** — `set_cell_shading(cell, 'F6EAE6')` fill + `AGENTMAN_500` text
- [ ] **No dark table headers** — No navy, dark brown, charcoal, or any saturated fill on headers
- [ ] **No banned colors** — No green, red, amber, blue, navy, or generic grays
- [ ] **Warm borders** — `E3DACC` borders, not black/gray
- [ ] **Alternating rows** — White / `FAF9F5` cream
- [ ] **Terracotta budget** — Max 3 `AGENTMAN_500` elements per section
- [ ] **Footer on every page** — "Agentman Equity Research Assistant · {date} · Data: FMP"
- [ ] **Font is Calibri** — Set on every run, not just the default style
- [ ] **No shadows, gradients, or transparency** — Solid fills only
- [ ] **Visual weight feels 70/20/10** — Mostly charcoal, some cream, rare terracotta

Included Files

  • SKILL.md(25.1 KB)
  • _archive/skill-package.zip(7.6 KB)

Ready to use this skill?

Try it now in your favorite AI, or set up MCP for persistent access.