This page covers the technical internals of the XLSX skill: its sole Python utility (recalc.py), how it configures LibreOffice to recalculate formulas, how it handles platform differences, and the structure of the JSON report it produces. For an overview of how the four document skills share a common architecture, see Document Skills. For the SKILL.md format itself, see SKILL.md Format Specification.
The XLSX skill enables Claude to work with Excel spreadsheets. Its primary programmatic capability—exposed via scripts/recalc.py—is formula recalculation: opening a .xlsx file in headless LibreOffice, triggering a full recalculation of all formulas, saving the result, and then scanning the output for Excel error values (#VALUE!, #DIV/0!, etc.).
This is useful when a spreadsheet's cached formula results are stale or missing (e.g., the file was created programmatically without ever being opened in a spreadsheet application).
recalc.pyFile: skills/xlsx/scripts/recalc.py
The script exposes a single public function, recalc(filename, timeout=30), callable from Claude during skill execution. A main() entry point also allows direct CLI invocation.
Diagram: recalc.py Execution Flow
Sources: skills/xlsx/scripts/recalc.py70-161
Function: setup_libreoffice_macro()
skills/xlsx/scripts/recalc.py42-67
Before invoking LibreOffice to recalculate, the script must install a StarBasic macro into the LibreOffice user profile. The macro directory is platform-specific:
| Platform | Macro Directory |
|---|---|
| macOS | ~/Library/Application Support/LibreOffice/4/user/basic/Standard/ |
| Linux | ~/.config/libreoffice/4/user/basic/Standard/ |
The macro file is always named Module1.xba (MACRO_FILENAME).
Idempotency check: If Module1.xba already exists and contains the string RecalculateAndSave, the function returns True immediately without rewriting the file. skills/xlsx/scripts/recalc.py48-51
Directory creation: If the macro directory does not exist, the script runs LibreOffice with --headless --terminate_after_init to initialize the user profile, then calls os.makedirs to ensure the directory is present. skills/xlsx/scripts/recalc.py54-61
The macro written to Module1.xba is the RECALCULATE_MACRO constant, a StarBasic XML module containing a single subroutine:
Sub RecalculateAndSave()
ThisComponent.calculateAll()
ThisComponent.store()
ThisComponent.close(True)
End Sub
skills/xlsx/scripts/recalc.py21-29
After the macro is in place, recalc() builds and runs the soffice command:
skills/xlsx/scripts/recalc.py79-92
soffice --headless --norestore \
"vnd.sun.star.script:Standard.Module1.RecalculateAndSave?language=Basic&location=application" \
<abs_path_to_xlsx>
The vnd.sun.star.script: URI tells LibreOffice to execute the named macro from the application-level Basic library (location=application), which is where Module1.xba was installed.
The environment for the subprocess is provided by get_soffice_env(), imported from office.soffice. This function returns an environment dictionary that configures an isolated LibreOffice user profile (see Document Skills for the shared pattern).
LibreOffice can hang on malformed or locked files. The script wraps the soffice call with an OS-level timeout:
Diagram: Timeout Command Selection
Sources: skills/xlsx/scripts/recalc.py87-91
timeout utility (GNU coreutils), always available.gtimeout from GNU coreutils if installed (detectable via has_gtimeout()). If not installed, no timeout wrapper is applied.has_gtimeout() runs gtimeout --version with a 1-second timeout and returns True if it exits normally. skills/xlsx/scripts/recalc.py32-39
Exit code 124 is the standard signal for timeout expiration from both timeout and gtimeout. The script treats exit code 124 as non-fatal — the recalculation may have partially succeeded — and continues to inspect the file. skills/xlsx/scripts/recalc.py94
After LibreOffice returns, recalc() uses openpyxl to read the recalculated values and scan for Excel error strings. Two load_workbook passes are made:
Pass 1 — Error scan (data_only=True): Reads computed cell values. Iterates every cell in every sheet, checking whether the value string contains any of the seven Excel error codes:
skills/xlsx/scripts/recalc.py100-125
| Error Code | Meaning |
|---|---|
#VALUE! | Wrong argument type or operand |
#DIV/0! | Division by zero |
#REF! | Invalid cell reference |
#NAME? | Unrecognized formula name |
#NULL! | Incorrect range operator |
#NUM! | Invalid numeric value |
#N/A | Value not available |
For each error found, the cell location is recorded as "SheetName!CellCoordinate" (e.g., "Summary!B12"). Up to 20 locations are captured per error type. skills/xlsx/scripts/recalc.py139
Pass 2 — Formula count (data_only=False): Reads raw formula strings. Counts all cells whose value starts with =. skills/xlsx/scripts/recalc.py142-154
recalc() returns a Python dict (serialized to JSON by main()):
Diagram: Output JSON Structure
Sources: skills/xlsx/scripts/recalc.py129-158
Example output (no errors):
Example output (errors found):
main() wraps recalc() for direct invocation:
skills/xlsx/scripts/recalc.py164-184
python recalc.py <excel_file> [timeout_seconds]
<excel_file>: Path to the .xlsx file.[timeout_seconds]: Optional integer timeout (default: 30).Output is the JSON result printed to stdout.
| Symbol | Location | Role |
|---|---|---|
recalc(filename, timeout) | recalc.py:70 | Main entry point; orchestrates macro setup, LibreOffice run, and error scan |
setup_libreoffice_macro() | recalc.py:42 | Writes Module1.xba to the platform-specific LibreOffice macro directory |
has_gtimeout() | recalc.py:32 | Detects availability of gtimeout on macOS |
RECALCULATE_MACRO | recalc.py:21 | StarBasic XML string for the RecalculateAndSave subroutine |
MACRO_DIR_MACOS | recalc.py:17 | macOS LibreOffice Basic Standard directory path |
MACRO_DIR_LINUX | recalc.py:18 | Linux LibreOffice Basic Standard directory path |
MACRO_FILENAME | recalc.py:19 | Always "Module1.xba" |
get_soffice_env() | office/soffice.py | Returns env dict with isolated LibreOffice user profile |
load_workbook(..., data_only=True) | recalc.py:101 | openpyxl: read computed values post-recalc |
load_workbook(..., data_only=False) | recalc.py:142 | openpyxl: read raw formula strings for count |
excel_errors | recalc.py:103 | List of seven Excel error strings to scan for |
Sources: skills/xlsx/scripts/recalc.py1-184
Refresh this wiki
This wiki was recently refreshed. Please wait 5 days to refresh again.