# Jaw DOCX

> Word DOCX create, read, edit, review. Triggers: Word doc, .docx, reports, memos, letters, templates.

- Skill: `lidge-jun/jaw-docx` (Agent Skill, multi-file: 47 files)
- Install (CLI): `npx skillmds@latest add lidge-jun/jaw-docx`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lidge-jun/jaw-docx/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: lidge-jun (https://skillmd.com/u/lidge-jun)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lidge-jun/jaw-docx

---


# DOCX Skill

Use this skill for any `.docx` task: create, read, edit, review, template-fill, or QA verification.
Triggers: `"Word doc"`, `".docx"`, reports, memos, letters, templates.

**OfficeCLI routing and consent rule:**
- First check whether `officecli` is available with a probe that works in the agent's actual shell: `command -v officecli` on POSIX, `Get-Command officecli -ErrorAction SilentlyContinue` in PowerShell. **`command -v` is not a PowerShell builtin or cmdlet** — on Windows it prints nothing, sets no exit code, and raises no error, so it is indistinguishable from "not installed" and the agent asks to install a tool that is already there (#298). `officecli --version` is the portable fallback: a non-zero exit or no output means missing.
- If installed, recommend OfficeCLI first for high-fidelity DOCX mutations, validation, query, batch/resident flows, track changes, and CJK/rhwp-aware work.
- If missing, do not auto-install. Present choices before proceeding:
  1. Install forked OfficeCLI from `https://github.com/lidge-jun/OfficeCLI` via `bash "$(npm root -g)/cli-jaw/scripts/install-officecli.sh"`.
  2. Continue with lightweight fallback tools for the current task, with limitations stated.
  3. Stop or cancel.
- Before taking a lightweight fallback path, ask the user again and state what fidelity/features may be lost.
- If the user chooses lightweight mode, save that preference to memory for future Office work.
- Use upstream/vanilla `iOfficeAI/OfficeCLI` only when the user explicitly asks for upstream behavior.

OfficeCLI is the recommended advanced backend for add/set/remove, validate, query, and track-change accept/reject workflows.
Lightweight fallback: **Python OOXML scripts** (`scripts/*.py`) for what OfficeCLI cannot do, or when the user chooses lightweight mode: tracked-change **creation**, OMML equations, bulk pattern matching, unpack/edit/repack. See §3.

**DOCX only.** Do NOT use this skill for PDFs, spreadsheets, HWPX, Google Docs, or any other format.

**OfficeCLI discovery rule:** before guessing paths, element names, or properties, ask the installed CLI. Use `officecli --help` for workflow entry points and `officecli help docx ... --json` for machine-readable schema.

**Same-file execution rule:** run OfficeCLI commands against the same `.docx` sequentially. Do not run `officecli view`, `officecli validate`, `officecli query`, or `officecli get` in parallel against one package. If a file lock occurs, stop and report the exact command and path before making a copy or retrying.

---

## 1. Quick Decision

| Task | Tool | Command pattern | Notes |
|------|------|-----------------|-------|
| **Format like existing doc** | shell + officecli | `cp source.docx target.docx && officecli open target.docx` | **Inherit styles/headers/footers. See §2.** |
| Create blank DOCX | officecli | `officecli create report.docx` | Start from real Office file |
| Add paragraph | officecli | `officecli add FILE /body --type paragraph --prop text="..."` | Primary write path |
| Edit paragraph/run | officecli | `officecli set FILE /body/p[N] --prop ...` | Exact path targeting |
| Read text/outline/stats | officecli | `officecli view FILE text` | Modes: `text`, `annotated`, `outline`, `stats`, `issues`, `html` |
| Query document | officecli | `officecli query FILE "p[style=Heading1]"` | CSS-like selectors |
| Template-safe replacement | officecli | `officecli set FILE / --prop find="{{X}}" --prop replace="Y"` | Preserves template structure |
| Validation / issue scan | officecli | `officecli validate FILE` | Pair with `view FILE issues` |
| Accept/reject tracked changes | officecli | `officecli set FILE / --prop accept-changes=all` | Also `reject-changes=all` |
| **CREATE tracked changes** | officecli (native) | `add ... --prop revision.type=ins --prop revision.author=...` | **Native create + accept/reject** (v1.0.115); Python only for bulk redline diffs |
| **OMML equations** | Python (L4) | Unpack → inject `<m:oMath>` → repack | **officecli cannot generate OMML** |
| **Complex anchored comments** | Python (L3) | `python3 scripts/comment.py IN OUT --text "..." --anchor "..."` | For comments beyond officecli |
| PDF conversion / visual QA | soffice | `soffice --headless --convert-to pdf FILE` | Screenshot-based QA |
| Edit existing document | -- | Read [editing.md](./editing.md) | Detailed editing guides |
| Create from scratch | -- | Read [creating.md](./creating.md) | Detailed creation recipes |

---

## 2. Reference-Based Editing (Edit > Create from Scratch)

When the user says "format like X.docx", "match existing style", "based on template", or provides a source file — **start from the source file. Don't rebuild from scratch.**

### Workflow

1. **Copy the source**: `cp source.docx target.docx` — inherits all styles, margins, numbering, headers, footers
2. **Open** with `officecli open target.docx` — daemon starts; command returns immediately (do NOT run as `run_in_background` shell)
3. **Remove body content only** — keep `/styles`, `/numbering`, `/header`, `/footer`
4. **Add new paragraphs** using style names that already exist (e.g. `--prop style=Heading1`) — they auto-apply

### Why This Matters

Pandoc-generated and Word-generated documents have specific style IDs (e.g. `Heading1`, `BodyText`, `FirstParagraph`) unique to that document. Adding a new style with the same name causes:

- `officecli validate` errors about duplicate style IDs
- Word/LibreOffice rendering falls back to defaults
- The task takes 10× longer than necessary

### Template Sources (priority order)

1. **User-provided source file** — first-class template
2. **`tests/fixtures/*.docx`** — pre-built working examples shipped with this skill
3. **`officecli create`** blank — only when nothing else applies

### Example — Assignment Case

```bash
# CORRECT: inherit Pandoc styles
cp Assignment1.docx Assignment2.docx
officecli open Assignment2.docx
officecli remove Assignment2.docx "/body/p[1]"   # remove old body (keep styles/headers/footers)
# ... remove more paragraphs ...
officecli add Assignment2.docx /body --type paragraph --prop text="New title" --prop style=Heading1
officecli close Assignment2.docx

# WRONG: recreate styles that already exist — validate fails
officecli add doc.docx /styles --type style --prop name=Heading1 --prop size=20pt ...
```

---

## 3. Reference Materials & Script Map

officecli covers most DOCX tasks. For the rest, use these reference docs + Python scripts.

### References (`references/`)

| File | Read when | Contains |
|------|-----------|----------|
| `references/cjk-handling.md` | Korean text / East Asian font / wrapping issues | `rFonts` East Asian fonts, `lang` tags, accessibility |
| `references/tracked-changes.md` | Track changes / comments / redline work | `w:ins`, `w:del`, comments XML, script usage examples |
| `references/docx-js-api.md` | **DEPRECATED** — npm `docx` library API, not applicable to officecli ecosystem | Ignore — kept for historical reference only |

### Scripts (`scripts/`) — Python OOXML Toolkit

| Script | Run when | Command |
|--------|----------|---------|
| `scripts/docx_cli.py` | Unified Python CLI — unpack, save, validate, repair, search, TOC, chunk, comment, accept-changes, merge-runs | `python3 scripts/docx_cli.py {open\|save\|validate\|repair\|text\|search\|toc\|chunk\|comment\|accept-changes\|merge-runs}` |
| `scripts/accept_changes.py` | Accept all tracked changes (alternative to officecli) | `python3 scripts/accept_changes.py IN.docx OUT.docx` |
| `scripts/comment.py` | Add W3C-compliant OOXML comments anchored to text | `python3 scripts/comment.py IN.docx OUT.docx --text "..." --anchor "..."` |
| `scripts/ooxml/merge_runs.py` | Merge adjacent runs with identical formatting (post-edit cleanup) | `python3 scripts/ooxml/merge_runs.py unpacked/` |
| `scripts/ooxml/redline_diff.py` | Validate tracked-change correctness vs original | `python3 scripts/ooxml/redline_diff.py unpacked/ original.docx` |
| `scripts/ooxml/simplify_tracked.py` | Simplify same-author adjacent tracked changes | `python3 scripts/ooxml/simplify_tracked.py unpacked/` |

### Editing Escalation Ladder

When officecli can't do the job, escalate in this order:

| Level | When | Tool |
|-------|------|------|
| **L1** officecli high-level | Typical add/set/remove operations | `officecli add/set/remove/query/view` |
| **L2** officecli `raw-set` | XML injection — PAGE field, fldChar, hyperlink anchor, custom attributes | `officecli raw-set FILE PATH --xpath X --action A --xml ...` |
| **L3** Python script | Bulk tracked-change ops, comment add, merge runs, redline validation | `python3 scripts/*.py` |
| **L4** Unpack → edit XML → repack | OMML equations, custom style injection, pattern-match editing, anything L1-L3 can't reach | `scripts/docx_cli.py open FILE work/` → edit `work/word/*.xml` → `scripts/docx_cli.py save work/ OUT.docx` |

**Escalation signals:**
- officecli shows **"silently ignored"** → **L2** (raw-set)
- Need **OMML/MathML equations** → **L4** (inject `<m:oMath>` XML — officecli cannot generate these)
- Need to **CREATE** tracked changes (officecli only accepts/rejects) → **L3** or **L4**
- **Bulk find/replace** across 100+ targets → **L3** (`docx_cli.py search/replace`)
- **Pandoc-generated** doc with custom style IDs → **§2 Reference-Based Editing** first
- Task **still fails after L1+L2** → Read relevant `references/*.md` BEFORE giving up

---

## 4. Subskill References

Additional detail lives in companion files. Load only the one you need.

| Subskill | Path | When to use |
|----------|------|-------------|
| **officecli-academic-paper** | `./officecli-academic-paper/SKILL.md` | Academic papers, citations, bibliography, TOC for papers |
| **creating.md** | `./creating.md` | Detailed creation recipes (new documents from scratch) |
| **editing.md** | `./editing.md` | Detailed editing guides (modify existing documents) |

### Decision flow

```
Is the document an academic paper (thesis, journal, conference)?
  YES --> read officecli-academic-paper/SKILL.md
  NO  --> continue with this file
User provided a source file to match?
  YES --> §2 Reference-Based Editing + ./editing.md
  NO  --> ./creating.md
```

---

## 5. Design Principles for Business Documents

### 5.0 Design Read & Document Anti-Slop

**Intent discovery (before building):** ask audience (board / exec / internal team / public), formality
register (formal report · memo · whitepaper · proposal), and density (dense reference vs spacious) — then
match the type scale, palette restraint, and whitespace. If the user names a target ("McKinsey-style",
"academic", "startup memo"), map to it.

**Named document anti-slop (AI-tells — pattern → fix):**
1. **Calibri-everything** — single default font → a deliberate heading+body pair (§5.3), committed.
2. **Fake-heading bold** — manual bold+size instead of real styles → use Heading 1/2/3 styles (§5.1) so TOC/navigation work.
3. **Wall of text** — dense unbroken prose → break into lists, callouts, tables, sectioned headings.
4. **Default-Word-template look** — no palette/style identity → a restrained palette (§5.2) + consistent scale.
5. **Over-coloring** — many accents / colored body text → one accent; body near-black.
6. **Justified-everything + orphan headings** — full-justify body, headings stranded at page bottom → left-align body; keep headings with content.
7. **Placeholder leakage** — "Acme Corp"/lorem/TBD in delivered output → realistic specific content, never invented data.

> Named palettes + font pairings + personality→doc-type map: `references/design-system.md`.

### 5.1 Heading Hierarchy

- **H1**: Document title (one per document)
- **H2**: Major sections
- **H3**: Subsections under H2
- Never skip levels (H1 -> H3 is invalid). Table of Contents depends on correct heading structure.

```bash
# Verify heading hierarchy
officecli view report.docx outline
```

### 5.2 Color Palette

Use professional, muted tones only:

| Purpose | Allowed colors | Hex examples |
|---------|---------------|--------------|
| Headings, emphasis | Navy | `#003366`, `#1B2A4A` |
| Body accents, borders | Charcoal | `#333333`, `#4A4A4A` |
| Highlights, callouts | Forest green | `#2E5E3F`, `#1A4731` |

**NEVER** use rainbow colors, bright primary colors, or more than 3 accent colors in a single document.

### 5.3 Font Selection

| Script | Primary font | Fallback |
|--------|-------------|----------|
| Korean | Malgun Gothic | Pretendard |
| English / Latin | Calibri | Aptos |

The CJK fork auto-applies East Asian fonts, but verify with:

```bash
officecli raw report.docx /document | grep rFonts
```

### 5.4 Typography

Choose a readable body font (Calibri, Cambria, Georgia, Times New Roman). Keep body at 11-12pt. Headings should step up: **H1=18pt minimum (20pt preferred for long documents)**, H2=14pt bold, H3=12pt bold.

### 5.5 Spacing & Page Setup

Use paragraph spacing (`spaceBefore`/`spaceAfter`) instead of empty paragraphs. Line spacing of 1.15x-1.5x for body text.

Always set margins explicitly. US Letter default: `pageWidth=12240`, `pageHeight=15840`, margins=1440 (1 inch).

### 5.6 Table of Contents

TOC generation depends entirely on heading styles. Before inserting TOC:

1. Confirm all headings use proper Heading1/Heading2/Heading3 styles (not manual bold+size).
2. Run `officecli view FILE outline` to verify hierarchy.
3. Generate TOC via the subskill method.

### 5.7 Table Design & Color Usage

Alternate row shading for readability. Header row with contrasting background. Consistent cell padding.
Use color sparingly -- accent color for headings or table headers, not rainbow formatting.

### 5.8 Content-to-Element Mapping

| Content Type | Recommended Element(s) | Why |
|---|---|---|
| Sequential items | Bulleted list (`listStyle=bullet`) | Scanning is faster than inline commas |
| Step-by-step process | Numbered list (`listStyle=ordered`) | Numbers communicate order |
| Comparative data | Table with header row | Columns enable side-by-side comparison |
| Trend data | Embedded chart (`chartType=line/column`) | Visual pattern recognition |
| Key definition | Hanging indent paragraph | Offset term from definition |
| Legal/contract clause | Numbered list with bookmarks | Cross-referencing via bookmarks |
| Mathematical content | Equation element (`formula=LaTeX`) | Proper OMML rendering |
| Citation/reference | Footnote or endnote | Keeps body text clean |
| Pull quote / callout | Paragraph with border + shading | Visual distinction from body |
| Multi-section layout | Section breaks with columns | Column control per section |

---

## 6. Mandatory Verification (NEVER SKIP)

> **Delivery Gate — treat verification as a gate, not a confirmation.** Any failure = REJECT, do not deliver. Fix → re-run the checks → repeat until a pass finds zero new issues. After 3 rounds without convergence, STOP and report the likely root cause for the user to decide.

After ANY DOCX creation or edit, ALWAYS execute both steps:

```bash
# Step 1: Structural validation
officecli validate output.docx

# Step 2: Visual PDF verification
soffice --headless --convert-to pdf --outdir /tmp output.docx
# Open/inspect PDF to confirm: formatting, tables, images, headers/footers
```

- Skip PDF verification = **unverified output**. Inform user if soffice is unavailable.
- If `validate` reports errors, fix them before delivering the file.

---

## 7. Prerequisite Check

```bash
# Required
python3 -c "import docx, lxml" || echo "MISSING: pip install python-docx lxml"

# LibreOffice: check only; ask before installing when PDF conversion is needed.
which soffice >/dev/null 2>&1 || echo "ASK USER: LibreOffice is not installed; install it for PDF conversion or skip PDF output."

# OfficeCLI: check only; do not auto-install from a skill.
if ! command -v officecli >/dev/null 2>&1; then
  echo "ASK USER: install forked OfficeCLI from https://github.com/lidge-jun/OfficeCLI, continue lightweight, or stop."
  echo "Install command after approval: bash \"\$(npm root -g)/cli-jaw/scripts/install-officecli.sh\""
fi
```

## 8. Tool Discovery

Always confirm syntax from help before guessing:

```bash
officecli --help
officecli help docx
officecli help docx add
officecli help docx set
officecli help docx query
officecli help docx add paragraph --json
officecli help docx set run --json
```

Drill into a specific area:

```bash
officecli help docx add paragraph
officecli help docx add picture
officecli help docx set run
officecli help docx set style
officecli help all --jsonl | grep '"format":"docx"'
```

| Binary | Path | Notes |
|--------|------|-------|
| officecli | `officecli` (PATH) | Optional advanced backend; ask before install. Supported fork: `https://github.com/lidge-jun/OfficeCLI`, with CjkHelper.cs for CJK font/language behavior |

---

## 9. Core Workflows

### 9.1 Execution Model

**Run commands one at a time. Do not write all commands into a shell script and execute it as a single block.**

OfficeCLI is incremental: every `add`, `set`, and `remove` immediately modifies the file and returns output.

1. **One command at a time, then read the output.** Check the exit code before proceeding.
2. **Non-zero exit = stop and fix immediately.** Do not continue building on a broken state.
3. **Verify after structural operations.** After adding a style, table, chart, or section, run `get` or `validate` before building on top of it.

### 9.2 Reading & Analyzing

```bash
officecli view doc.docx text                    # Full text extraction
officecli view doc.docx text --max-lines 200    # Truncated extraction
officecli view doc.docx text --start 1 --end 50 # Range extraction
officecli view doc.docx outline                 # Structure: stats, headings, headers/footers
officecli view doc.docx annotated               # Style/font/size per run, equations as LaTeX
officecli view doc.docx stats                   # Paragraph count, style/font distribution
```

### 9.3 Element Inspection

```bash
officecli get doc.docx /                        # Document root (metadata, page setup)
officecli get doc.docx /body --depth 1           # List body children
officecli get doc.docx "/body/p[1]"              # Specific paragraph
officecli get doc.docx "/body/p[1]/r[1]"         # Specific run
officecli get doc.docx "/body/tbl[1]" --depth 3  # Table structure
officecli get doc.docx /styles                   # Style definitions
officecli get doc.docx "/styles/Heading1"        # Specific style
officecli get doc.docx "/header[1]"              # Header/footer
officecli get doc.docx /numbering                # Numbering definitions
officecli get doc.docx "/body/p[1]" --json       # JSON output for scripting
```

### 9.4 CSS-like Queries

```bash
officecli query doc.docx 'paragraph[style=Heading1]'            # By style
officecli query doc.docx 'p:contains("quarterly")'              # By text content
officecli query doc.docx 'p:empty'                              # Empty paragraphs
officecli query doc.docx 'image:no-alt'                         # Images without alt text
officecli query doc.docx 'p[align=center] > r[bold=true]'      # Compound selectors
officecli query doc.docx 'paragraph[size>=24pt]'                # By size
officecli query doc.docx 'field[fieldType!=page]'               # Fields by type
```

### 9.5 Headers & Footers

**Standard footer setup (always use this pattern for documents with a cover page):**

> **`--prop field=page` works** (verified v1.0.115) — `add --type footer --prop field=page` injects a live PAGE field directly. The old `raw-set <w:fldChar>` workaround is no longer needed.

```bash
# Step 1. Empty footer for the cover page (auto-enables a title-page footer)
officecli add doc.docx / --type footer --prop type=first --prop text=""

# Step 2. Default footer with a live PAGE field — no raw-set needed
officecli add doc.docx / --type footer --prop field=page --prop type=default --prop align=center --prop size=9pt --prop font=Calibri

# Verify: officecli get doc.docx "/footer[2]" --depth 3   # shows the fldChar PAGE field
```

> **Footer index rule:** When both a first-page footer and a default footer are added, the default footer is `/footer[2]`. If there is no first-page footer, the default footer is `/footer[1]`. Always verify with `officecli get doc.docx "/footer[2]"` (or `"/footer[1]"`) to confirm the `<w:fldChar>` element is present.

> **LibreOffice rendering note:** Page number fields may display as static "Page" in LibreOffice PDF preview -- this is a LibreOffice limitation. Open in Microsoft Word to see actual page numbers. Confirm the field with `officecli get doc.docx "/footer[2]"` -- output must show `fldChar` children.

### 9.6 Resident Mode (Performance)

**Always use `open`/`close` -- it is the smart default.** Every command benefits: no repeated file I/O.

```bash
officecli open doc.docx           # Load once into memory (returns IMMEDIATELY; daemon in bg)
officecli add doc.docx ...        # All commands run in memory -- fast
officecli set doc.docx ...
officecli close doc.docx          # Write once to disk
```

> **Do NOT run `officecli open` as a background shell job (e.g. via `run_in_background`).** It returns immediately and the daemon lives in the background automatically. Running it as a monitored shell creates zombies and file locks. If stuck: `pkill -9 -f "officecli.*resident"` then retry.

### 9.7 Batch Mode (Performance)

Execute multiple operations in a single open/save cycle:

```bash
cat <<'EOF' | officecli batch doc.docx
[
  {"command":"add","parent":"/body","type":"paragraph","props":{"text":"Introduction","style":"Heading1"}},
  {"command":"add","parent":"/body","type":"paragraph","props":{"text":"This report covers Q4 results.","font":"Calibri","size":"11pt"}}
]
EOF
```

Batch supports: `add`, `set`, `get`, `query`, `remove`, `move`, `swap`, `view`, `raw`, `raw-set`, `validate`.

Batch fields: `command`, `path`, `parent`, `type`, `from`, `to`, `index`, `after`, `before`, `props` (dict), `selector`, `mode`, `depth`, `part`, `xpath`, `action`, `xml`.

`parent` = container to add into (for `add`). `path` = element to modify (for `set`, `get`, `remove`, `move`, `swap`).

> **Error decoding:** `'X' is an invalid start of a value` = shell syntax leaked into JSON (unquoted `$`, stray shell metachar). Use heredoc `cat <<'EOF' | officecli batch FILE` with single-quoted `'EOF'` delimiter — prevents shell expansion.

---

## 10. Common Pitfalls

| Pitfall | Correct Approach |
|---------|-----------------|
| `--name "foo"` | Use `--prop name="foo"` -- all attributes go through `--prop` |
| Guessing property names | Run `officecli help docx set paragraph --json` to see exact names |
| `\n` in shell strings | Use `\\n` for newlines in `--prop text="line1\\nline2"` |
| Modifying an open file | Close the file in Word first |
| Hex colors with `#` | Use `FF0000` not `#FF0000` -- no hash prefix |
| Paths are 1-based | `/body/p[1]`, `/body/tbl[1]` -- XPath convention |
| `--index` is 0-based | `--index 0` = first position -- array convention |
| Unquoted `[N]` in zsh/bash | Shell glob-expands `/body/p[1]` -- always quote paths: `"/body/p[1]"` |
| Spacing in raw numbers | Use unit-qualified values: `'12pt'`, `'0.5cm'`, `'1.5x'` not raw twips |
| Empty paragraphs for spacing | Use `spaceBefore`/`spaceAfter` properties on paragraphs |
| `$` in `--prop text=` (shell) | Use single quotes: `--prop text='$50M'` |
| `$` and `'` in batch JSON | Use heredoc: `cat <<'EOF' \| officecli batch` |
| Wrong border format | Use `style;size;color;space` format: `single;4;FF0000;1` |
| listStyle on run | `listStyle` is a paragraph property, not a run property |
| Row-level bold/color/shd | Row `set` only supports `height`, `header`, and `c1/c2/c3` text shortcuts. Use cell-level `set` for formatting |
| Section property names | Canonical is camelCase `pageWidth`/`pageHeight`/`marginTop` (lowercase `pagewidth` etc. are accepted aliases — no real dichotomy) |
| `--prop field=page` in footer | **Works** (v1.0.115) — `add --type footer --prop field=page` injects a live PAGE field; no `raw-set` needed. See §9.5 |
| Suppress page number on cover | `set /section[N] --prop titlePage=true` (works v1.0.115) + a `type=first` empty footer. There is no `differentFirstPage` prop — `titlePage` is the lever |
| TOC skipped for multi-heading docs | Any document with 3+ headings requires a TOC. Add with `--type toc --index 0` after cover page break |
| Code block indentation via spaces | Use `ind.left` paragraph property (e.g. `--prop ind.left=720`) -- consecutive spaces produce warnings |
| **Recreating styles that exist in template** | `cp source.docx target.docx` first. Don't add styles with existing IDs — validate fails. See §2 |
| **`officecli open` as background shell** | Run foreground — `open` returns immediately, daemon runs in bg automatically. Background shell spawn creates zombies + file locks |
| **Batch JSON `'X' is an invalid start of a value`** | Shell syntax leaked into JSON. Use heredoc: `cat <<'EOF' \| officecli batch FILE.docx` |
| **OMML equation creation** | officecli cannot generate OMML. Options: (a) inline text, or (b) L4 — `scripts/docx_cli.py open FILE work/` → inject `<m:oMath>` into `work/word/document.xml` → `scripts/docx_cli.py save`. No dedicated OMML guide; author XML by hand or port from an existing equation-containing fixture in `tests/fixtures/` |

---

## 11. Known Issues

| Issue | Workaround |
|---|---|
| **No visual preview** | Unlike pptx (SVG/HTML), docx has no built-in rendering. Use `view text`/`outline`/`annotated`/`issues` for verification. Users must open in Word for visual check. |
| **Track changes — native create** | OfficeCLI creates tracked changes natively (v1.0.115): `--prop revision.type=ins\|del\|moveTo\|moveFrom\|format` with `revision.author`/`revision.date` on the host element; accept/reject via `set /revision --prop revision.action=accept\|reject`. (`scripts/docx_cli.py` no longer required for creation.) |
| **Tab stops may require raw XML** | Tab stop creation is not exposed in high-level commands. Use `raw-set` to add tab stop definitions. |
| **Chart series cannot be added after creation** | `set --prop data=` can only update existing series, not add new ones. Delete and recreate the chart. |
| **Complex numbering definitions** | `listStyle=bullet/ordered` (canonical) covers simple cases. For multi-level lists, use `numId`/`numLevel` properties. |
| **Shell quoting in batch with echo** | Use heredoc: `cat <<'EOF' \| officecli batch doc.docx`. |
| **Batch intermittent failure** | ~1-in-15 batch operations may fail with "Failed to send to resident". Retry or close/reopen file. Split large batches into 10-15 operation chunks. |
| **Table-level `padding` produces invalid XML** | Do not use `set tbl[N] --prop padding=N`. Use cell-level `padding.top`/`padding.bottom`. If already applied, remove with `raw-set --xpath "//w:tbl[N]/w:tblPr/w:tblCellMar" --action remove`. |
| **Internal hyperlinks not supported** | `hyperlink` only accepts absolute URIs. For `#bookmark` links, use `raw-set` with `<w:hyperlink w:anchor="bookmarkName">`. |
| **Table `--index` positioning unreliable** | `--index N` on `add /body --type table` may be ignored. Add content in desired order, or remove/re-add elements. |
| **`\mathcal` in equations causes validation errors** | Use `\mathit` or plain letters instead. |
| **`view text` shows "1." for all numbered items** | Display-only limitation. Rendered output in Word/LibreOffice shows correct auto-incrementing numbers. |
| **`chartType=pie`/`doughnut` in LibreOffice PDF** | Do NOT use these chart types when LibreOffice PDF delivery is required. Slices are invisible. Use `chartType=column` or `bar` instead. |
| **OMML equation creation via officecli** | officecli has no high-level OMML generator. Escalate to L4: `scripts/docx_cli.py open FILE work/` → inject `<m:oMath>` into `work/word/document.xml` → `scripts/docx_cli.py save`. Copy OMML from a reference fixture (`tests/fixtures/`) rather than authoring from scratch. |

---

## 12. QA Checklist

**Assume there are problems. Your job is to find them.**

### Issue Detection

```bash
officecli view doc.docx issues
officecli view doc.docx issues --type format
officecli view doc.docx issues --type content
officecli view doc.docx issues --type structure
```

### Content QA

```bash
officecli view doc.docx text
officecli view doc.docx outline
officecli query doc.docx 'p:empty'
officecli query doc.docx 'image:no-alt'

# Check for leftover placeholders
officecli query doc.docx 'p:contains("lorem")'
officecli query doc.docx 'p:contains("xxxx")'
officecli query doc.docx 'p:contains("placeholder")'
```

### Pre-Delivery Checklist

- [ ] Metadata set (title, author)
- [ ] PAGE field in footer -- `add --type footer --prop field=page` (works v1.0.115); verify with `officecli get doc.docx "/footer[2]" --depth 3` (shows `fldChar`). If no first-page footer, use `"/footer[1]"`.
- [ ] First-page footer added (`--prop type=first --prop text=""`) if document has a cover page
- [ ] Cover page content fills >= 60% of the page (accent bars, subtitle, author, date, contact info)
- [ ] TOC present when document has 3+ headings (`--type toc --prop levels="1-3" --prop title="Table of Contents" --prop hyperlinks=true --prop pagenumbers=true --index 0`)
- [ ] Last page content fills >= 40% of the page
- [ ] Heading hierarchy correct (no skipped levels)
- [ ] No empty paragraphs used as spacing
- [ ] All images have alt text
- [ ] Tables have header rows
- [ ] Document validates with `officecli validate`
- [ ] No placeholder text remaining

### Verification Loop

1. Generate document
2. Run `view issues` + `view outline` + `view text` + `validate`
3. List issues found (if none, look again more critically)
4. Fix issues
5. Re-verify -- one fix often creates another problem
6. Repeat until a full pass reveals no new issues

**Do not declare success until you've completed at least one fix-and-verify cycle.**

**QA display notes:**
- `view text` shows "1." for ALL numbered list items regardless of actual rendered number. This is a display limitation -- not a defect.
- `view issues` flags "body paragraph missing first-line indent" on cover page paragraphs, centered headings, list items, callout boxes, etc. These warnings are expected. First-line indent is only required in APA/academic body text.

---

## 13. Anti-Patterns (MUST AVOID)

- **Placeholder data**: NEVER leave "Acme Corp", "Alice Chen", "Lorem ipsum" in output. If the user has not provided data, **ask**.
- **Footer PAGE fields**: When setting page numbers via `raw-set`, the XML structure must be exact. See the Headers & Footers section for the correct `fldChar`/`instrText`/`fldChar` sequence.
- **Empty paragraphs for spacing**: Use `spacing-after` properties.
- **Manual bullet characters** (-, *): Use `listStyle=bullet` or `listStyle=number`.
- **Manual font XML injection**: Use `--prop font=...` when it suffices.
- **Chinese comments in output**: Some subskill reference files contain Chinese-language code comments (operational notes). NEVER copy these into user-facing document output. Treat them as internal annotations only.
- **Ignoring reference materials**: If a complex task fails with officecli, READ `references/*.md` + check `scripts/*.py` (§3) BEFORE giving up or falling back to inline text. The Pre-officecli OOXML workflow is still available via scripts.
- **Recreating existing styles**: When user provides a source file ("format like X.docx"), copy it and modify — do not rebuild styles from scratch. See §2.

---

## 14. Dependencies

| Tool | Purpose | Status |
|------|---------|--------|
| `officecli` (PATH) | Recommended advanced DOCX backend; fork source is `https://github.com/lidge-jun/OfficeCLI` | Optional; ask before install |
| `dotnet` | Runtime/build for OfficeCLI fork builds | Optional; required only after user approves fork install/build |
| `python3` | Fallback scripts (scripts/*.py) | Required for L3/L4 |
| `lxml` | Python XML processing for scripts/ooxml/* | Required for L3/L4 (`pip install lxml`) |
| `soffice` | PDF conversion / `.doc` migration / macro workflows | Optional fallback |
| `pdftoppm` | Image-based QA after PDF render | Optional fallback |

### Fork build (development only)

```bash
dotnet publish -c Release -o build-local
```

