Skip to content

feat(office): anydoc for fast-mode office → markdown extraction [VLM-749] - #195

Draft
nwaughachukwuma wants to merge 4 commits into
mainfrom
claude/replace-libreoffice-anydoc-1cti6p
Draft

feat(office): anydoc for fast-mode office → markdown extraction [VLM-749]#195
nwaughachukwuma wants to merge 4 commits into
mainfrom
claude/replace-libreoffice-anydoc-1cti6p

Conversation

@nwaughachukwuma

@nwaughachukwuma nwaughachukwuma commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Resolves VLM-749. Adopts anydoc for office → markdown, keeping libreoffice where it is strongest.

Design

Path Backend Change
fast mode: office → markdown anydoc (firecrawl-anydoc Python binding) swapped in
accurate mode: office → PDF → page-text → LLM libreoffice-rs (office_to_pdf) unchanged
mm peek --full document metadata libreoffice-rs (office_metadata) unchanged

Per the benchmarks attached to the ticket, anydoc beats libreoffice on every shared format (overall score 81 vs 40, median 4.4 ms vs 1129.5 ms) — but it doesn't convert to PDF, so accurate mode keeps its libreoffice flow.

Changes

  • page_text.py / extract_meta.py: office extraction calls anydoc.to_markdown instead of mm._mm.office_content.
  • office.rs / mm-python / _mm.pyi: libreoffice surface stripped to the two entry points in use (office_to_pdf, office_metadata); dead content path (office_content / office_parse_full / OfficeDoc) removed. All five workspace deps remain — each is used by the surviving entry points, and all are transitive deps of libreoffice-pure regardless.
  • pyproject.toml / uv.lock: add firecrawl-anydoc>=0.1.8.
  • AGENTS.md / README drift fix: both claimed mode is a no-op for non-PDF documents; accurate mode runs office docs through the LLM pipeline. Backend-per-path corrected in docs/cat.md, SPEC.md, user guide, mm-skill.
  • Tests: two new tests assert the encoder and fast passthrough return anydoc markdown from a real in-test docx; existing accurate-mode office→PDF test untouched.

Validation

  • cargo test --workspace: 100 passed; clippy clean
  • pytest tests/python: 1191 passed, 46 skipped
  • Smoke: uncached mm cat notes.docx returns anydoc markdown; stripped module surface verified in the built extension

Follow-ups

  • OFFICE_EXTS could extend to doc/ppt/xls/rtf/epub/csv (anydoc reads them) — separate change, affects kind classification and accurate routing.
  • Folding mm encoders into the gateway — page-text is now a clean file → markdown Message boundary; separate design note.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LrXDqpPAFvk3mTdjcKtpnh

…749]

Swap the fast-mode office extraction backend from libreoffice-pure to
the anydoc Python binding (firecrawl-anydoc): docx/pptx/xlsx/odt/odp/ods
now convert to GitHub-Flavored Markdown instead of plain text. In
firecrawl's 100-document benchmark anydoc scores 81 vs libreoffice's 40
(median 4.4ms vs 1129.5ms) and wins every shared format head-to-head.

Each backend keeps the job it is strongest at: anydoc for file →
markdown (page-text encoder + extract_meta passthrough), libreoffice-rs
for accurate mode's office → PDF → page-text → LLM flow and for
peek --full document metadata — both unchanged, as is the entire Rust
surface.

Also fixes AGENTS.md drift: it claimed mode is a no-op for non-PDF
documents, but the design (and the code) runs office docs through the
LLM pipeline in accurate mode. README carried the same stale claim.

Two new tests cover the swap: page-text encoder output and the fast
passthrough path against a minimal in-test docx.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LrXDqpPAFvk3mTdjcKtpnh
@nwaughachukwuma
nwaughachukwuma force-pushed the claude/replace-libreoffice-anydoc-1cti6p branch from ddccc9c to a1e7737 Compare August 12, 2026 13:20
@nwaughachukwuma nwaughachukwuma changed the title feat(office): replace libreoffice-pure with anydoc [VLM-749] feat(office): anydoc for fast-mode office → markdown extraction [VLM-749] Aug 12, 2026
…rding

With anydoc handling office → markdown on the Python side, the
libreoffice-backed Rust surface shrinks to the two entry points the
codebase actually calls: office_to_pdf (accurate-mode cat) and
office_metadata (peek --full). The dead content path — office content(),
parse_full(), OfficeDoc, and their PyO3 bindings and type stubs — is
removed.

All five libreoffice workspace deps remain: each is still used by the
two surviving entry points (libreoffice-pure for conversion + format
sniffing, lo_core for the Metadata type, lo_writer/lo_calc/lo_impress
for the per-family parsers behind metadata()), and all are transitive
dependencies of libreoffice-pure regardless.

Also: say 'markdown' plainly instead of 'GitHub-Flavored Markdown'
across docs and docstrings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LrXDqpPAFvk3mTdjcKtpnh
@nwaughachukwuma
nwaughachukwuma marked this pull request as draft August 12, 2026 13:35
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LrXDqpPAFvk3mTdjcKtpnh
@nwaughachukwuma

Copy link
Copy Markdown
Collaborator Author

@claude, fix the rust version to fix the failing CI job

The test-python job's make lint-python step failed after the pyproject
change invalidated CI's uv cache: the unpinned 'ruff>=0.4' dev
dependency resolved to 0.16.2, whose newer rules flag 294 pre-existing
violations repo-wide. The rustc toolchain itself built fine (1.97.1).

Pin ruff to 0.11.6 — the same version .pre-commit-config.yaml pins and
the passing lint job uses — so bare ruff and pre-commit agree on one
ruleset. Verified locally: make lint-python passes on 0.11.6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LrXDqpPAFvk3mTdjcKtpnh

Copy link
Copy Markdown
Collaborator Author

Fixed in b2649ac — though the culprit turned out to be ruff, not rustc: the job's Rust build succeeded (rustc 1.97.1), and test-rust is green. The failing step was make lint-python. The pyproject change invalidated CI's uv cache, so the unpinned ruff>=0.4 dev dependency freshly resolved to 0.16.2, whose newer rules flag 294 pre-existing violations repo-wide.

Pinned ruff==0.11.6 — the same version .pre-commit-config.yaml pins (which is why the lint job passes) — so bare ruff and pre-commit agree on one ruleset. Verified make lint-python passes locally on 0.11.6.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants