Looks promising for document editing with your agent

原始链接: https://www.paperinstruments.com/blog/introducing-paper-office

Hacker News 最新 | 往期 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 [已标记] nvmdbljstm 2天前 | 隐藏 | 往期 | 收藏 codingdave 1天前 | 下一条 [–] 实际标题:介绍 Paper Office 根据社区准则:“请使用原始标题,除非其具有误导性或属于诱导点击;请勿添加个人观点。” https://news.ycombinator.com/newsguidelines.html 社区准则 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系方式 搜索:
相关文章

原文

Today, we release Paper Office, a suite of Python packages that allow agents to manipulate Word, PowerPoint, and Excel files with added safety, correctness and breadth, building on legacy open source packages: python-docx, python-pptx and OpenPyxl. Across five models and 61 tasks, Paper packages plus guidance passed 92.5% of trials, versus 80.7% for upstream packages without skills and 69.5% with Anthropic's comparable Office skills. Agents also wrote code to edit Office file internals directly in just 1.6% of Paper runs, compared with 78.7% without skills and 50.5% with Anthropic skills. We note that basic software, in addition to prompt, skills, and tools, remains an important lever for harness optimization.

Agents still have low penetration in the daily work of consultants, lawyers, bankers, and operators. We believe the bottleneck to professional adoption is fidelity to real workflows. Agents dont manipulate existing documents with the same techniques that humans do, and the resulting decks, sheets, and documents sit in an uncanny valley that aren't fit for client consumption.

DOCX, PPTX, and XLSX files use Office Open XML (OOXML): each is a ZIP archive containing XML files, images, and other resources linked together, rather than a single text file. Editing them means keeping those parts and their relationships consistent, so even a small visible change can require updates in several places.

The standard Python Office libraries (python-docx, python-pptx, and openpyxl) are mature construction tools with years of accumulated edge cases, and most production agents often rely on these libraries for doc manipulation. However, they haven't seen updates in several years and, for many important workflows, lack feature breadth and correctness contracts. In some cases, models opt for other Javascript based packages or HTML-to-document processes to more easily represent and manipulate classic office documents, but these intermediate representations are lossy and often corrupt existing, brownfield work.

We forked, patched, and reworked the APIs of the standard Python Office libraries to support a variety of agent-first use cases, improving correctness and expanding feature completeness.

An agent editing a file often has to:

  • find the logical object a user refers to, even when its text is split across elements or inherited from a template
  • apply the requested change while maintaining formatting and relationships
  • preserve everything outside the requested scope, including package parts the library does not understand
  • reopen the saved artifact and establish that the intended effect survived serialization.

When the package cannot express those operations, the model falls through to wrapper scripts and raw OOXML, polluting its context with package mechanics. This frequently leads to silent regressions in comment anchors, chart workbooks, fields, custom XML, formula dependencies and so on.

Paper Office keeps the familiar imports and extends the packages underneath them. Existing model priors remain useful: import docx, from pptx import Presentation, and import openpyxl still work.

The additions expose hidden structure as typed, machine-readable data, validate targets before supported edits, provide package-preserving save paths, report bounded changes, and refuse explicitly when an operation cannot be handled safely.

Paper DOCX

Overview

paper-docx extends python-docx with document-wide search, tracked edits, comments, composition, and reversible redlines, allowing agents to revise and review existing Word documents using Word's native review model.

Explore Features

The additions, tied to the work:

  • Cross-Run Text Search. docx.search matches exact text across Word's run fragmentation, with opt-in normalized matching, and returns a live Span for replacement, tracked edits, or comment anchoring. Spans revalidate before mutation; reacquire a span after a text-changing replacement.
  • Numbering Restarts. docx.numbering.restart_numbering() creates a new numbering instance that retains the existing definition and restarts at one; apply_numbering() assigns it to the intended paragraphs.
  • Native Word Redlines. docx.package.compare emits text and table-row changes as Word-native tracked changes, verifies both accept and reject outcomes on private copies, and refuses differences it cannot represent safely.
  • Review Resolution and Comment Threads. doc.revisions enumerates supported revisions and accepts or rejects them atomically; remaining_unsupported() identifies forms requiring another tool. docx.commentops manages replies, anchors, and resolution state as a connected thread.
  • Content Controls. docx.controls fills supported controls with typed values. Supported data-bound text updates synchronize visible text with the custom XML store; unsupported bound types, locked controls, and unsafe structures refuse.
  • Fields and Bookmarks. docx.bookmarks and docx.fields create bookmarks over a span and author page numbers, dates, cross-references, and tables of contents as fields with placeholder results.
  • Cross-Document Composition. docx.composition copies formatted content between documents, reconciles styles, numbering, media, hyperlinks, and bookmarks, and reports every part touched.
  • Package Diffs and Saves. docx.package.patch_save restores original bytes for semantically unchanged package parts; diff_package and text_diff report changes, and diagnose explains unreadable packages. Normal Document.save() validates its output but does not promise byte-minimal serialization.
  • Document Protection. docx.protection checks Paper mutations against the active restriction mode: comments-only protection permits comment operations, and forms protection permits supported form updates. An explicit acknowledgment overrides the guard without removing the protection setting.

The fork also traverses body text, headers, footers, footnotes, endnotes, comments, tracked insertions, content controls, and text boxes through docx.story, with revision views and counts of blind regions it cannot read.

Paper PPTX

Overview

paper-pptx extends python-pptx with inherited-format inspection, native bullets, guarded slide and shape edits, cross-deck composition, and structural diffs, enabling surgical diffing of PowerPoint files.

Explore Features

The additions, tied to the work:

  • Effective Formatting Inspection. pptx.inspect, inspect_text, and inspect_deck resolve supported font, paragraph, and shape formatting through the placeholder, layout, master, and theme chain, with provenance and content-fingerprinted BlockAnchor targets. Unsupported values are marked unresolved and unreadable regions are counted.
  • Formatting-Preserving Text Replacement. pptx.edit.replace_text, replace_text_at, and refind replace text while preserving unaffected runs, and anchored edits detect stale content and refuse before a change lands on the wrong text.
  • Relationship-Safe Slide Cloning. prs.slides.clone(), delete(), reorder(), and move() are relationship-safe; cloned charts receive independent embedded workbooks, and unsupported relationships raise typed refusals.
  • Package-Safe Shape Editing. SlideShapes.delete(), move(), and add_copy() edit shapes while preserving ownership, and group-aware by-name lookup refuses ambiguous names and asks the caller to disambiguate.
  • Merged-Cell Table Editing. Table.insert_row(), delete_row(), insert_column(), and delete_column() keep the grid consistent and guard merged regions at the affected cells.
  • Bullets, Numbering, and Notes. Paragraph.bullet and TextFrame.normalize_autofit() author real bullets and make inherited autofit explicit. Slide.read_notes_text() reads without creating a notes part; replace_notes_text() edits an existing notes body.
  • Safe Image and Chart Updates. Picture.replace_image() changes only the target picture while preserving position and crop, even when an image part is shared. Chart.replace_data_safe() validates the target chart and workbook structure, refusing shared chart parts and unsupported chart families.
  • Policy-Based Slide and Deck Imports. Presentation.import_slide() and append_deck() require an explicit reconciliation mode: adopt the destination theme, keep the source appearance, or bake effective values into explicit formatting. They return an ImportReport for each imported slide.
  • Layout Rebinding. Slide.rebind_layout() moves a slide to another layout under explicit placeholder and orphan policies, and its RebindReport identifies every run whose resolved appearance changed.
  • Live Slide Number and Date Fields. Presentation.apply_footers() and Slide.apply_footers() author native a:fld elements bound to footer placeholders. Date formats use datetime1 through datetime13; fixed_date instead writes literal text.
  • Package-Preserving Saves. pptx.package.patch_save() restores original bytes for semantically unchanged members, so unrelated serialization changes need not appear in the delivered package.
  • Permanent-ID Deck Diffs. pptx.diff.diff_decks reports structural changes in decks derived from a common ancestor. detail="text" adds text, chart-data, and notes deltas; detail="full" adds resolved run-formatting and bullet changes.

Intake is hardened too: the package rejects ambiguous or unsafe ZIP archives, including duplicate or case-colliding members, noncanonical paths, encryption, and unsupported compression. Path-based saves write a sibling temporary package and atomically replace the destination after serialization succeeds.

Paper XLSX

Overview

paper-xlsx extends openpyxl with package-preserving saves, reference-aware structural edits, edit receipts, and LibreOffice-backed recalculation, supporting diffs that account for formulas, dependencies, and package content.

Explore Features

The additions, tied to the work:

  • Targeted Workbook Inspection. Standard surfaces such as wb.sheetnames, bounded cell ranges, and wb.defined_names remain the starting point. wb.search() finds text or regex matches in values and formulas; ws.allowed_values(cell) reports validation-derived choices.
  • Reference-Aware Structural Edits. Supported row, column, sheet, and range operations update dependent formulas, names, print areas, table ranges, and chart references, or refuse. Row and column insertions and deletions return an AddressRemap; sheet renames and move_range() do not.
  • Preserve-Mode Object Editing. copy_format() copies formatting, chart.repoint() updates a value series and removes its stale cache, ws.append_table_row() expands a supported table atomically, and ws.replace_image() replaces one loaded image without rewriting the drawing. Category ranges and the intended business scope still need explicit attention.
  • Formula Cache Freshness. Formula edits and input changes that may feed formulas invalidate retained cached results and request recalculation on open. Style-only and unrelated value edits keep their caches. Until recalculation, a data-only reader may see None; Paper does not calculate formulas itself.
  • Error Inspection and Diffs. openpyxl.preserve.scan_errors() inspects formula and cached/value error representations without LibreOffice. diff_workbooks(..., remaps=()) separates content changes from cells shifted by structural edits.
  • Edit Receipts. wb.save(..., receipt=True) returns an EditReceipt naming changed cells and parts; wb.validate() runs save validation without writing. A receipt can include formula-cache invalidations as well as the cell the agent explicitly edited.
  • LibreOffice Recalculation and Certification. oracle.recalc() recalculates a temporary copy, scans for errors, and can write a separate Paper-preserved candidate through output_path. oracle.certify() reports whether LibreOffice reproduces cached values as CERTIFIED, DIVERGED, or BASELINE_UNVERIFIABLE. oracle.evaluate() and oracle.evaluate_many() apply temporary inputs and return requested outputs. These operations never overwrite the source, and preservation does not require LibreOffice.
  • Protection and Pivot Refresh. Writes to locked cells can warn; wb.strict_protection = True makes them refuse. wb.set_pivot_refresh_on_load() grants explicit consent for dependent edits and asks Excel to refresh the selected pivots on open. Their cached results remain stale until that refresh.

Path saves build the archive on disk, validate ZIP consistency, and fsync before rename. Callers, rather than fixed package-wide size or compression-ratio limits, control resource budgets.

The reported comparison covers 61 tasks: 27 DOCX, 15 PPTX, and 19 XLSX. It covers a wide range of existing-file workflows involving fragmented text, revisions, comment threads, numbering, fields, slide relationships, embedded workbooks, template lineage, formulas, names, charts, and dependent ranges, alongside two creation controls.

We evaluated five models: Opus 5, GLM 5.3 Flash, GPT 5.6 Sol, Grok 4.6, and DeepSeek v4.1 Flash. Each model-task pair is rolled out under each of three conditions:

ConditionPackageGuidance
No skillsUpstreamNone
Anthropic skillsUpstreamAnthropic's Office skills
Paper + skillsPaperPaper skills

All conditions ran through OpenCode in Harbor, with identical task prompts across conditions.

Both upstream conditions used the same pinned versions: python-docx==1.2.0, python-pptx==1.0.2, and openpyxl==3.1.5.

Task success by model