Skill: stevenobiajulu/docx-editing (version 0.3.0)

--- name: docx-editing description: >- Surgically edit existing (brownfield) .docx files with formatting preservation and tracked changes via the Safe-DOCX MCP server. Use when user says "edit this docx," "change the contract," "redline the document," "compare these Word files," "add a comment to the docx," "read this Word file," or "mark up the agreement." Not for from-scratch document generation. license: MIT compatibility: >- Works with any MCP-compatible agent. Requires Node.js >=18.0.0 and npm (for npx) on the host machine. The MCP server runs locally as a stdio child process. Install-time: npm registry fetch (one-time, cacheable). Runtime: zero network calls, file access limited to ~/ and system temp. requires: binaries: - node (>=18.0.0) - npx (bundled with npm) network: install_time: npm registry (registry.npmjs.org) — one-time fetch runtime: none filesystem: - ~/ (home directory) - system temp directories metadata: author: safe-docx version: "0.3.0" --- # Editing .docx Files with Safe-DOCX Safe-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. ## Source Code and Audit Safe-DOCX is fully open source (MIT license). Review the complete source before installing: - **GitHub**: https://github.com/UseJunior/safe-docx - **npm registry**: https://www.npmjs.com/package/@usejunior/safe-docx - **Code coverage**: Published via Codecov on every release - **Conformance harness**: Automated spec coverage tests run in CI on every commit - **No postinstall scripts** — verify: `npm view @usejunior/safe-docx scripts` shows no `postinstall` or `install` hooks All security claims below are verifiable by reading the source. ## Runtime Requirements Safe-DOCX requires these binaries to be available on the host: | Binary | Minimum version | Why | |--------|-----------------|-----| | `node` | 18.0.0 | Authoritative version from `packages/safe-docx/package.json` engines field | | `npx` | Bundled with npm | Used by the recommended MCP connector to launch the server | If you prefer not to use `npx`, see **Offline / Pinned Installation** below for alternatives. ## Safety Model Safe-DOCX's safety model has two distinct phases: **install time** (when the package is fetched) and **runtime** (when the MCP server is running). ### Install-Time Behavior (network required, one-time) - **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. - **No postinstall scripts** — the package declares no `postinstall`, `preinstall`, or `install` hooks. Verify with `npm view @usejunior/safe-docx scripts`. - **Provenance** — releases are published with npm provenance (`--provenance`), so you can verify the package was built from the public GitHub repo via GitHub Actions. - **If you need guaranteed offline install** — pin a specific version and vendor it locally. See the next section. ### Runtime Behavior (zero network) - **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)) - **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). - **Path policy** — only files under `~/` (home directory) and system temp directories are accessible. Symlinks must resolve to allowed roots. - **Archive guardrails** — zip bomb detection and hostile payload rejection protect against malformed `.docx` inputs. ## Offline / Pinned Installation For high-security environments where `npx` auto-fetch is unacceptable, install the package manually and pin the version: ```bash # Option 1: Pin a specific version globally npm install -g @usejunior/safe-docx@0.9.0 # Then configure your MCP client to invoke it by path: # command: "safe-docx" # args: [] # Option 2: Vendor the package into your project npm pack @usejunior/safe-docx@0.9.0 # Inspect the tarball, then install it from disk: npm install -g ./usejunior-safe-docx-0.9.0.tgz # Option 3: Build from source (most auditable) git clone https://github.com/UseJunior/safe-docx.git cd safe-docx git checkout <release-tag> npm ci npm run build npm link packages/safe-docx ``` After any of these, your MCP client config becomes: ```json { "mcpServers": { "safe-docx": { "command": "safe-docx", "args": [] } } } ``` Using `command: "safe-docx"` (the installed binary) instead of `command: "npx"` eliminates the install-time network fetch on every invocation. ### Always pin the version Even with `npx`, you can pin the version to prevent unexpected updates: ```json { "mcpServers": { "safe-docx": { "command": "npx", "args": ["-y", "@usejunior/safe-docx@0.9.0"] } } } ``` Before upgrading, review the changelog: https://github.com/UseJunior/safe-docx/blob/main/CHANGELOG.md ## When to Use This Skill Use Safe-DOCX when you need to: - Change clauses or paragraphs in an existing `.docx` - Insert or delete content with formatting preservation - Add comments or footnotes for reviewers - Produce a tracked-changes redline from edits - Compare two `.docx` files into a redline - Extract revisions to structured JSON - Apply layout formatting (spacing, row heights, cell padding) ## Not for From-Scratch Generation Safe-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. ## Quick Start ``` 1. read_file(file_path="~/doc.docx") → see paragraphs + _bk_* IDs 2. grep(file_path="~/doc.docx", patterns=["target phrase"]) → find paragraph IDs 3. replace_text(session_id, target_paragraph_id, old_string, new_string, instruction) 4. save(session_id, save_to_local_path="~/doc-edited.docx") ``` ## Core Workflow: Read, Locate, Edit, Save **Step 1 — Read.** Call `read_file` with `format: "toon"` (token-efficient table) to see paragraphs and their stable `_bk_*` IDs. **Step 2 — Locate.** Use `grep` with regex patterns to find target paragraphs. It returns paragraph IDs with surrounding context. **Step 3 — Edit.** Use `replace_text` to swap text within a paragraph, or `insert_paragraph` to add new paragraphs before/after an anchor. **Step 4 — Save.** Call `save` to write output. Default is `save_format: "both"` which produces a clean copy and a tracked-changes redline. ## Gotchas That Will Bite You ### Unique match required `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`. ``` BAD: old_string: "the Company" → 5 matches, fails GOOD: old_string: "the Company shall indemnify" → 1 match, succeeds ``` ### Footnote markers are display-only `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. ### Hyperlinks are read-only `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. ### Paragraph IDs are session-scoped The `_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. ### Smart text matching `replace_text` is tolerant of: - Quote variants: straight `"`, curly `\u201c\u201d`, angle `\u00ab\u00bb` all match each other - Whitespace differences: multiple spaces, tabs, and line breaks are normalized This means you can copy text from `read_file` output and use it in `old_string` even if the underlying XML uses different quote characters. ## Formatting Tags When writing `new_string` in `replace_text` or `insert_paragraph`, use inline tags to apply formatting: | Tag | Effect | |-----|--------| | `<b>text</b>` | Bold | | `<i>text</i>` | Italic | | `<u>text</u>` | Underline | | `<highlighting>text</highlighting>` | Yellow highlight | Tags can be nested: `<b><i>bold italic</i></b>`. Formatting from the original matched text is preserved for untagged replacement text. ## Batch Edits with apply_plan For 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. ``` 1. read_file / grep → gather paragraph IDs and text 2. apply_plan(file_path, steps=[ { step_id: "1", operation: "replace_text", target_paragraph_id, old_string, new_string, instruction }, { step_id: "2", operation: "insert_paragraph", positional_anchor_node_id, new_string, instruction }, ... ]) 3. save(session_id, save_to_local_path) ``` ## Insert Paragraphs `insert_paragraph` adds new content before or after an anchor paragraph. - `position`: `"BEFORE"` or `"AFTER"` (default `"AFTER"`) - `style_source_id`: optional `_bk_*` ID of a paragraph whose formatting you want to clone - Multi-paragraph: separate with `\n\n` in `new_string` (each becomes its own paragraph) ## Comments and Footnotes **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`. **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. ## Comparing Documents Two modes: - **Two files:** `compare_documents(original_file_path, revised_file_path, save_to_local_path)` — produces a redline - **Session edits:** `compare_documents(session_id)` — compares current session state against the original Use `extract_revisions` on any document with tracked changes to get structured JSON diffs. ## Accepting Tracked Changes Call `accept_changes(session_id)` to flatten all tracked changes into a clean document. This removes all revision markup. ## Session Behavior - Sessions auto-create when you first use `file_path` with any tool - Sessions expire after **1 hour** of inactivity (each tool call resets the timer) - Call `clear_session` to clean up when done - Documents are **normalized on open**: format-identical runs are merged and proof-error markers removed, which improves text matching reliability ## Layout Formatting `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). ## Path Restrictions By default, only files under `~/` (home directory) and system temp directories are accessible. Symlinks must resolve to allowed roots. ## Related Skills - **Open Agreements** (`open-agreements`) — fill standard legal templates (NDAs, SAFEs, cloud service agreements) and produce signable DOCX files: `clawhub install open-agreements/open-agreements` - **Outlook Email Management** (`outlook-email-management`) — manage Outlook email with AI agents: `clawhub install stevenobiajulu/outlook-email-management` ## Connectors For MCP server setup instructions (Claude Desktop, Cursor, Claude Code), see [CONNECTORS.md](./CONNECTORS.md). ## Feedback If this skill helped, star us on GitHub: https://github.com/UseJunior/safe-docx On ClawHub: `clawhub star usejunior/docx-editing`


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)