Spreadsheet toolkit. Reach for it whenever the artifact on either side of the conversation is a workbook file — .xlsx, .xlsm, .xltx, .csv, .tsv — and the user wants that artifact produced, changed, cleaned, or read. Typical triggers: 'build me a model', 'update this sheet', 'add a column', 'compute the totals as formulas', 'sanity-check this xlsx', 'export sheet 2 to CSV', 'render the workbook as PDF', 'the spreadsheet in ~/Downloads is a mess, fix it'. Applies equally to financial models, ops reports, data cleanups, and template fills. Skip it when the workbook is only source material and the real output is a Word doc, an HTML page, a Python script that runs standalone, a Google Sheets integration, or an ingestion pipeline into a database — in those cases the spreadsheet is a means, not the deliverable.
76
96%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
An Apache-2.0 toolkit for producing, editing, and reading Microsoft Excel
(.xlsx) files. Written from scratch against the public
ECMA-376 / ISO/IEC 29500 (SpreadsheetML)
specification and built on permissively-licensed tooling
(openpyxl MIT, pandas BSD-3-Clause, lxml BSD-3-Clause,
optional xlsxwriter BSD-2-Clause, optional external binary soffice
MPL 2.0) so it can be reused in commercial projects without restriction.
| Situation | Path | Read first |
|---|---|---|
| Build a workbook from a prompt / dataframe / raw values | Author with openpyxl (formulas + formatting) or pandas (bulk data) | create.md |
Edit an existing .xlsx — add rows, patch cells, refresh formulas | Load with openpyxl, preserve formulas & styles | edit.md |
| Only need to read the data out (analysis, ETL, quick QA) | pandas.read_excel + openpyxl for structural inspection | read.md |
| Clean, aggregate, or transform tabular data before writing back | pandas pipeline, then hand back to openpyxl for final polish | analyze.md |
| Deep structural edits (custom XML parts, defined names, VBA-free surgery) | Unpack → edit XML → repack | edit.md → Raw XML workflow |
| Recompute formula values before shipping | scripts/bake.py via LibreOffice | see QA below |
If the task mixes several of these, do them in this order: read → plan → edit/create → recalc → validate.
Bundled runtime: when the
MIMO_PYTHONenvironment variable is set, skip the pip installs below — run every command withpython3/uv runreplaced by"$MIMO_PYTHON"(e.g."$MIMO_PYTHON" scripts/overview.py book.xlsx). openpyxl/pandas/lxml/xlsxwriter are preinstalled in that interpreter; pip console scripts are unavailable, so always go through"$MIMO_PYTHON" -m <module>. A bundled LibreOffice (forbake.py/pdf_out.py) is exposed asMIMO_SOFFICEand picked up automatically.
python3 -m pip install --upgrade openpyxl pandas lxml
# Optional but recommended:
python3 -m pip install --upgrade xlsxwriter
# For formula recalc and PDF export:
# macOS brew install --cask libreoffice
# Debian/Ubuntu apt-get install -y libreofficeEvery script under scripts/ uses only the standard library plus openpyxl
and pandas. No proprietary dependencies.
# 1. Describe a workbook (sheets, dimensions, formula count, sample rows)
python scripts/overview.py input.xlsx
# 2. Recalculate every formula, then flag any residual #REF! / #DIV/0! / etc.
python scripts/bake.py output.xlsx # default 30s LibreOffice timeout
python scripts/bake.py output.xlsx --timeout 60 # custom timeout
# 3. Validate ZIP integrity, XML well-formedness, and openpyxl load
python scripts/audit.py output.xlsx
# 4. Convert to CSV (one file per sheet, or a single sheet by name/index)
python scripts/csv_out.py input.xlsx out_dir/ # all sheets
python scripts/csv_out.py input.xlsx out.csv --sheet 0 # first sheet
# 5. Convert to PDF for visual QA (needs LibreOffice)
python scripts/pdf_out.py output.xlsx # writes output.pdf next to it
# 6. Unpack an .xlsx into readable XML parts (for surgical edits)
python scripts/explode.py input.xlsx unpacked/
# 7. Repack an unpacked directory into a fresh .xlsx
python scripts/assemble.py unpacked/ output.xlsxEvery script is a small, self-contained Python file. Read the top of the file for full CLI options.
Excel is a live calculation surface, not a static table renderer. Users open workbooks and expect to change numbers, watch the rest update, and trust what they see. Keep that in mind:
=SUM(...), not
with a Python sum() written into the cell. When source data changes, the
workbook must recompute itself.=B5*(1+$B$6)), never inline (=B5*1.05). This is the single biggest
determinant of whether a model is usable.Inputs!B5) make dependencies explicit.NamedStyle once and reapply.sheet.freeze_panes = "A2" (or "B2" if the first
column is a row label) — every scrolling table needs this.cell.number_format in a
loop over the data range of each column (for row in ws.iter_rows(min_col=3, max_col=3): ...).
Note: column_dimensions['C'].number_format does not reliably format
cells you write afterwards — openpyxl-written cells carry their own style."=SUM(...)" and a cached previous value (if the file was opened before).
Freshly written formulas have no cached value until LibreOffice or Excel
recomputes.| Kind | Format string | Renders |
|---|---|---|
| Plain integer with thousands | #,##0 | 1,234 |
| Currency (USD, hide zeros) | $#,##0;($#,##0);"-" | $1,234 / ($1,234) / - |
| Currency (2 dp) | $#,##0.00 | $1,234.56 |
| Percentage (1 dp) | 0.0% | 12.3% |
| Multiplier | 0.00"x" | 1.35x |
| Year as text | 0 | 2026 (no comma) |
| Short date | yyyy-mm-dd | 2026-07-04 |
| Long date | dddd, mmmm d, yyyy | Saturday, July 4, 2026 |
| Scientific | 0.00E+00 | 1.23E+04 |
Use parentheses for negatives in financial contexts; use a leading minus for scientific or engineering contexts.
There is no universal standard, but if the user does not specify one, this palette is safe for internal financial or operational models:
| Purpose | Value | Rationale |
|---|---|---|
| Header text | #1F1F1F on #F2F2F2 fill | High contrast, print-safe |
| Input (user changes) | Blue #0033CC | Visually distinct from formulas |
| Formula (calculated) | Black #1F1F1F | Default reading color |
| Same-workbook link | Green #116611 | "Comes from elsewhere in this file" |
| Cross-file link | Red #B22222 | "Fragile — points outside this file" |
| Assumption to review | #FFF2CC fill | Yellow highlight, still readable in b/w |
| Error / warning | #FFC7CE fill, #9C0006 text | Excel's built-in "bad" style |
Override these whenever the file has an existing template — match it exactly.
Assume something is wrong. Excel opens broken files quietly: a stray
#REF!, an off-by-one range, a formula that quietly evaluates to 0. Verify
explicitly.
Recalculate formulas. openpyxl does not evaluate them — LibreOffice does.
python scripts/bake.py output.xlsxRead the JSON output. status: "clean" with error_count: 0 is the
only acceptable result.
Structural validation.
python scripts/audit.py output.xlsxConfirms the ZIP is well-formed, all XML parts parse, and openpyxl can round-trip the file.
Spot-check the values. Load with data_only=True after recalculation
and read the cells you expect to be non-zero:
from openpyxl import load_workbook
wb = load_workbook('output.xlsx', data_only=True)
assert wb['Summary']['B10'].value == expected_totalVisual sanity. Render a PDF and scan the first and last sheets for:
######## (column too narrow for the format).=, or a leading apostrophe).python scripts/pdf_out.py output.xlsxIf any of these fail, fix and re-run. Do not paper over.
#DIV/0! — wrap divisions defensively: =IF(B2=0,0,A2/B2) or
=IFERROR(A2/B2, 0). Prefer IF so real zeros stay visible; use IFERROR
only for values that must always be numeric.#REF! — a cell reference points to a deleted row/column. Rebuild the
formula against current coordinates; do not just delete the offending cell.#VALUE! — text where a number is expected, usually from a stray label
in a data column. Check the column dtype in pandas before writing.#NAME? — the formula uses a function name Excel does not recognize.
Common causes: typos (=SUMM(...)), locale-specific separators (; vs
,), or dynamic-array functions like FILTER in older Excel versions.#N/A — usually from VLOOKUP / XLOOKUP / MATCH failing to find a
key. Wrap in IFNA(..., default) when a miss is expected.Sheet1!A1 works; Sheet 1!A1 needs
quoting: 'Sheet 1'!A1. openpyxl accepts either — Excel demands the quoting..xls (Excel 97-2003 binary). Convert to .xlsx first:
soffice --headless --convert-to xlsx old.xls..xlsm. This skill does not emit or execute macros.create.md — workbooks, sheets,
formulas, formatting, named styles, charts, images, freeze panes, print
setup.edit.md — patching cells, appending
rows, inserting columns, preserving formulas & styles, unpack/repack for
deep XML surgery, defined names, data validation.read.md — pandas reads, structural
inspection, formula extraction, conversion to CSV / TSV / PDF.analyze.md — pandas pipelines,
reshaping, groupby, joins, then handing back to openpyxl for the final
writeable artifact.scripts/ — CLI utilities used throughout.ff87d47
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.