Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/nb-99-docx
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: documents, writing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Python package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/docx
What's inside
- Skill name
docx- Description
- Create, edit, redline, and verify Word .docx files. Use when generating documents with the docx npm package, editing a .docx's XML directly, adding tracked changes (redlining) or comments, or verifying rendered output. Not for .odt, .rtf, .pages, or PDF files.
- License
- MIT
- Instructions
- 230 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Files (4)
- SKILL.md
- openai.yaml · agents/
- add_comment.py · scripts/
- merge_runs.py · scripts/
SKILL.md (first lines)
# Word documents (.docx)
A .docx is a zip of XML parts. Generating from scratch is easiest through the
`docx` npm package; changing an existing file is usually surgical XML editing
of its unpacked parts. Pick the row that matches the task:
| Task | Approach |
| --- | --- |
| Create a new document | Write a Node script with the `docx` package, `Packer.toBuffer` to a file |
| Edit an existing document | Unzip, edit `word/document.xml` (and friends), rezip from inside the directory |
| Read the text | `pandoc -t markdown file.docx` (or `textutil -convert txt` on macOS) |
| Verify visually | `soffice --headless --convert-to pdf` then `pdftoppm -png` and inspect |
| Redline / tracked changes | Edit XML: wrap runs in `w:ins` / `w:del` (see below) |
| Add a comment | `scripts/add_comment.py` to create the parts and print/insert the anchor |
## Generating with the `docx` npm package
Everything below is verified against docx 9.x behavior; treat older versions
with suspicion.
```js
const { Document, Packer, Paragraph, TextRun, HeadingLevel, Table, TableRow,
TableCell, WidthType, ShadingType, AlignmentType, LevelFormat,
TableOfContents, ImageRun, PageBreak, PositionalTab, PositionalTabAlignment,
PositionalTabLeader, PositionalTabRelativeTo, PageOrientation } = require("docx");
const doc = new Document({
numbering: { config: [{ reference: "bullets",
levels: [{ level: 0, format: LevelFormat.BULLET, text: "\u2022",
style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] }] },
sections: [{
properties: { page: { size: { width: 12240, height: 15840 } } }, // US Letter
children: [ /* Paragraphs and Tables */ ],
}],
});
Packer.toBuffer(doc).then((buf) => fs.writeFileSync("out.docx", buf));
```
Dimensions are DXA: **1440 DXA = 1 inch**. The default page is A4
(11906 x 16838); for US Letter pass `width: 12240, height: 15840` explicitly.
Landscape keeps the same two numbers swapped plus
`orientation: PageOrientation.LANDSCAPE` — the library writes both the
swapped `w:pgSz` values and `w:orient="landscape"`, so don't pre-swap them
yourself.
Hard-won gotchas:
- **Tables need widths twice**: `columnWidths: [dxa, ...]` on the Table AND
`width: { size: dxa, type: WidthType.DXA }` on every TableCell. DXA only —
percentage widths resolve against different bases in Word, LibreOffice, and
pandoc, and tables come out squashed or sprawling somewhere.
- **Cell shading is `ShadingType.CLEAR`, never SOLID.** SOLID darkens the
fill; CLEAR (the Word default `w:shd w:val="clear"`) renders the plain fill
color you chose.
- **Bullets come from a numbering config** (`numbering.config` + a Paragraph
with `numbering: { reference, level }`). Never type a literal "•" into a
run — it loses list semantics, indentation, and hanging indents.
- **`ImageRun` needs an explicit `type: "png"` (or jpeg/gif/svg).** Omit it
and docx 9.x silently stores the media part as `image.undefined` with no
content type; LibreOffice tolerates that, Word offers to "repair" the file.
- **`PageBreak` must sit inside a Paragraph's children**, not bare in a
section. A break not wrapped in a paragraph is dropped or corrupts output.
- **No `\n` inside a TextRun.** It is written to the XML as a literal
backslash-n and shows up in the document as that text. One paragraph per
line, or `new TextRun({ break: 1 })` for a line break within a paragraph.
- **`TableOfContents` writes an empty field marked dirty** (`TOC \h \o "1-2"`
with `w:dirty="true"`). It renders empty everywhere until a field update:
Word populates it on open/print, LibreOffice via Tools > Update > Indexes —
`soffice --headless --convert-to pdf` does NOT populate it, so don't panic
when the PDF shows no TOC.
- **TOC and pandoc headings need heading styles that resolve.** Give body
headings `heading: HeadingLevel.HEADING_1` (or `outlineLevel`). pandoc
recognizes headings through the styles part; docx-js emits
`<w:basedOn w:val="Normal"/>` on every style but never *defines* a `Normal`
style, and pandoc's style resolution then fails, demoting every heading to
a plain paragraph in the pandoc read-back. Fix by injecting one style into
`word/styles.xml` before (or after) generation:
`<w:style w:type="paragraph" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style>`
- **Dot leaders are positional tabs**, not padded dots: `new PositionalTab({
alignment: PositionalTabAlignment.RIGHT, leader: PositionalTabLeader.DOT,
relativeTo: PositionalTabRelativeTo.MARGIN })` inside the paragraph
produces `<w:ptab w:leader="dot"/>` — real right-aligned dot leaders that
survive font changes.
- **Namespaces in output are heavy but harmless.** docx-js declares a dozen
namespaces and drops an empty self-closing `<w:comments .../>` scaffold
into the package. Word and LibreOffice ignore both.
## Editing an existing .docx
Unzip to a directory and edit the XML parts by hand (or with a script):
```sh
mkdir dir && unzip -o file.docx -d dir # word/document.xml is the body
# ... edit ...
cd dir && zip -Xr ../out.docx . # rezip FROM INSIDE the directory
```
- **Check for symlink entries in untrusted files first.** `zipinfo
file.docx` prints a mode column; any entry starting with `l` (e.g.
`lrwxrwxrwx`) is a symlink, and command-line `unzip` will happily create
it (pointing wherever the archive wants, e.g. `/etc/passwd` when you later
read or follow it). Python's `zipfile` is safe — it writes symlink entries
as regular files — so for anything you didn't generate yourself, either
extract with python or filter out `l`-mode entries.
- **Rezip from inside the directory** (`cd dir && zip -Xr ../out.docx .`).
Zipping with paths (`zip -r out.docx dir/`) nests a `dir/` prefix inside
the archive and Word can't find the parts. `-X` strips filesystem extra
fields; unlike odt/epub there is no stored-first entry requirement, so any
entry order works.
- **Visible phrases are usually fragmented XML.** Word splits text across
many `<w:r>` runs (spellcheck markers, rsid revision ids, IME input), so
"the quick brown fox" is rarely one `<w:t>` — you often can't wrap it in a
`w:ins`, delete it, or anchor a comment to it directly. Run
`scripts/merge_runs.py` to coalesce adjacent same-format runs (it never
changes text or formatting), then re-read.
- **`w:rsid*` attributes are inert session bookkeeping** — safe to ignore
and safe to keep; don't try to "clean" them while editing.
- **Validate after every edit**: `python3 -c "from
xml.etree import ElementTree; ElementTree.parse('dir/word/document.xml')"`.From nb-99/skillektion, MIT.
More from nb-99/skillektion
- 0.589score
engineering-principles
nb-99
Apply conditional engineering principles to code changes, test writing or review, performance testing already in scope, and substantial design, migration…
SkillAFreshness: A★ 1Claude Code +9 - 0.586score
creating-a-pr-mr
nb-99
Create a pull request or merge request.
SkillAFreshness: A★ 1Claude Code +9 - 0.581score
forgejo-cli
nb-99
Use fj and fgj for everyday Forgejo issues, pull requests, Actions, tags, releases, and wiki workflows.
SkillAFreshness: A★ 1Claude Code +9 - 0.562score
codebase-design
nb-99
Shared vocabulary for designing deep modules.
SkillAFreshness: A★ 1Claude Code +9 - 0.562score
domain-modeling
nb-99
Build and sharpen a project's domain model.
SkillAFreshness: A★ 1Claude Code +9 - 0.549score
code-review
nb-99
Review implemented changes for completeness, correctness, simplification, security, quality, tests, performance, and documentation.
SkillBFreshness: B★ 1Claude Code +9 - 0.544score
blast-radius
nb-99
Analyze what a change could break beyond its diff and prove the central safety invariant with executable evidence.
SkillBFreshness: B★ 1Claude Code +9 - 0.544score
confluence-workflow
nb-99
Fetch and search Telekom Confluence wiki pages.
SkillBFreshness: B★ 1Claude Code +9 - 0.544score
gh-cli
nb-99
Operate on GitHub from the terminal with the gh CLI.
SkillBFreshness: B★ 1Claude Code +9 - 0.544score
glab-cli
nb-99
Operate on GitLab from the terminal with the glab CLI.
SkillBFreshness: B★ 1Claude Code +9 - 0.544score
how
nb-99
Explain how code, a feature flow, or a subsystem works and where its responsibilities belong.
SkillBFreshness: B★ 1Claude Code +9 - 0.542score
bro
nb-99
Restate the assistant's previous message in plain, concise human language.
SkillBFreshness: B★ 1Claude Code +9
Signals
- Stars
- 1
- Forks
- 0
- Open issues
- 1
- Last commit (this folder)
- Sep 6, 2026 (1 month ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/nb-99/skillektion
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from nb-99
- 0.589score
engineering-principles
nb-99
Apply conditional engineering principles to code changes, test writing or review, performance testing already in scope, and substantial design, migration…
SkillAFreshness: A★ 1Claude Code +9 - 0.586score
creating-a-pr-mr
nb-99
Create a pull request or merge request.
SkillAFreshness: A★ 1Claude Code +9 - 0.581score
forgejo-cli
nb-99
Use fj and fgj for everyday Forgejo issues, pull requests, Actions, tags, releases, and wiki workflows.
SkillAFreshness: A★ 1Claude Code +9 - 0.562score
codebase-design
nb-99
Shared vocabulary for designing deep modules.
SkillAFreshness: A★ 1Claude Code +9 - 0.562score
domain-modeling
nb-99
Build and sharpen a project's domain model.
SkillAFreshness: A★ 1Claude Code +9 - 0.549score
code-review
nb-99
Review implemented changes for completeness, correctness, simplification, security, quality, tests, performance, and documentation.
SkillBFreshness: B★ 1Claude Code +9
Cite this page
docx skill. Agent Mart. https://agentmart.dev/skills/nb-99-docx (last updated 2026-10-24)