officecli-docx 精选
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.
安装方式
cp -r skills/officecli-docx ~/.claude/skills/officecli-docx把该 skill 目录放进客户端 skills 目录。不同客户端的目录可能不同,Claude Code 默认是 ~/.claude/skills/
https://raw.githubusercontent.com/iOfficeAI/OfficeCLI/fb98e593612dee2cec36847666671dba502e60aa/skills/officecli-docx/SKILL.md下载后另存为 ~/.claude/skills/officecli-docx/SKILL.md。链接锁定采集时的 commit,内容与本站展示一致。
整仓一次性获取:git clone --depth 1 https://github.com/iOfficeAI/OfficeCLI.git
依赖与权限
- 无需 API Key
- 需要联网访问外部服务
- 依赖外部命令:
curljqgo - 以上为按正文与 frontmatter 自动推断的信号,仅供参考;安装前建议先阅读原文。
SKILL.md 正文
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.
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.
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 (see the XML appendix).
Shell & Execution Discipline
docx paths contain []; some prop values contain $. Both are shell metacharacters. Escaping happens at three layers — keep them separate.
- Shell. ALWAYS quote element paths:
"/body/p[1]", not/body/p[1](zsh/bash glob[N]). Single-quote any value containing$:--prop text='$50M'— at any length, the whole value inside one pair of single quotes. Unquoted$50Mis stripped toM; mixing'…$var…'and"…$50…"on one long string is where the$50silently vanishes. - CLI (
text=). The two-char escapes\nand\tARE interpreted in--prop text=—\nbecomes a<w:br/>soft line break,\ta<w:tab/>— consistently across docx / pptx / xlsx. Double them (\\n) for a literal backslash-n (rarely wanted). This applies to row-level tablec1…cNshortcuts too (\n→<w:br/>within the cell). - JSON (batch). A real newline can also be passed as
"\n"in the JSON string of abatchheredoc; same result.
If in doubt, view text after writing and compare character-for-character.
Incremental execution. officecli mutates the file on every call. Run commands one at a time and check each exit code — a 50-command script that fails at command 3 cascades silently. After any structural op (new style, table, TOC, section break) run get on it before stacking more.
Open/save lifecycle: officecli open <file> at the start, officecli save <file> at the end to flush to disk — save only writes and leaves the resident warm for follow-up edits; reach for officecli close <file> only to release the resident on a one-shot handoff. Both are always safe (never error or lose work). For many paragraphs of one style, use batch (one pass for the whole array). Flush only at the non-officecli boundary: officecli's own reads always see your edits; run save/close only before a non-officecli program reads the file (python-docx, Word, a renderer, delivery).
$FILE convention. All commands use "$FILE" — set it once (FILE="your-doc.docx"). Never copy a literal doc.docx / review.docx into output — always substitute your actual target.
Requirements for Outputs
Deliverable standards every document MUST meet — know these before reaching for a command.
Clear hierarchy. Every non-trivial document has Title → Heading 1 → Heading 2 → body, not a wall of unstyled Normal paragraphs. If view outline shows one flat list, the hierarchy is missing.
Explicit heading sizes (Word default style sizes drift between templates): H1 ≥ 18pt (20pt for long reports), H2 = 14pt bold, H3 = 12pt bold, body = 11–12pt, line spacing 1.15–1.5x. Prefer style=Heading1 over inline sizes so a retheme touches the definition once — but set explicit sizes when you can't trust the template's styles.
One body font, one accent. One readable body font (Calibri, Cambria, Georgia, Times New Roman); accent color for heading emphasis or table headers, not rainbow formatting.
Spacing through properties. Use spaceBefore / spaceAfter on paragraphs. Rows of empty paragraphs break pagination and are flagged by view issues.
Typographic quality. New content uses curly quotes (' ' " "), not ASCII — Unicode directly or 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 (--prop field=page), never the literal text "Page 1" — the CLI injects <w:fldChar> for you (see 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 declaring 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,xxxxmust never appear in a heading, body, cover, TOC, caption, header, or footer. A literal{name}meant for a human to fill belongs inside a visible instruction paragraph ("Replace{name}before sending"), never as finished content. - No truncated titles or overflowing cells. Widen the column or set
wrapTextrather than trimming content. - TOC present when the document has 3+ headings (
--type toc). - Cover page ≥ 60% filled, last page ≥ 40% filled. Pad a thin cover with subtitle / author / date / scope / key highlights; pad a "Thank you" last page with conclusion / next steps / contact / legal.
- No
\$,\t,\nliterals in document text. Ifview textshows these, a shell-escape layer leaked — delete the paragraph and re-enter it.
If any fails, STOP and fix before declaring done.
Common Workflow
Six steps. Every non-trivial build follows this shape.
- Open the file.
officecli open "$FILE"(resident default). New file:officecli create "$FILE"first. - Orient. Existing file:
officecli view "$FILE" outline— heading tree, section count, whether a TOC / watermark / tracked changes already exist. Never edit blind. - Build incrementally. Structural first, content next, formatting last: styles & numbering defs → sections / page setup → headings & body → tables / images / fields / TOC → headers / footers → comments. After each structural op,
getit back before stacking on top. - Format to spec. Explicit heading sizes, spacing, widths, alignment, tabs, list indents — formatting is part of the deliverable, not optional polish.
- Save, then trust structure over cached text.
officecli save "$FILE"writes the XML. TOC / PAGE / NUMPAGES / SEQ / PAGEREF fields carry cached values that may be stale or empty until a human recalculates (F9 in Word). Confirm fields exist (get --depth 3finds<w:fldChar>) rather than trusting the visible text. - QA — assume there are problems. You are done after one fix-and-verify cycle finds zero new issues, not when your last command exited 0. See QA.
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.
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 save "$FILE"
officecli validate "$FILE"
Verified: validate returns no errors found; get /footer[1] --depth 3 shows the 5-run PAGE field chain (begin / instrText / separate / cached value / end).
Reading & Analysis
Start wide, then narrow. outline tells you what's already there; jump into view text / get / query once you know where to look.
officecli view "$FILE" outline # heading tree, section count, table/image counts, watermark, tracked-changes presence — orient here first
officecli view "$FILE" html # Read the returned HTML path: first visual check after a batch of edits (hierarchy, empty-para spacing, missing TOC)
officecli view "$FILE" text --start 1 --end 80 # text for content QA; paths shown as [/body/p[N]] so you can jump back with get
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
officecli watch "$FILE" keeps a live preview running for the human user to open at their discretion — agent self-check uses view html. Final visual verification is the user opening the .docx in Word / WPS / Pages.
Inspect one element. XPath-style semantic paths (1-based). Always quote — shells glob [N]. Use [last()] (with parens) for the last element; [last] errors. Add --json for machine output.
officecli get "$FILE" / # document root: metadata, page setup
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
Query across the document. CSS-like selectors, for systematic checks rather than hand-walking. Operators: =, !=, ~= (contains), >=, <=, [attr] (exists). Full reference: officecli query --help.
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
query --json wraps results in .data.results[] — jq '.data.results | length' to count.
Large documents. Navigate by heading with view outline and jump with query; don't dump the whole body into context.
Creating & Editing
Verbs: add (new element), set (change a prop), remove, move, swap, batch, raw-set (last-resort XML). Ninety percent of a 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 props (style, alignment, spacing, indent) on the p; set font / size / color / bold on the r.
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 spaceBefore / spaceAfter for vertical spacing — never chains of empty paragraphs. For left indent use --prop indent=720 (twips), firstLineIndent=360 for first line, hangingIndent=720 for hanging; leading spaces fire view issues.
Tables
Tables are /body/tbl[N] with rows tr[N] and cells tc[N]. Add with row/column counts, then fill.
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
Row-level set supports height, header, and c1 / c2 / … / cN text shortcuts (cN generalises to any column count). Cell formatting (bold, fill, color) goes on the cell's paragraph / run — not row-level. For per-cell borders, set cell-level border. on the tc (--prop border.bottom="single;6;000000;0"), or paragraph-level pbdr. on the inner paragraph.
Horizontal rule = a paragraph bottom border, never a 1-row table. A table-as-divider renders as an empty min-height box (worst in headers/footers). Use pbdr.bottom (STYLE;SIZE;COLOR) on the paragraph instead:
officecli set "$FILE" "/body/p[3]" --prop pbdr.bottom="single;6;2E75B6"
Lists (bullets, numbered, multi-level)
For single-level bullets/numbers, set listStyle on the paragraph (listStyle is a paragraph prop, NOT a run prop — common mistake):
officecli add "$FILE" /body --type paragraph --prop text="First item" --prop listStyle=bullet
For multi-level (legal-style 1 / 1.1 / 1.1.1), add an abstractNum, then a num, then reference the numId per paragraph:
officecli add "$FILE" /numbering --type abstractnum --prop format=decimal # → abstractNum id=0
officecli add "$FILE" /numbering --type num --prop abstractNumId=0 # → num id=1
officecli add "$FILE" /body --type paragraph --prop text="Section one" --prop numId=1 --prop ilvl=0
IDs are 0-based: the first abstractNum is id=0; the num references it via abstractNumId=0 and is itself assigned id=1. A non-existent abstractNumId errors, so check ids after creating. Verify with officecli query "$FILE" 'paragraph[numId>0]'. See help docx abstractnum / help docx num for level and format options.
Tab stops (signature lines, leader rows)
Tab stops are a first-class tab child of the paragraph; pos accepts 6in/6cm/twips, val ∈ left/center/right, leader ∈ none/dot/hyphen/underscore. See help docx tab.
officecli add "$FILE" "/body/p[1]" --type tab --prop pos=6in --prop val=right --prop leader=dot
Leader caveat. leader=dot alone emits no dots — the leader renders only when a real <w:tab/> character sits in a run between the text and the tab stop. Put one there with \t in the text: define the stop (add tab --prop pos=6in --prop val=right --prop leader=dot), then --prop text="Chapter 1\t12" — the \t becomes the <w:tab/> and dots fill to the right-aligned page number. (Literal text="Chapter 1 ......... 12" also ships, but a real tab stop aligns cleanly.)
Fields (PAGE / NUMPAGES / DATE / MERGEFIELD / REF)
Fields are live values computed at render time. fieldType picks the field; name supplies the target (merge name or ref bookmark); format / instr add switches.
| Field | Use | Example |
|---|---|---|
page | current page number | --prop field=page on footer, or --prop fieldType=page inline |
numpages | total pages | --prop field=numpages / --prop fieldType=numpages |
date | today | --prop fieldType=date --prop format='yyyy-MM-dd' |
mergefield | template merge token | --prop fieldType=mergefield --prop name=CustomerName |
ref | cross-reference to a bookmark | --prop fieldType=ref --prop name=bookmarkName |
Full fieldType enum (30+ values incl. pageref, seq, styleref, docproperty, createdate, …) is in help docx field. There is NO fieldInstr fieldType — use the instruction prop for raw field instruction text when typed shortcuts fall short. Picture switches (MERGEFIELD Amount \# "#,##0.00", DATE \@ "yyyy年MM月") go via --prop instruction='…' (mergefield's format prop is ignored with a warning — use instruction).
officecli add "$FILE" "/body/p[3]" --type field --prop fieldType=mergefield --prop name=customer_name
# Renders «customer_name» — visible placeholder, replaced in Word at mail-merge time.
MERGEFIELD templates: never render placeholder literals. A {{customer_name}} or $NAME$ shown as body text is a failed template the recipient sees — insert a real MERGEFIELD (above), or confine literal tokens to an obvious instruction paragraph. Confirm with query 'field[fieldType=mergefield]'.
SEQ / PAGEREF / TOC field values. officecli doesn't store rendered field values at write time. Recompute by what each path needs:
- SEQ numbering (
Figure 1/2/3):officecli set "$FILE" / --prop recalcFields=seqcounts SEQ fields in body document order and writes the cached values (evaluatedflips true; switches/formats inhelp docx document). Heading-relative\sand SEQ in headers/footers defer to Word. - PAGE / PAGEREF / NUMPAGES / TOC page numbers need pagination, which officecli has no engine for —
officecli set "$FILE" /settings --prop updateFields=truedefers them to Word on open.
Use both on a multi-figure document. Academic papers: see the officecli-academic-paper skill.
Headers & Footers (page numbering)
Single-command pattern — the CLI injects <w:fldChar>, so you never compose the field by hand:
# Empty first-page footer — auto-enables differentFirstPage so the cover has no page number
officecli add "$FILE" / --type footer --prop type=first --prop text=""
# Default footer with live page number
officecli add "$FILE" / --type footer --prop type=default --prop align=center --prop size=9pt --prop text="Page " --prop field=page
When both exist, the default footer is /footer[2]; alone it is /footer[1]. Verify: get --depth 3 must show fldChar children, not just a run with literal "Page" (view outline prints "Footer: Page" for both live fields AND static text — don't rely on it). Do NOT set --prop differentFirstPage=true — that prop is unsupported (exit 2 with WARNING: UNSUPPORTED; the element itself is still created — check success in --json); adding a first-type footer flips the bit. For composite Page X of Y, see recipe (b).
Table of Contents
For any document with 3+ headings, first verify that the requested range has real sources. A TOC source must use a built-in Heading style or a custom paragraph style with outlineLvl; bold or large Normal text is not a source. If no eligible source exists, stop and fix the heading structure instead of inserting a TOC that renders "Error! No table of contents entries found."
# Built-in Heading styles are TOC sources.
officecli add "$FILE" /body --type paragraph --prop text="Introduction" --prop style=Heading1
# Custom paragraph styles need an outline level (0 = Heading 1).
officecli add "$FILE" /styles --type style --prop id=ThesisH1 --prop type=paragraph --prop outlineLvl=0
# Add the TOC only after its sources exist.
officecli add "$FILE" /body --type toc --prop levels="1-3" --prop title="Table of Contents" --prop hyperlinks=true --index 0
Page numbers need pagination; OfficeCLI cannot calculate TOC page numbers itself. Set updateFields=true so Word recomputes the TOC (and all fields) on open. Without a Word-compatible field engine, report the TOC as dynamic and uncomputed; do not claim ready page numbers or guess a static TOC.
officecli set "$FILE" /settings --prop updateFields=true
Address the TOC directly with /toc[1] or /tableofcontents for get/set/remove.
Images
Pictures go inside a run. Alt text is mandatory for accessibility — pass alt directly at create time:
officecli add "$FILE" "/body/p[5]" --type picture --prop src=logo.png --prop width=1.5in --prop alt="Acme logo"
Confirm officecli query "$FILE" 'image:no-alt' is empty before delivery.
Charts
For data, add a native chart — editable, themeable, accessible, re-renders in Word — never a flat PNG screenshot of a chart. data="Label:v1,v2,…" per series; one data= per series (or series1=/series2=).
officecli add "$FILE" /body --type chart --prop chartType=bar --prop title="Revenue by Region" --prop categories="EMEA,APAC,Americas" --prop data="2026:120,150,180"
chartType ∈ bar / column / line / pie / area / scatter (help docx chart for axis/legend/series styling). A PNG via --type picture is only a fallback for an exotic chart officecli can't build.
Hyperlinks and bookmarks
External links go via hyperlink:
officecli add "$FILE" "/body/p[2]" --type hyperlink --prop url="https://example.com" --prop text="our site"
Internal links (to a bookmark) use --prop anchor=bookmarkName — not a #fragment in url:
officecli add "$FILE" "/body/p[2]" --type hyperlink --prop anchor=chapter1 --prop text="See Chapter 1"
Pairing a PAGEREF field with visible text is the alternative. See help docx hyperlink / help docx bookmark.
Sections and page setup
Document root / carries page setup (pageWidth, pageHeight, margins, in twips). Multi-section documents (landscape insert, columns) add a section break — see help docx section. Both camelCase (pageWidth, canonical) and lowercase alias (pagewidth) are accepted; prefer camelCase.
officecli set "$FILE" / --prop pageWidth=12240 --prop pageHeight=15840 --prop marginTop=1440 --prop marginLeft=1440
# Newspaper-style multi-column flow (columnSpace in twips; 720 = 0.5in):
officecli set "$FILE" / --prop columns=2 --prop columnSpace=720
Forcing page breaks
Use exactly one page-break mechanism per logical boundary. The default is pageBreakBefore=true on the target heading. Alternatively, insert one explicit pagebreak before the heading. Never combine both mechanisms for the same boundary: the resulting double break can create a blank page. Never set pageBreakBefore on p[last()] immediately after adding a pagebreak.
# Default: apply the break directly to the heading.
officecli add "$FILE" /body --type paragraph --prop text="Introduction" --prop style=Heading1 --prop pageBreakBefore=true
--prop break=newPage is an alias for pageBreakBefore=true. Preview with view html and check for blank pages.
Report-level recipes
Patterns that come up on every long-form report. Each has been executed and validate-passed.
(a) Rich cover page — hit the ≥ 60% filled floor. Stack a confidentiality banner, title, subtitle, client/project/date block, and a key-themes strip, then force the next section onto a new page:
officecli add "$FILE" /body --type paragraph --prop text="CONFIDENTIAL — CLIENT USE ONLY" --prop align=center --prop size=9pt --prop color=C00000 --prop spaceAfter=24pt
officecli add "$FILE" /body --type paragraph --prop text="Strategic Growth Review" --prop style=Title --prop size=32pt --prop bold=true --prop align=center --prop font=Cambria --prop spaceAfter=8pt
officecli add "$FILE" /body --type paragraph --prop text="FY26 Outlook and Scenario Planning" --prop italic=true --prop size=16pt --prop align=center --prop spaceAfter=36pt
officecli add "$FILE" /body --type paragraph --prop text='Prepared for: Acme Corp. Leadership Team' --prop align=cente质量与来源
- 所属仓库
- iOfficeAI/OfficeCLI
- 仓库星标
- 3.2 万
- 最近更新
- 今天
- 采集时间
- 今天
- commit
- fb98e593612d
- 内容指纹
- sha256:4dbeacba4bd1074
- 文件路径
- skills/officecli-docx/SKILL.md