Install
$ agentstack add skill-matrixfounder-universal-skills-xlsx ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
xlsx skill
Purpose: Give the agent a deterministic, script-first path for creating and sanity-checking .xlsx workbooks. The core operations (CSV → styled .xlsx, force formula recalculation, scan for formula errors, structural OOXML validation) are wrapped in small CLIs so the agent does not have to rewrite openpyxl boilerplate on every task and is never surprised by "formulas are stored but not calculated" (the single most common xlsx bug).
1. Red Flags (Anti-Rationalization)
STOP and READ THIS if you are thinking:
- "I'll just call
DataFrame.to_exceland ship it." → WRONG.to_excelwrites no styles, no frozen header, and no auto-filter. The result looks amateur. Usecsv2xlsx.py. - "I'll just call
pd.DataFrame.from_records(rows).to_excel(out)on my LLM JSON output." → WRONG. Sameto_excelstyling gap, plus pandas'infer_objectsheuristics silently promote mixed-type columns toobject/float64(anintcolumn with onenullbecomesfloat64). Usejson2xlsx.py— preserves native JSON types, ISO-date auto-coercion, csv2xlsx-style header. - "I wrote formulas with openpyxl, so the numbers are there." → WRONG.
openpyxlstores formulas as strings with no cached value. Every downstream consumer (pandas, charts, external apps) seesNone. Runxlsx_recalc.pybefore shipping. - "Validation says OK, the formulas must be fine." → WRONG.
xlsx_validate.pyscans for cached error values. If there are no cached values at all (fresh openpyxl output), the scan is meaningless. Use--fail-emptyor recalc first. - "Leading zeros in my phone-number column vanished; it's fine." → WRONG. It is almost never fine. Excel and pandas both coerce
"007"to7by default.csv2xlsx.pydetects leading-zero columns and keeps them as text; inline code should either passdtype=strto pandas or setcell.number_format = "@"in openpyxl. - "I'll just regex-replace
\|to extract markdown tables." → WRONG. GFM pipe parsing has 5+ edge cases (escaped pipes\|, optional trailing pipes, separator-row alignment markers:---:/---:/:---, column-count validation, blockquote skip, fenced-code-block skip) that regex hand-rolls always fail. Usemd_tables2xlsx.py. For HTML `blocks: same tool —lxml.htmlis locked withnonetwork=True, hugetree=False`.
2. Capabilities
- Convert a CSV / TSV to a styled
.xlsxwith bold header, freeze-first-row, auto-filter, auto column widths, and leading-zero preservation. - Convert an
.xlsxworkbook back to CSV (per-sheet / per-region) or JSON (flat / dict-of-arrays / nestedtables) (xlsx2csv.py,xlsx2json.py). Thin shims on top of thexlsx_read/foundation library (xlsx-10.A). Supports--sheet NAME|all,--include-hidden,--header-rows N|auto,--tables whole|listobjects|gap|auto,--merge-policy anchor-only|fill|blank,--include-hyperlinks(JSON: dict-form{"value", "href"}; CSV: markdown-link-as-text[text](url)),--include-formulas,--datetime-format ISO|excel-serial|raw. JSON shapes: single-sheet single-region flat array; multi-sheet dict-of-arrays; multi-sheet multi-region nested{Sheet: {tables: {Name: [...]}}}; single-sheet multi-region flat{Name: [...]}. CSV multi-region requires--output-dir→ subdirectory schema//.csv(sheet names with__are NOT split — L4 lock). Round-trip withjson2xlsx.py(xlsx-2) for Shape 1 / Shape 2 is byte-identical (live intests/test_json2xlsx.py::TestRoundTripXlsx8::test_live_roundtrip); Shape 3 / Shape 4 are lossy on xlsx-2 v1 consume (full restoration deferred to xlsx-2 v2--write-listobjects). Cross-cutting parity: cross-3 / cross-4 / cross-5 / cross-7 envelopes; path-traversal guard on--output-dir. Public helpersconvert_xlsx_to_csv(input, output=None, **kwargs)andconvert_xlsx_to_json(input, output=None, **kwargs)inxlsx2csv2json/__init__.py. - Convert a JSON / JSONL document (file or stdin
-) to a styled.xlsxwith the SAME visual contract as csv2xlsx (json2xlsx.py). Three input shapes auto-detected: array-of-objects (single sheet), dict-of-arrays-of-objects (multi-sheet), JSONL (one JSON object per line —.jsonlextension). Preserves native JSON types (int / float / bool / null / str); ISO-8601 date strings auto-coerced to Excel datetime cells;--strict-datesmakes timezone-aware datetimes a hard fail. Cross-cutting parity: cross-5--json-errorsenvelope, cross-7 H1 same-path guard (exit 6SelfOverwriteRefused), stdin pipe-. Round-trip contract withxlsx2json.py(xlsx-8) is frozen at [skills/xlsx/references/json-shapes.md](references/json-shapes.md) and is LIVE as of xlsx-8 merge. - Convert an
.xlsxworkbook back to Markdown (GFM pipe tables, HTML `blocks, or per-table hybrid auto-select) (xlsx2md.py). Thin shim on top of thexlsxread/foundation (xlsx-10.A) — symmetric pair tomdtables2xlsx.pyclosing thexlsx → md → edits → xlsxround-trip. Supports--sheet NAME|all,--include-hidden,--format gfm|html|hybrid(defaulthybrid),--header-rows N|auto|smart,--memory-mode auto|streaming|full,--hyperlink-scheme-allowlist http,https,mailto(Sec-MED-2 default-enabled),--no-table-autodetect,--no-split,--gap-rows N --gap-cols N,--gfm-merge-policy fail|duplicate|blank,--datetime-format ISO|excel-serial|raw,--include-formulas(HTML only — M7 lock: GFM + formulas → exit 2). Hybrid promotion rules (per-table, first match wins): body merges → HTML; multi-row header → HTML;--include-formulas+ formula cell → HTML;headerRowCount=0(synthetic headers) → HTML (D13). Otherwise GFM. Multi-rowreconstruction from xlsx_read's flat›-joined headers (D-A11). Hyperlinks via Path C′ (parallel pass through openpyxl) preserve display text — emit as[text](url)GFM ortextHTML; blocked schemes emit text-only + warning. Round-trip contract frozen at [references/xlsx-md-shapes.md](references/xlsx-md-shapes.md); LIVE round-trip viaTestRoundTripXlsx9::testliveroundtripxlsxmd(cell-content byte-identical for non-merged plain tables; sheet-name asymmetryHistory → Historyis xlsx-3's documented sanitisation, NOT a regression). Cross-cutting parity: cross-3/4/5/7 envelopes; terminalInternalErrorredaction (R23f). Public helperconvertxlsxtomd(input, output=None, **kwargs)inxlsx2md/__init__.py`. - Extract markdown tables from a
.mddocument (file or stdin-) into a styled multi-sheet.xlsx(md_tables2xlsx.py). Two table flavors auto-detected: GFM pipe tables (with per-column alignment carried to Excel cell alignment) and HTML `blocks (withcolspan/rowspanhonoured as Excel merged cells). Sheet names derive from the nearest preceding markdown or HTML heading; fallbackTable-N; UTF-16-aware truncate to Excel's 31-char limit; case-insensitive workbook-wide dedup via-2..-99suffix. Default-on numeric + ISO-date coercion (csv2xlsx + json2xlsx parity; leading-zero preservation; aware datetimes → UTC-naive). Cross-cutting parity:--json-errorscross-5 envelope, cross-7 H1 same-path guard (exit 6), stdin pipe-. Pre-scan strips fenced code blocks, HTML comments, indented code blocks,/blocks, and blockquoted tables — so tables inside those regions never reach the parser. HTML parser islxml.html.HTMLParser(nonetwork=True, hugetree=False, recover=True)singleton (defense-in-depth against XXE + libxml2 huge-tree expansion). Public helperconvertmdtablestoxlsx(inputpath, outputpath, **kwargs) -> intlives inmdtables2xlsx/_init__.py(mirrors xlsx-2convertjsonto_xlsx`; VDD-multi atomic-token protection inherited). - Force formula recalculation in an
.xlsxvia headless LibreOffice, then optionally scan for error cells. - Scan an
.xlsxfor formula errors (#REF!,#DIV/0!,#VALUE!,#NAME?,#N/A,#NUM!,#NULL!) without recomputing. - Add a bar / line / pie chart on a value range with optional categories, title, anchor; stays editable in Excel / LibreOffice.
- Insert an Excel comment (legacy `
, optionally with the threaded-comment + personList Excel-365 modern layer) into a target cell, with cross-sheet--cellsyntax and a batch mode that auto-detects the xlsx-7 findings envelope. Closes the "validation-агент расставляет замечания" pipeline together withxlsxcheckrules.py` (xlsx-7). - Declarative business-rule validation —
xlsx_check_rules.pyreads a YAML/JSON rules file alongside an.xlsxand emits a machine-readable findings envelope ({ok, summary, findings}) on stdout; pipes directly intoxlsx_add_comment.py --batch -for cell-comment placement. Optional--outputwrites a workbook copy with aRemarkscolumn + per-severity PatternFill. Hardened DSL (closed AST, noeval/exec), ReDoS-lint reject-list, billion-laughs YAML alias rejection, and a 100K-row × 10-rule perf contract (≤ 30 s wall-clock). - Unpack and repack
.xlsxarchives for raw OOXML editing (sharedoffice/module with the docx skill). - Structurally validate an
.xlsx(relationships, content types, required parts, package-layout allow-list — every ZIP entry must live under[Content_Types].xml,_rels/,xl/,docProps/, orcustomXml/per ECMA-376 §11.3.10; catches scratch-file leaks that Excel refuses to open. With--strict, the package-layout warning is promoted to exit 1). - Reject password-protected and legacy
.xls(CFB-container) inputs early in the reader scripts (xlsx_recalc.py,xlsx_validate.py,xlsx_add_chart.py,office/validate.py,office/unpack.py,preview.py) with a clear remediation message (exit 3) instead of aBadZipFiletraceback.csv2xlsx.pyandoffice_passwd.pyare not gated — the former takes CSV/TSV input (no encryption to detect), the latter is the encryption tool itself. - Detect macro-enabled inputs (
.xlsm, withxl/vbaProject.bin) and warn when the chosen output extension would silently drop the macros (xlsm→xlsx). - Render any
.xlsx/.xlsm/.pdf(or peer-skill.docx/.pptx) into a single PNG-grid preview viapreview.py(LibreOffice + Poppler). - Emit failures as machine-readable JSON to stderr with
--json-errors(uniform across all four office skills). - Set or remove a password on a
.xlsx/.docx/.pptx(MS-OFB Agile, Office 2010+) viaoffice_passwd.py— three modes:--encrypt PASSWORD,--decrypt PASSWORD,--check(exit 0 encrypted / 10 clean / 11 missing).
3. Execution Mode
- Mode:
script-first. - Why this mode: Spreadsheet tasks have well-defined inputs and outputs and benefit heavily from deterministic CLIs. Writing the styling code inline produces ugly workbooks every time; delegating to scripts frees the agent to focus on the user's intent.
4. Script Contract
- Commands:
python3 scripts/csv2xlsx.py INPUT.csv OUTPUT.xlsx [--delimiter auto|,|;|\t] [--encoding utf-8] [--no-freeze] [--no-filter]python3 scripts/xlsx2csv.py INPUT.xlsx [OUTPUT.csv|-] [--output-dir DIR] [--sheet NAME|all] [--include-hidden] [--header-rows N|auto] [--merge-policy anchor-only|fill|blank] [--tables whole|listobjects|gap|auto] [--gap-rows N] [--gap-cols N] [--include-hyperlinks] [--include-formulas] [--datetime-format ISO|excel-serial|raw] [--memory-mode auto|streaming|full] [--encoding utf-8|utf-8-sig] [--delimiter ,|;|tab|\\t|pipe] [--drop-empty-rows] [--json-errors]— convert .xlsx → CSV. Multi-region requires--output-dir. Output-or omitted → stdout.--drop-empty-rowsfilters out rows where every value isNone/""(default off; same semantics as the JSON path). For full Excel-RU/EU double-click compatibility pass BOTH--encoding utf-8-sigAND--delimiter ';': the BOM lets Excel detect UTF-8 encoding, and;is the field separator on RU/EU locales (where,is the decimal separator). Defaults (utf-8+,) stay pandas-/jq-friendly. Stdout always plain UTF-8 regardless of flags. Thetabalias (or 2-char\\tescape) maps to a real tab;pipemaps to|. Python-helper equivalent:convert_xlsx_to_csv(input, output, delimiter=';', encoding='utf-8-sig')(kwarg names map to CLI flags 1:1).python3 scripts/xlsx2json.py INPUT.xlsx [OUTPUT.json|-] [--sheet NAME|all] [--include-hidden] [--header-rows N|auto|leaf|smart] [--header-flatten-style string|array] [--merge-policy anchor-only|fill|blank] [--tables whole|listobjects|gap|auto] [--gap-rows N] [--gap-cols N] [--include-hyperlinks] [--include-formulas] [--datetime-format ISO|excel-serial|raw] [--memory-mode auto|streaming|full] [--drop-empty-rows] [--json-errors]— convert .xlsx → JSON. Output-or omitted → stdout.--drop-empty-rowsfilters rows where every value isNone/"".--header-rows leafauto-detects the header band but keeps ONLY the deepest non-empty level per column as the JSON key — solves the layout-heavy-report key bloat where rows 1..K-1 are merged metadata banners (title / customer / contract / project / period) and the real column names sit on row K. Example recipe:xlsx2json.py FILE.xlsx out.json --sheet all --tables auto --header-rows leaf --drop-empty-rows→ keys become["Date", "Hours", "Days", "Specialist", "Position", "Task #", "Description"]instead of 7-level›-concatenated metadata-prefixed strings.--header-rows smart(xlsx-8a-09 / R11; iter-3 2026-05-13) is the "find-the-data-table" recipe — locates the real header row whether or not merges are present. Uses a type-pattern heuristic: scores each top row by string-ratio + column-coverage + downstream type-stability + depth (max 5.0); when a candidate scores ≥ 3.5 ANDlen(sample_below) ≥ 2, the library shifts the region past the metadata and treats the candidate row as a 1-row header.smartdoes NOT defer to merge-based detection — it competes purely on score. On merged-banner fixtures (e.g.A1:C1"2026 plan" overQ1/Q2/Q3),smartshifts to the sub-header row and produces leaf-like keys["Q1", "Q2", "Q3"]. Callers needing the multi-level concatenated form ("2026 plan › Q1") must use--header-rows auto(orleafto take the deepest level only) —smartis non-overlapping withauto/leafat the OUTPUT shape level. Usesmartwhenautoproduces{"": ..., "От": ..., "До": ..., "__2": ..., ..., "__N": ...}-style keys on a workbook whose real headers are buried below a config section (typical: financial-modeling sheets withОт/Доparameter ranges on rows 1-K + a real data table starting at row K+1; or per-row banner + per-row metadata header rows above the column-name row, e.g. masterdata Timesheet pattern).--memory-mode {auto,streaming,full}(xlsx-8a-11 / R13) exposes the read-mode selection:auto(default) lets the library pick based on file size (_DEFAULT_READ_ONLY_THRESHOLD = 100 MiB);streamingminimises RAM — measured 7.6× RAM reduction PLUS 2.6× wall-clock speedup on 15 MB multi-sheet workbooks (1188 MB / 32 s → 156 MB / 13 s, live subprocess measurement 2026-05-13) at the cost of merge-aware features (overlap detection, multi-row header band via merges, merge-policy fill) becoming no-ops — use on workbooks without merges OR where merge fidelity does not matter;fullforces non-streaming so all merge features work but RAM scales ~10× with file size.--include-hyperlinksis incompatible withstreaming(hyperlink extraction needs the non-streaming cell object); the combination emits a stderr warning and auto-overrides tofull. Practical recipe for large multi-sheet workbooks without critical merges:xlsx2json.py BIG.xlsx out.json --sheet all --tables whole --header-rows smart --memory-mode streaming --drop-empty-rows.python3 scripts/md_tables2xlsx.py INPUT.md OUTPUT.xlsx [--no-coerce] [--no-freeze] [--no-filter] [--allow-empty] [--sheet-prefix STR] [--encoding utf-8] [--json-errors]— markdown tables → multi-sheet xlsx.INPUTis a path or-for stdin.- `python3 scripts/xlsx2md.py INPUT.xlsx [OUTPUT.md|-] [--sheet NAME|
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: MatrixFounder
- Source: MatrixFounder/Universal-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.