GitHub Docs

VibeCody uses your installed LibreOffice as a document engine: it opens Visio diagrams and legacy Office files, and renders documents to PDF, PNG or SVG. It is optional and needs no setup. If LibreOffice is not installed, nothing breaks — those files show a message saying what to do.

What it is for, and what it is not

Use Through LibreOffice
View a Visio diagram (.vsd, .vsdx, .vsdm, stencils and templates) ✅ read-only, via libvisio
View legacy .doc, .xls, .ppt and ODF (.odt, .ods, .odp, .odg) ✅ read-only
Export any of those to PDF, PNG, SVG, DOCX, XLSX, PPTX, ODF, HTML, TXT, CSV ✅ a copy is saved; the original is untouched
Edit a file ❌ not here
Write a Visio file ❌ LibreOffice reads Visio but cannot save it

It is a converter, not an editor. A LibreOffice round trip regenerates the document, which drops formatting it does not model. In a controlled test, converting a styled DOCX through a regenerating engine lost the text colours, table shading and image; the surgical writers in vibe-docfmt, vibe-sheetfmt and vibe-slidefmt kept them. So DOCX, XLSX, PPTX, Pages, Numbers and Keynote keep their existing in-process viewers and “Edit as Markdown” paths — LibreOffice is used for what those do not cover.

Zero-config

Nothing to set. LibreOffice is found, in order, at:

  1. Your override (Settings → Office), if you set one — and only that. A path that does not work is reported, never silently replaced by a different LibreOffice.
  2. soffice or libreoffice on PATH.
  3. Standard install locations — /Applications/LibreOffice.app (macOS), %ProgramFiles%\LibreOffice (Windows), /usr/bin/soffice, /opt/libreoffice*, /snap/bin/libreoffice (Linux). A Finder- or Start-menu-launched app has a minimal PATH, so these are probed directly.

The result is visible in three places:

Where What you see
Daemon startup banner office: LibreOffice ready — LibreOffice 26.8… (/Applications/…/soffice) or office: LibreOffice not found — …
GET /health → features.soffice state: checking · ready · missing · configured_invalid · broken, plus version, path, source
Settings → Office The same verdict, a path override field, Re-check and Auto-detect

checking means the first probe has not finished (a cold LibreOffice takes seconds to report its version); it is never reported as missing.

Setting a path

Only needed if LibreOffice is somewhere unusual. Settings → Office → Path to soffice, or:

curl -X PUT http://localhost:7878/office/soffice/path \
  -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"path": "/opt/lo/program/soffice"}'

The value is stored in the encrypted ProfileStore (~/.vibecli/profile_settings.db, key office.soffice_path) — not in config.toml, not in an environment variable. The daemon and the desktop app read the same key. A path that cannot start LibreOffice is refused (422) and the previous setting is kept, so Settings never holds a value that silently turns the feature off. Send {"path": null} to go back to auto-detection.

How conversion behaves

  • A private profile. Conversions run with -env:UserInstallation pointing at ~/.vibecli/office/profile-<host>, never your own LibreOffice profile. Sharing yours makes a headless run hand off to a LibreOffice window you have open and exit having done nothing.
  • One at a time per host. LibreOffice allows one instance per profile, so conversions in a process are queued. The daemon and the desktop app each have their own profile.
  • The exit code is not trusted. LibreOffice exits 0 having written nothing. A conversion succeeds only if a non-empty file of the right kind (checked by its magic bytes) exists.
  • Inputs are checked first. A file whose bytes do not match its extension — a broken.docx that is not a ZIP — is refused (422) before LibreOffice runs, because LibreOffice would import it as plain text and hand back a valid-looking PDF of garbage. Legacy binary formats are not policed this way: an .xls that is really HTML or CSV is legitimate.
  • Cached. Results are keyed on the file’s path, modification time and size, the target, and the LibreOffice version, under ~/.vibecli/office/cache (newest 100 kept). An unchanged file does not start LibreOffice again; the response says "cached": true.
  • Bounded. Inputs over 200 MB are refused; a conversion that exceeds its time limit (120 s by default) is stopped along with its child processes, so a hung run does not hold the profile lock for every later one.
  • PNG and SVG are the first page or slide only. Use PDF for anything multi-page.
  • Spreadsheets have their own PDF target, pdf_sheets: one page per sheet, sized to the sheet. The ordinary PDF paginates a sheet and clips its columns (a 40-column CSV came out as 13 pages; with pdf_sheets it is 1). It is refused (422) for anything that is not a spreadsheet. It is capped by the PDF page size (about 14,400 pt, ~1,100 rows): beyond that LibreOffice does not split the sheet, it shrinks the whole sheet to fit — 20,000 rows came out 23 pt wide and unreadable. The app therefore offers the accurate spreadsheet view only while every sheet has at most 1,000 rows and 200 columns.

macOS: Gatekeeper and LibreOffice’s signature

Some people have to approve LibreOffice in System Settings → Privacy & Security before it will run. There are two separate causes, and VibeCody addresses only one of them.

  • LibreOffice changes its own app. Its embedded Python writes bytecode (.pyc) files inside LibreOffice.app, including files the code signature covers. macOS then reports a sealed resource is missing or invalid (codesign --verify --deep --strict /Applications/LibreOffice.app shows file modified: …/__pycache__/….pyc), Gatekeeper rejects the app, and you are asked to allow it. This is LibreOffice’s behaviour, not VibeCody’s: on one machine the first such file was written five minutes after LibreOffice was installed. Opening LibreOffice yourself does the same thing, and VibeCody cannot prevent that.
  • VibeCody must not add to it. A headless conversion with a fresh profile was measured writing 31 .pyc files into the app bundle (0 with the setting below). VibeCody now runs every LibreOffice process with PYTHONPYCACHEPREFIX pointing into its own private profile (~/.vibecli/office/profile-<host>/pycache), so its conversions leave the signed app untouched. A one-time cost: Python compiles its own bytecode on the first run instead of using the files shipped in the app. A test checks the bundle’s .pyc files are unchanged after a conversion.

What VibeCody does not do: it never clears the quarantine flag (com.apple.quarantine), approves the app, or changes any Gatekeeper setting for you. Whether to trust that app is your decision.

What you see when macOS blocks it: if LibreOffice fails to start (or does not answer, which is how a Gatekeeper prompt waiting on you looks) and spctl --assess says the app is rejected, Settings → Office, the startup banner and the viewer say so, with the setting to open: Privacy & Security → the message about LibreOffice → Open Anyway, then Re-check.

Repairing an install that is already unsealed: VibeCody does not modify /Applications/LibreOffice.app. Its new behaviour does not repair an existing broken signature; reinstalling LibreOffice from libreoffice.org gives a sealed copy, which stays sealed as long as only VibeCody runs it.

HTTP

All routes require the bearer token (daemonFetch in the panels).

Route Purpose
GET /office/soffice Fresh status — same body as /health.features.soffice, plus import_extensions
PUT /office/soffice/path Set or clear the override ({"path": "…"} / {"path": null})
POST /office/convert {"path": "…", "to": "pdf" \| "pdf_sheets" \| "png" \| …, "timeout_secs": 120} → {output, target, bytes, cached, engine_version, elapsed_ms}

POST /office/convert refuses credential-store paths (403) and reads only the file named; the result lands in the daemon’s cache and output is its local path (a remote client cannot fetch the bytes through this route yet).

Status Meaning
503 LibreOffice not available — the body carries soffice with the state and remedy
404 Input file not found
422 Unsupported extension, or the bytes are not that format
413 Input over 200 MB
502 LibreOffice ran but produced nothing usable, or exited non-zero
504 Timed out and was stopped

In the app

Opening a Visio, .doc, .xls, .ppt or ODF file in VibeCoder renders it through LibreOffice and shows it in the PDF viewer, labelled Rendered by LibreOffice · Read-only. Files that have their own editable viewer get the same rendering as an option:

File Accurate view Default?
.pptx Accurate view / Edit shapes in the deck toolbar Yes — the shape view does not draw layout graphics or photos
.docx Accurate beside Word view / Text view; also offered from the notice when the file has legacy VML shapes the Word view cannot draw No
.xlsx, .xlsm, .csv Accurate view in the grid toolbar (one page per sheet; see pdf_sheets above) No — the grid is editable. Disabled for a sheet over 1,000 rows or 200 columns, and while there are unsaved edits (it renders the file on disk)

Export as… converts to another format and saves a copy through a save dialog. Failures are specific: not installed points at Settings → Office, not a valid .vsdx says the file is the problem, timed out says LibreOffice was stopped.

Known limits

  • Rendering fidelity is LibreOffice’s, not Microsoft’s. Complex Visio diagrams (custom masters, layers, some connectors) may differ from what Visio shows. A hand-built minimal .vsdx renders correctly; real-world diagrams have not been compared shape-for-shape.
  • Apple formats (.pages, .numbers, .key) are attempted only if your LibreOffice build includes libetonyek; the native viewers remain the primary path for them.
  • Only VibeCoder has the viewer; VibeDesk and VibeAIChat show the Settings section and can call the routes.