Read a reviewed docx into a reconciliation table with a single command: who commented, which paragraph they commented on, what they commented, and the handling status, plus the paragraph-by-paragraph deletions and changes in track changes mode. The produced table comes with a blank "Disposition" column — its purpose is precisely to be used for item-by-item adjudication.
The engine is distilled from the author's review toolchain for a real book publishing project (in production validation since 2026-02: 96 editorial comments in a single file, whole-book revision handling, inputs including WPS cloud document exports); this is a generalized version. The manuscript-level deep editing workflow (version chains, comment resolve state machine, review dashboard) remains in the original project (private) and is outside the scope of this skill.
Quick Start
All commands in this document assume the working directory is this skill's root directory(scripts/ is a relative path) — first cd over, or replace scripts/… with an absolute path; the docx argument does not care whether it is relative or absolute.
uv run python scripts/extract_review.py <审阅稿.docx>
Expected output (when there are comments):
# 审阅对账 · 某某协议-审阅版.docx
批注 12 条(未处理 10 / 已处理 2,其中回复 1 条);修订段落 3 个(删除元素 2、插入元素 4)。
## 批注
| # | 批注人 | 时间 | 锚定段落 | 批注内容 | 状态 | 处置 |
|---|---|---|---|---|---|---|
| 0 | 张三 | 2026-02-14 16:02 | 乙方应于收到通知后 15 个工作日内… | 15 天太短,建议 30 天 | 未处理 | |
| ↳1 | 李四 | 2026-02-14 18:11 | (回复 #0) | 同意,30 天合理 | 未处理 | |
## 修订(track changes)
| 段落 | 删除 | 插入 | 处置 |
|---|---|---|---|
| 47 | 百分之十五 | 百分之十 | |
When there are no comments and no revisions, output a clear notice ("this docx carries no review traces" + two common causes); it will not silently output an empty table — getting a copy with the comments lost and assuming the other party has no opinions is more dangerous than misreading the content.
Variants:
# 机器可读全量(锚定段落不截断、含全部字段)
uv run python scripts/extract_review.py <docx> --json
# 对账表包含已处理(resolved)的批注(默认只列未处理)
uv run python scripts/extract_review.py <docx> --include-resolved
To see more context paragraphs before and after a given comment (the reconciliation table's anchor column is truncated to 60 characters,--json contains the full text):
uv run python -c "
import sys; sys.path.insert(0, 'scripts') # 同样假设 cwd = skill 根目录
from bridge_lib.docx_bridge_client import extract_views
for v in extract_views('<docx>', paragraph_range=(40, 55)): # 批注锚定段落 ±N
print(v['index'], v['display'][:100])"
Why you must go through this engine (do not fall back to raw python-docx reading)
python-docx's paragraph.text goes through paragraph.runs, and runs only take direct child <w:r>, without recursively
<w:ins> wrapping —all content the other party inserted using track changes mode will be missed in reading; raw lxml's .//w:t can read
ins, but cannot recognize "an entire paragraph whose paragraph mark is wrapped by <w:del> " (content that would disappear entirely after accepting the revision still has <w:t>).
Both directions of missed reading have been encountered on real publishing review drafts. This skill's csx engine is based on the OpenXML SDK officially maintained by the Word engineering team, where ins/del/move are first-class citizens. For mechanism details, paragraph index semantics (body direct child paragraphs, aligned with python-docx, not recursing into paragraphs inside tables) and the output parameter specifications of the three csx commands, see
references/csharp-tasks-spec.md。
scripts/bridge_lib/docx_bridge_client.py is the Python entry layer:list_comments() /
list_revisions() / extract_views() / paragraph_text(), all of which are stateless direct docx reads, with in-memory caching by
(path+mtime). When writing custom analysis, import it; do not bypass it to hand-parse XML.
Dependencies (install once on first use)
brew install dotnet # 或已有任意 .NET SDK
dotnet tool install -g dotnet-script # csx 运行时
DOTNET_ROLL_FORWARD=Majoris already configured built-in by the client (automatically compatible when the local .NET version is higher than the csx target version).~/.dotnet/toolsWhen not in PATH, the client will automatically add it; no manual export is needed.- NuGet package (DocumentFormat.OpenXml 3.2.0, declared in csx via
#r) automatically restores on first run, requires network; the first run being slow at about 10-30 seconds is normal; after that it uses the local package cache. - The Python side is pure stdlib, with zero third-party dependencies (all parsing is done on the C# side; Python only does orchestration and rendering) —
uv run pythonor the system'spython3can both run it.
Troubleshooting
| Symptom | Cause | Handling |
|---|---|---|
csx script failed … dotnet-script: command not found |
dotnet-script not installed | two install commands in the dependency section above |
| first run hangs 10-30 seconds | NuGet first restore | normal, wait for it; offline environments will fail, needs one online first run |
| 0 annotations, but the other party says they annotated | the copy you received lost annotations on export; or the other party annotated on the online document and it was not exported | ask the other party to "Download/Save As docx" again. WPS cloud documents' "Download as docx" was tested to preserve annotations and resolved status (as of 2026-03, 96 annotations from a real publishing review draft came from exactly this source; this skill's empty-result notice also reminds about this item) |
| annotations are there, but "filter by chapter" type requests cannot be done | the document did not use Word Heading styles (many generators typeset text directly) | locate by anchored paragraph numbers; the reconciliation table itself is unaffected |
| revision table is empty, but red-text changes are visible in Word | the changes in that file have already been accepted/rejected, the red text is a comparison view | revisions only exist in unaccepted track changes; ask the other party to send the original manuscript with revisions unaccepted |
Design boundaries (to prevent re-litigating in the future)
- The Python ecosystem has annotation/revision libraries such as docx-revisions, docx-editor, docx2python (verified to exist as of 2026-08). Not adopted: this engine has already been production-verified in real publishing review workflows, and the OpenXML SDK is the official implementation with a higher ceiling for revision semantic fidelity; the patch layer of community libraries over python-docx has not been verified by us, and redoing verification for an already-solved problem is a negative return.
- This skill is read-only. It does not provide "accept/reject revisions", "reply to annotations", or "edit the text and re-export" — post-reconciliation changes should land in your own authoritative source (contract draft SSOT, manuscript source file) and be regenerated, not made on the other party's review copy.
- PDF annotations and Feishu/Tencent Docs online annotations are out of scope (each has its own dedicated toolchain).
Next Step
Common downstream after the reconciliation table is produced: item-by-item adjudication is done by the document owner (the "Disposition" column of the table); when you need to modify the contract/agreement/manuscript authoritative source and regenerate the external document, go through your own project's drafting and regeneration workflow — this skill deliberately does not touch manuscript editing.