- name
- officecli-docx
- description
- Use this skill any time a .docx file is involved -- as input, output, or both. This includes: creating Word documents, reports, letters, memos, or proposals; reading, parsing, or extracting text from any .docx file; editing, modifying, or updating existing documents; working with templates, tracked changes, comments, headers/footers, or tables of contents. Trigger whenever the user mentions 'Word doc', 'document', 'report', 'letter', 'memo', or references a .docx filename.
# OfficeCLI DOCX Skill
## Setup
If `officecli` is missing:
- **macOS / Linux**: `curl -fsSL https://d.officecli.ai/install.sh | bash`
- **Windows (PowerShell)**: `irm https://d.officecli.ai/install.ps1 | iex`
Verify with `officecli --version` (open a new terminal if PATH hasn't picked up). If install fails, download a binary from https://github.com/iOfficeAI/OfficeCLI/releases.
## ⚠️ Help-First Rule
**This skill teaches what good docx looks like, not every command flag. When a property name, enum value, or alias is uncertain, consult help BEFORE guessing.**
```bash
officecli help docx # List all docx elements
officecli help docx <element> # Full element schema (e.g. paragraph, field, numbering, watermark, toc)
officecli help docx <verb> <element> # Verb-scoped (e.g. add field, set section)
officecli help docx <element> --json # Machine-readable schema
```
Help is pinned to the installed CLI version. When this skill and help disagree, **help is authoritative**. Special-topic mini-sections below end with an explicit pointer back to help.
## Mental Model & Inheritance
**Mental model.** A `.docx` is a ZIP of XML parts (`document.xml`, `styles.xml`, `numbering.xml`, `header*.xml`, `footer*.xml`, `comments.xml`, ...). Everything the user sees — headings, tables, page numbers, TOC, tracked changes — is XML inside that ZIP. `officecli` gives you a semantic-path API (`/body/p[1]/r[2]`) over it, so you almost never touch raw XML; when you must, use `raw-set`.
## Shell & Execution Discipline
**Shell quoting (zsh / bash).** docx paths contain `[]`, some prop values contain `$`. Both are shell metacharacters. Rules:
- ALWAYS quote element paths: `"/body/p[1]"`, not `/body/p[1]`.
- Use **single quotes** for any prop value containing `$`: `--prop text='$50M'`. The rule holds at any length — a 200-word body paragraph containing `$50M` needs the whole value inside single quotes, same as a three-word heading: `--prop text='In Q4 we hit $50M ARR, up 18% YoY — the strongest quarter since inception...'`. Mixing `'... $var ...'` and `"... $50 ..."` on long strings is where shell-leak silently strips `$50` → nothing.
- NEVER hand-write `\$`, `\t`, `\n` inside executable examples. The CLI does not interpret backslash escapes; they will land in your file as literal characters. In a cell / paragraph text, a real newline goes through the JSON layer (`batch` heredoc with `"\n"` inside the JSON string).
**Incremental execution.** Run commands one at a time and read each exit code. `officecli` mutates the file on every call; a 50-command script that fails at command 3 will cascade silently. One command → check output → continue. After any structural op (new style, table, TOC, section break) run `get` on it before stacking more on top.
**File-name convention in this skill.** All commands use `"$FILE"` — set once at the top of your script or session (`FILE="your-doc.docx"`) and every command picks it up. Copy-paste blocks and individual examples both assume `$FILE` is set. Do NOT copy a literal `doc.docx` / `review.docx` into an output directory — that is the wrong filename, always substitute your actual target.
## Requirements for Outputs
Before reaching for a command, know what a good docx looks like. These are the deliverable standards every document MUST meet.
### All documents
**Clear hierarchy.** Every non-trivial document has Title → Heading 1 → Heading 2 → body, not a wall of unstyled `Normal` paragraphs. A reader scans headings first. If `view outline` shows one flat list of paragraphs, the hierarchy is missing.
**Explicit heading sizes.** Do NOT rely on Word default style sizes — they drift between templates. Set sizes explicitly: **H1 = 18pt minimum (20pt preferred for long reports)**, H2 = 14pt bold, H3 = 12pt bold. Body = 11-12pt. Line spacing 1.15-1.5x.
**One body font, one accent.** Pick one readable body font (Calibri, Cambria, Georgia, Times New Roman) and keep it consistent. Accent color for heading emphasis or table headers — not rainbow formatting.
**Spacing through properties, not empty paragraphs.** Use `spaceBefore` / `spaceAfter` on paragraphs. Rows of empty paragraphs render as spacing in Word but break pagination and `view issues` will flag them.
**Smart quotes and typographic quality.** New content uses curly quotes (`'`, `'`, `"`, `"`) not ASCII `'` and `"`. Use Unicode directly (`'smart'`) or the XML entities `‘` / `’` / `“` / `”` inside `raw-set`. En-dash `–` for ranges (`2024–2026`), em-dash `—` for parenthetical breaks.
**Headers, footers, page numbers on any document > 1 page.** Page numbers go through a live `PAGE` field, not the literal text "Page 1". Use `--prop field=page` on a footer add — the CLI injects `<w:fldChar>` for you (see Creating & Editing → Headers & Footers).
**Preserve existing templates.** When editing a file that already has a look, match it. Existing conventions override these guidelines.
### Visual delivery floor (applies to EVERY document)
Before you declare done, run `officecli view "$FILE" html` and Read the returned HTML path to confirm all of these:
- **No placeholder tokens rendered as data.** `$xxx$`, `{var}`, `{{name}}`, `<TODO>`, `lorem`, `xxxx` must never appear in a heading, body paragraph, cover page, TOC, caption, header, or footer. These are build-time tokens that escaped replacement. If you want a literal `{name}` in a template for a human to fill, wrap it in a visible instruction paragraph ("Replace `{name}` before sending") so no one confuses it with finished content.
- **No truncated titles or overflowing cells.** Long headings / table cell values must fit the page and the column. If a cell overflows, widen the column or set `wrapText` on the cell.
- **Page numbers render as real numbers.** Confirm `get --depth 3` on the footer shows `<w:fldChar>` children — not just a run with literal text `"Page"`. The footer must contain a live field, not a static word.
- **TOC present when document has 3+ headings.** Add with `--type toc`. The TOC is a live field — some viewers show the heading list immediately, others show `Update field to see table of contents` until the user recalculates (F9 in Word).
- **Cover page ≥ 60% filled, last page ≥ 40% filled.** A cover that is 80% blank space looks unfinished. Pad with subtitle / author / date / scope statement / key highlights / decorative band. A last page with just "Thank you" centered also reads as unfinished — add conclusion, next steps, contact, legal notice.
- **No `\$`, `\t`, `\n` literals in document text.** If you see these in `view text`, a shell-escape layer leaked. Delete the paragraph and re-enter it.
If any of the above fails, STOP and fix before declaring done.
### Hard rules worth repeating (they are how docx goes wrong)
- Single-command footer with page number: `add / --type footer --prop field=page ...` — do NOT pass `--prop fldChar=...` or hand-compose the field. The CLI handles it.
- First-page footer `--type footer --prop type=first --prop text=""` automatically triggers `differentFirstPage`. Do NOT `set / --prop differentFirstPage=true` separately — that prop is UNSUPPORTED and silently fails.
- TOC add: `--type toc --prop levels="1-3" --prop hyperlinks=true --index 0`. Do NOT pass `--prop pagenumbers=true` — UNSUPPORTED (page numbers render automatically).
## Common Workflow
Six steps. Every non-trivial build follows this shape.
1. **Choose the mode.** Always use `officecli open <file>` at the start and `officecli close <file>` at the end. Resident mode is the default, not an optimization — it avoids re-parsing the XML on every command. For many paragraphs of the same style, use `batch` (≤ 12 ops per block for reliability).
2. **Orient.** For a new file, `officecli create "$FILE"`. For existing, `officecli view "$FILE" outline` first — get the heading tree, section count, whether a TOC / watermark / tracked changes are already there. Never start editing blind.
3. **Build incrementally.** Structural first, content next, formatting last. Styles and numbering defs → sections / page setup → headings and body → tables / images / fields / TOC → headers / footers → comments. After each structural op, `get` it back to confirm shape before stacking on top.
4. **Format to spec.** Explicit heading sizes, spacing, widths, alignment, tabs, list indents. Formatting is not optional polish — per Requirements for Outputs it is part of the deliverable.
5. **Close, then recalculate fields.** `officecli close "$FILE"` writes XML to disk. TOC / PAGE / NUMPAGES / SEQ / PAGEREF fields have **cached values** that may be stale or empty. When a human opens the file in Word, they press F9 to recalc. For the CLI's purposes, confirm fields _exist_ (via `get --depth 3` finding `<w:fldChar>`) rather than trusting the text value — the text is the cached render, the field is the truth.
6. **QA — assume there are problems.** See the QA section. You are not done when your last command exited 0; you are done after one fix-and-verify cycle finds zero new issues.
## Quick Start
Minimal viable docx: a heading, a body paragraph, a subheading, and a footer with a live page-number field. Adapt, don't copy-paste — your file, your content.
```bash
FILE="review.docx"
officecli create "$FILE"
officecli open "$FILE"
officecli add "$FILE" /body --type paragraph --prop text="Q4 2026 Review" --prop style=Heading1 --prop size=20pt --prop bold=true --prop spaceAfter=12pt
officecli add "$FILE" /body --type paragraph --prop text="Revenue grew 18% year-over-year, ahead of plan." --prop size=11pt --prop spaceAfter=8pt
officecli add "$FILE" /body --type paragraph --prop text="Key Drivers" --prop style=Heading2 --prop size=14pt --prop bold=true --prop spaceBefore=12pt --prop spaceAfter=6pt
officecli add "$FILE" /body --type paragraph --prop text="Enterprise renewals, upsell, and a new EMEA region." --prop size=11pt
officecli add "$FILE" / --type footer --prop type=default --prop size=9pt --prop text="Page " --prop field=page
officecli set "$FILE" "/footer[1]/p[1]" --prop align=center
officecli close "$FILE"
officecli validate "$FILE"
```
Verified: `validate` returns `no errors found`; `get /footer[1] --depth 3` shows the 5-run PAGE field chain (the begin / instrText / separate / cached value / end runs that wrap the live field), not a static `"Page"` string; for the raw `<w:fldChar>` XML behind those runs, use `officecli raw "$FILE" "/footer[1]" | grep fldChar`. This is the shape of every build: open → structure → content → format → footer/fields → close → validate.
## Reading & Analysis
Start wide, then narrow. `outline` tells you what structure is already there; jump into `view text` / `get` / `query` only once you know where to look.
**Open the rendered document to eyeball your own work.**
- `officecli view $FILE html` — Read the returned HTML to audit the rendered output. Headings, tables, page breaks visible. Catches heading hierarchy issues, empty paragraphs-as-spacing, missing TOC entries.
- `officecli watch $FILE` keeps a live preview running for the human user — they can open it at their own discretion. Use only when the user wants to watch along; agent self-check uses `view html` above.
Use `view html` as your **first visual check after a batch of edits**. For final visual verification, the user opens the `.docx` in their Word / WPS / Pages viewer.
**Orient.** Heading tree, section count, table / image counts, watermark, tracked changes presence.
```bash
officecli view "$FILE" outline
```
**Extract text for content QA or LLM context.** Paths are shown as `[/body/p[N]]` so you can jump back with `get`. Scope with `--start` / `--end` / `--max-lines` on long documents.
```bash
officecli view "$FILE" text --start 1 --end 80
officecli view "$FILE" annotated # values + style/font/size + warnings per run
officecli view "$FILE" stats # paragraph counts, font usage, style distribution
officecli view "$FILE" issues # empty paras, missing alt text, spacing anomalies
```
**Inspect one element.** XPath-style semantic paths (1-based, like XPath). Always quote — shells glob `[N]`.
```bash
officecli get "$FILE" / # document root: metadata, page setup
officecli get "$FILE" /body --depth 1 # body children overview
officecli get "$FILE" "/body/p[1]" # one paragraph
officecli get "$FILE" "/body/p[1]/r[1]" # one run (character-level formatting)
officecli get "$FILE" "/body/tbl[1]" --depth 3 # table with rows and cells
officecli get "$FILE" "/footer[1]" --depth 3 # footer — check for fldChar
officecli get "$FILE" "/styles/Heading1" # style definition
officecli get "$FILE" /numbering --depth 2 # numbering abstractNum + num bindings
```
Add `--json` for machine output. Use `[last()]` (with parentheses) to address the last element: `/body/tbl[last()]/tr[1]`. `[last]` without parens errors.
**Query across the document.** CSS-like selectors, for systematic checks rather than hand-walking.
```bash
officecli query "$FILE" 'paragraph[style=Heading1]' # all H1s
officecli query "$FILE" 'p:contains("quarterly")' # text match
officecli query "$FILE" 'p:empty' # empty paragraphs (clutter)
officecli query "$FILE" 'image:no-alt' # accessibility gaps
officecli query "$FILE" 'paragraph[size>=24pt]' # numeric comparison
officecli query "$FILE" 'field[fieldType!=page]' # fields other than PAGE
```
Operators: `=`, `!=`, `~=` (contains), `>=`, `<=`, `[attr]` (exists). Full selector reference: `officecli query --help`.
**Large documents.** When a document is long enough that `view text` is unwieldy, use `view outline` to navigate by heading and `query` to jump directly to what you need — don't dump the whole body into context.
## Creating & Editing
The verbs: `add` (new element), `set` (change a prop), `remove`, `move`, `swap`, `batch`, `raw-set` (last-resort XML). Ninety percent of a docx build is paragraphs, runs, tables, a couple of images, a TOC, and a footer.
### Paragraphs, runs, styles
A paragraph (`p`) is a block; a run (`r`) is a span of consistent character formatting inside it. Set paragraph-level properties (style, alignment, spacing, indent) on the `p`; set font / size / color / bold on the `r`.
```bash
officecli add "$FILE" /body --type paragraph --prop text="Executive Summary" --prop style=Heading1 --prop size=18pt --prop bold=true --prop spaceAfter=12pt
officecli set "$FILE" "/body/p[1]/r[1]" --prop color=1F4E79
```
**Use styles, not ad-hoc formatting.** `style=Heading1` references the document's style definition — change the definition once, all headings update. Inline `size=18pt` on every heading is a style-bypass; when you need to retheme you have to touch every paragraph.
Use `spaceBefore` / `spaceAfter` for vertical spacing. Never use chains of empty paragraphs — they break pagination and are flagged by `view issues`.
### Tables
Tables are `/body/tbl[N]` with rows `tr[N]` and cells `tc[N]`. Add the table with a row and column count, then fill.
```bash
officecli add "$FILE" /body --type table --prop rows=4 --prop cols=3 --prop width=100%
officecli set "$FILE" "/body/tbl[1]/tr[1]" --prop header=true --prop c1=Quarter --prop c2="Revenue" --prop c3="Growth"
officecli set "$FILE" "/body/tbl[1]/tr[1]/tc[1]/p[1]/r[1]" --prop bold=true
```
View on GitHub