xlsx

Create, read, edit Excel .xlsx workbooks and CSVs.

  • excel
  • spreadsheet
  • xlsx
  • csv
  • openpyxl
  • productivity

Declared platforms: linux · macos · windows

Install
npx skills add 'https://github.com/NousResearch/hermes-agent/tree/main/skills/productivity/xlsx'
Download bundle ↓
main · 24fd22bScanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md
#!/usr/bin/env python3"""Recalculate a workbook's formulas headlessly with LibreOffice. openpyxl never computes formulas. This script shells out to `soffice`(LibreOffice) to open the workbook, recalculate, and re-save it, socached formula results become available to `xlsx_read.py --data-only`and `--formulas`. Behavior:  * soffice on PATH: converts the file to .xlsx in a temp dir (which    recalculates all formulas) and replaces the original (or writes    --out). Prints {"recalculated": true, ...} and exits 0.  * soffice absent: prints {"recalculated": false, "reason": ...} with    installation guidance and STILL exits 0 — callers can branch on the    JSON instead of the exit code. Note: LibreOffice recalculates .xlsx on load per its defaultcalculation settings; conversion re-saves with fresh cached values. Usage:  xlsx_recalc.py book.xlsx  xlsx_recalc.py book.xlsx --out recalced.xlsx  xlsx_recalc.py book.xlsx --timeout 120"""from __future__ import annotations import argparseimport jsonimport shutilimport subprocessimport sysimport tempfilefrom pathlib import Path  def count_cached(path):    """Number of formula cells with a cached value present."""    from openpyxl import load_workbook    wb_f = load_workbook(path, data_only=False)    wb_v = load_workbook(path, data_only=True)    formulas = cached = 0    for name in wb_f.sheetnames:        ws_f, ws_v = wb_f[name], wb_v[name]        for row in ws_f.iter_rows():            for cell in row:                if isinstance(cell.value, str) and cell.value.startswith("="):                    formulas += 1                    if ws_v[cell.coordinate].value is not None:                        cached += 1    return formulas, cached  def main(argv=None):    ap = argparse.ArgumentParser(        description="Recalculate .xlsx formulas headlessly via LibreOffice.")    ap.add_argument("file", help="path to .xlsx file")    ap.add_argument("--out", help="output path (default: replace input)")    ap.add_argument("--timeout", type=int, default=180,                    help="seconds to wait for soffice (default 180)")    args = ap.parse_args(argv)     src = Path(args.file).resolve()    if not src.exists():        print(json.dumps({"ok": False, "error": f"no such file: {src}"}),              file=sys.stderr)        return 1     soffice = shutil.which("soffice")    if not soffice:        print(json.dumps({            "ok": True, "recalculated": False,            "reason": "LibreOffice (soffice) not found on PATH",            "guidance": "Install LibreOffice (e.g. `apt install "                        "libreoffice-calc` or `brew install --cask "                        "libreoffice`), or open the file in Excel/"                        "LibreOffice once and re-save it.",        }, ensure_ascii=False))        return 0     with tempfile.TemporaryDirectory() as tmp:        proc = subprocess.run(            [soffice, "--headless", "--calc", "--convert-to", "xlsx:Calc "             "MS Excel 2007 XML", "--outdir", tmp, str(src)],            capture_output=True, text=True, encoding="utf-8",            timeout=args.timeout,            env={"HOME": tmp, "PATH": Path(soffice).parent.as_posix()                 + ":/usr/bin:/bin"})        produced = Path(tmp) / (src.stem + ".xlsx")        if proc.returncode != 0 or not produced.exists():            print(json.dumps({"ok": False,                              "error": "soffice conversion failed",                              "stderr": proc.stderr.strip()[-500:]}),                  file=sys.stderr)            return 1        formulas, cached = count_cached(produced)        dest = Path(args.out).resolve() if args.out else src        shutil.copyfile(produced, dest)     print(json.dumps({        "ok": True, "recalculated": True, "output": str(dest),        "formula_cells": formulas, "with_cached_values": cached,    }, ensure_ascii=False))    return 0  if __name__ == "__main__":    try:        sys.exit(main())    except Exception as exc:  # noqa: BLE001        print(json.dumps({"ok": False, "error": str(exc)}), file=sys.stderr)        sys.exit(1) 
Referenced from SKILL.md