{"skill":{"slug":"docx-editing","displayName":"Docx Editing","summary":"Surgically edit existing (brownfield) .docx files with formatting preservation and tracked changes via the Safe-DOCX MCP server. Use when user says \"edit thi...","description":"---\nname: docx-editing\ndescription: >-\n  Surgically edit existing (brownfield) .docx files with formatting preservation\n  and tracked changes via the Safe-DOCX MCP server. Use when user says \"edit this\n  docx,\" \"change the contract,\" \"redline the document,\" \"compare these Word files,\"\n  \"add a comment to the docx,\" \"read this Word file,\" or \"mark up the agreement.\"\n  Not for from-scratch document generation.\nlicense: MIT\ncompatibility: >-\n  Works with any MCP-compatible agent. Requires Node.js >=18.0.0 and npm\n  (for npx) on the host machine. The MCP server runs locally as a stdio\n  child process. Install-time: npm registry fetch (one-time, cacheable).\n  Runtime: zero network calls, file access limited to ~/ and system temp.\nrequires:\n  binaries:\n    - node (>=18.0.0)\n    - npx (bundled with npm)\n  network:\n    install_time: npm registry (registry.npmjs.org) — one-time fetch\n    runtime: none\n  filesystem:\n    - ~/ (home directory)\n    - system temp directories\nmetadata:\n  author: safe-docx\n  version: \"0.3.0\"\n---\n\n# Editing .docx Files with Safe-DOCX\n\nSafe-DOCX is a local MCP server for surgically editing existing `.docx` files. It preserves formatting, generates tracked-changes redlines, and — once installed — runs entirely on the local filesystem with zero network activity.\n\n## Source Code and Audit\n\nSafe-DOCX is fully open source (MIT license). Review the complete source before installing:\n\n- **GitHub**: https://github.com/UseJunior/safe-docx\n- **npm registry**: https://www.npmjs.com/package/@usejunior/safe-docx\n- **Code coverage**: Published via Codecov on every release\n- **Conformance harness**: Automated spec coverage tests run in CI on every commit\n- **No postinstall scripts** — verify: `npm view @usejunior/safe-docx scripts` shows no `postinstall` or `install` hooks\n\nAll security claims below are verifiable by reading the source.\n\n## Runtime Requirements\n\nSafe-DOCX requires these binaries to be available on the host:\n\n| Binary | Minimum version | Why |\n|--------|-----------------|-----|\n| `node` | 18.0.0 | Authoritative version from `packages/safe-docx/package.json` engines field |\n| `npx` | Bundled with npm | Used by the recommended MCP connector to launch the server |\n\nIf you prefer not to use `npx`, see **Offline / Pinned Installation** below for alternatives.\n\n## Safety Model\n\nSafe-DOCX's safety model has two distinct phases: **install time** (when the package is fetched) and **runtime** (when the MCP server is running).\n\n### Install-Time Behavior (network required, one-time)\n\n- **npm registry fetch** — the recommended connector command `npx -y @usejunior/safe-docx` downloads the package from `registry.npmjs.org` on first run. Subsequent runs use the cached copy unless the cache is cleared.\n- **No postinstall scripts** — the package declares no `postinstall`, `preinstall`, or `install` hooks. Verify with `npm view @usejunior/safe-docx scripts`.\n- **Provenance** — releases are published with npm provenance (`--provenance`), so you can verify the package was built from the public GitHub repo via GitHub Actions.\n- **If you need guaranteed offline install** — pin a specific version and vendor it locally. See the next section.\n\n### Runtime Behavior (zero network)\n\n- **Local-only stdio runtime** — the MCP server runs as a child process, never binds a port. Verify: the entry point (`src/server.ts`) uses `StdioServerTransport` with no HTTP listener. ([source](https://github.com/UseJunior/safe-docx/blob/main/packages/safe-docx/src/server.ts))\n- **No outbound network calls** — at runtime, the package makes zero outbound HTTP requests. Verify: `grep -r \"fetch\\|http\\.\\|https\\.\\|net\\.\" packages/safe-docx/src/` returns no matches in application code (test fixtures excluded).\n- **Path policy** — only files under `~/` (home directory) and system temp directories are accessible. Symlinks must resolve to allowed roots.\n- **Archive guardrails** — zip bomb detection and hostile payload rejection protect against malformed `.docx` inputs.\n\n## Offline / Pinned Installation\n\nFor high-security environments where `npx` auto-fetch is unacceptable, install the package manually and pin the version:\n\n```bash\n# Option 1: Pin a specific version globally\nnpm install -g @usejunior/safe-docx@0.9.0\n\n# Then configure your MCP client to invoke it by path:\n# command: \"safe-docx\"\n# args: []\n\n# Option 2: Vendor the package into your project\nnpm pack @usejunior/safe-docx@0.9.0\n# Inspect the tarball, then install it from disk:\nnpm install -g ./usejunior-safe-docx-0.9.0.tgz\n\n# Option 3: Build from source (most auditable)\ngit clone https://github.com/UseJunior/safe-docx.git\ncd safe-docx\ngit checkout <release-tag>\nnpm ci\nnpm run build\nnpm link packages/safe-docx\n```\n\nAfter any of these, your MCP client config becomes:\n\n```json\n{\n  \"mcpServers\": {\n    \"safe-docx\": {\n      \"command\": \"safe-docx\",\n      \"args\": []\n    }\n  }\n}\n```\n\nUsing `command: \"safe-docx\"` (the installed binary) instead of `command: \"npx\"` eliminates the install-time network fetch on every invocation.\n\n### Always pin the version\n\nEven with `npx`, you can pin the version to prevent unexpected updates:\n\n```json\n{\n  \"mcpServers\": {\n    \"safe-docx\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@usejunior/safe-docx@0.9.0\"]\n    }\n  }\n}\n```\n\nBefore upgrading, review the changelog: https://github.com/UseJunior/safe-docx/blob/main/CHANGELOG.md\n\n## When to Use This Skill\n\nUse Safe-DOCX when you need to:\n\n- Change clauses or paragraphs in an existing `.docx`\n- Insert or delete content with formatting preservation\n- Add comments or footnotes for reviewers\n- Produce a tracked-changes redline from edits\n- Compare two `.docx` files into a redline\n- Extract revisions to structured JSON\n- Apply layout formatting (spacing, row heights, cell padding)\n\n## Not for From-Scratch Generation\n\nSafe-DOCX edits already-existing `.docx` files — it does not create documents from blank. For new document generation, use a template-filling workflow (e.g. OpenAgreements). Safe-DOCX can refine generated docs downstream.\n\n## Quick Start\n\n```\n1. read_file(file_path=\"~/doc.docx\")        → see paragraphs + _bk_* IDs\n2. grep(file_path=\"~/doc.docx\", patterns=[\"target phrase\"])  → find paragraph IDs\n3. replace_text(session_id, target_paragraph_id, old_string, new_string, instruction)\n4. save(session_id, save_to_local_path=\"~/doc-edited.docx\")\n```\n\n## Core Workflow: Read, Locate, Edit, Save\n\n**Step 1 — Read.** Call `read_file` with `format: \"toon\"` (token-efficient table) to see paragraphs and their stable `_bk_*` IDs.\n\n**Step 2 — Locate.** Use `grep` with regex patterns to find target paragraphs. It returns paragraph IDs with surrounding context.\n\n**Step 3 — Edit.** Use `replace_text` to swap text within a paragraph, or `insert_paragraph` to add new paragraphs before/after an anchor.\n\n**Step 4 — Save.** Call `save` to write output. Default is `save_format: \"both\"` which produces a clean copy and a tracked-changes redline.\n\n## Gotchas That Will Bite You\n\n### Unique match required\n\n`replace_text` needs `old_string` to match **exactly one** location in the target paragraph. If the text appears multiple times, you get `MULTIPLE_MATCHES`. Fix: include more surrounding context in `old_string`.\n\n```\nBAD:  old_string: \"the Company\"          → 5 matches, fails\nGOOD: old_string: \"the Company shall indemnify\"  → 1 match, succeeds\n```\n\n### Footnote markers are display-only\n\n`read_file` shows footnotes as `[^1]`, `[^2]`, etc., but these markers are **not part of the editable text**. You cannot search for or replace `[^1]` via `replace_text`. To modify footnotes, use the dedicated `add_footnote`, `update_footnote`, and `delete_footnote` tools.\n\n### Hyperlinks are read-only\n\n`read_file` shows links as `<a href=\"...\">text</a>`, but you **cannot create new hyperlinks** via `replace_text` or `insert_paragraph`. The `<a>` tag is stripped from new text. Existing hyperlinks are preserved when surrounding text is edited.\n\n### Paragraph IDs are session-scoped\n\nThe `_bk_*` bookmark IDs are generated when a document is opened and are **tied to that session**. Do not store or reuse IDs across sessions. Always re-read the document to get fresh IDs.\n\n### Smart text matching\n\n`replace_text` is tolerant of:\n- Quote variants: straight `\"`, curly `\\u201c\\u201d`, angle `\\u00ab\\u00bb` all match each other\n- Whitespace differences: multiple spaces, tabs, and line breaks are normalized\n\nThis means you can copy text from `read_file` output and use it in `old_string` even if the underlying XML uses different quote characters.\n\n## Formatting Tags\n\nWhen writing `new_string` in `replace_text` or `insert_paragraph`, use inline tags to apply formatting:\n\n| Tag | Effect |\n|-----|--------|\n| `<b>text</b>` | Bold |\n| `<i>text</i>` | Italic |\n| `<u>text</u>` | Underline |\n| `<highlighting>text</highlighting>` | Yellow highlight |\n\nTags can be nested: `<b><i>bold italic</i></b>`. Formatting from the original matched text is preserved for untagged replacement text.\n\n## Batch Edits with apply_plan\n\nFor 3+ edits on one document, prefer `apply_plan` over sequential `replace_text` calls. It validates all steps before applying any, so you get all-or-nothing transactional semantics.\n\n```\n1. read_file / grep  → gather paragraph IDs and text\n2. apply_plan(file_path, steps=[\n     { step_id: \"1\", operation: \"replace_text\", target_paragraph_id, old_string, new_string, instruction },\n     { step_id: \"2\", operation: \"insert_paragraph\", positional_anchor_node_id, new_string, instruction },\n     ...\n   ])\n3. save(session_id, save_to_local_path)\n```\n\n## Insert Paragraphs\n\n`insert_paragraph` adds new content before or after an anchor paragraph.\n\n- `position`: `\"BEFORE\"` or `\"AFTER\"` (default `\"AFTER\"`)\n- `style_source_id`: optional `_bk_*` ID of a paragraph whose formatting you want to clone\n- Multi-paragraph: separate with `\\n\\n` in `new_string` (each becomes its own paragraph)\n\n## Comments and Footnotes\n\n**Comments:** `add_comment` anchors to a paragraph (optionally to a text span via `anchor_text`). Use `get_comments` to list, `delete_comment` to remove. Supports threaded replies via `parent_comment_id`.\n\n**Footnotes:** `add_footnote` inserts a footnote marker in a paragraph (optionally after specific text via `after_text`). Use `get_footnotes`, `update_footnote`, `delete_footnote` to manage.\n\n## Comparing Documents\n\nTwo modes:\n- **Two files:** `compare_documents(original_file_path, revised_file_path, save_to_local_path)` — produces a redline\n- **Session edits:** `compare_documents(session_id)` — compares current session state against the original\n\nUse `extract_revisions` on any document with tracked changes to get structured JSON diffs.\n\n## Accepting Tracked Changes\n\nCall `accept_changes(session_id)` to flatten all tracked changes into a clean document. This removes all revision markup.\n\n## Session Behavior\n\n- Sessions auto-create when you first use `file_path` with any tool\n- Sessions expire after **1 hour** of inactivity (each tool call resets the timer)\n- Call `clear_session` to clean up when done\n- Documents are **normalized on open**: format-identical runs are merged and proof-error markers removed, which improves text matching reliability\n\n## Layout Formatting\n\n`format_layout` applies paragraph spacing, table row height, and cell padding without touching text content. Units are in twips (1/20 of a point) or DXA (1/635 of an inch).\n\n## Path Restrictions\n\nBy default, only files under `~/` (home directory) and system temp directories are accessible. Symlinks must resolve to allowed roots.\n\n## Related Skills\n\n- **Open Agreements** (`open-agreements`) — fill standard legal templates (NDAs, SAFEs, cloud service agreements) and produce signable DOCX files: `clawhub install open-agreements/open-agreements`\n- **Outlook Email Management** (`outlook-email-management`) — manage Outlook email with AI agents: `clawhub install stevenobiajulu/outlook-email-management`\n\n## Connectors\n\nFor MCP server setup instructions (Claude Desktop, Cursor, Claude Code), see [CONNECTORS.md](./CONNECTORS.md).\n\n## Feedback\n\nIf this skill helped, star us on GitHub: https://github.com/UseJunior/safe-docx\nOn ClawHub: `clawhub star usejunior/docx-editing`\n","tags":{"latest":"0.3.0"},"stats":{"comments":0,"downloads":1436,"installsAllTime":10,"installsCurrent":10,"stars":2,"versions":5},"createdAt":1772340335902,"updatedAt":1778491674555},"latestVersion":{"version":"0.3.0","createdAt":1775654758792,"changelog":"Address ClawHub security scan feedback: declare required binaries (node >=18, npx) in frontmatter; separate install-time vs runtime safety model; add offline/pinned install path; fix Node version inconsistency (was >=20, now matches package.json >=18); add no-postinstall-scripts disclosure and npm provenance note","license":"MIT-0"},"metadata":null,"owner":{"handle":"stevenobiajulu","userId":"s17846kvqgde4k0takks4byt0184fe4h","displayName":"Steven Obiajulu","image":"https://avatars.githubusercontent.com/u/183783362?v=4"},"moderation":null}