xlsx-toolkit — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited xlsx-toolkit (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Single Rust binary with five subcommands, built on umya-spreadsheet (read+write) and clap. The skill directory is a cargo project — source in src/, binary at bin/xlsx-toolkit.
Invoke via the shim, which picks a prebuilt for the current platform or builds from source on first use:
~/.claude/skills/xlsx-toolkit/bin/xlsx-toolkit --helpThe skill ships a prebuilt only for aarch64-apple-darwin. On any other platform the shim runs cargo build --release once and caches the result in target/release/. Subsequent runs go straight to the cached binary — no cargo overhead.
Optional alias if you'll use this often:
alias xlsx-toolkit='~/.claude/skills/xlsx-toolkit/bin/xlsx-toolkit'macOS Gatekeeper: if the bundled binary arrived with a com.apple.quarantine xattr (downloaded .skill), the shim strips it automatically. If macOS still blocks it ("unidentified developer"), run xattr -dr com.apple.quarantine ~/.claude/skills/xlsx-toolkit/bin and retry.
The rest of this file assumes you can invoke the binary as xlsx-toolkit. If the alias isn't set, use the full path.
| Task | Subcommand |
|---|---|
| "What's in this xlsx?" / unknown workbook | inspect |
| Dump a sheet (or all sheets) to CSV/TSV | to-csv |
| Build a new xlsx from a JSON spec | write |
| Compare two workbooks | diff |
| Per-column fill % / data quality | coverage |
For anything else, read references/patterns.md — it covers formulas vs cached values, dates, merged cells, multi-row headers, hidden sheets, write-side details, and how to drop down to the umya-spreadsheet API when the subcommands don't fit.
xlsx-toolkit inspect <file> before doing anything else. It prints sheet names, dimensions, headers, formula count, merged ranges, and a sample. Without this, you'll guess wrong about what's in the workbook.to-csv --sheet NAME to stdout is the right move when feeding data to jq, grep, awk, csvkit, etc. Don't try to parse xlsx with shell.references/patterns.md.coverage to find columns that are mostly empty (often imported-but-unused fields) or to confirm a migration populated what it should. The HubSpot data-model coverage doc in this monorepo is exactly this shape.xlsx-toolkit inspect ./data.xlsx --sample 5
xlsx-toolkit inspect ./data.xlsx --json | jq '.details[].headers'
xlsx-toolkit inspect ./data.xlsx --sheet Contacts# One sheet → stdout (pipe to anything)
xlsx-toolkit to-csv ./data.xlsx --sheet Contacts | head
# All sheets → sibling .csv files next to the source
xlsx-toolkit to-csv ./data.xlsx
# TSV
xlsx-toolkit to-csv ./data.xlsx --sheet Contacts --delimiter $'\t'cat > /tmp/spec.json <<'EOF'
{
"sheets": [{
"name": "Report",
"headers": ["Item", "Qty", "Price", "Total"],
"rows": [
["apples", 3, 1.5, { "v": 0, "f": "B2*C2" }],
["bread", 2, 4.25, { "v": 0, "f": "B3*C3" }]
],
"freeze_header": true,
"autofilter": true,
"column_widths": [12, 6, 8, 10]
}]
}
EOF
xlsx-toolkit write --spec /tmp/spec.json --out report.xlsx
# Or pipe the spec on stdin:
cat /tmp/spec.json | xlsx-toolkit write --out report.xlsxCell values: plain JSON string | number | boolean | null for static data, or { "v": <value>, "f": "FORMULA", "t": "n|s|b" } for formulas / explicit types. Set the value AND the formula together — the cached v is what other tools see until Excel re-evaluates.
# Positional row diff (row N vs row N) across shared sheets
xlsx-toolkit diff before.xlsx after.xlsx
# Key-based: match rows by a header column value (stable across reorderings)
xlsx-toolkit diff before.xlsx after.xlsx --key "Property"
# Restrict to one sheet, JSON output
xlsx-toolkit diff before.xlsx after.xlsx --sheet Contacts --json# Per-column fill % on every sheet
xlsx-toolkit coverage ./data.xlsx
# Only columns with ≥50% fill
xlsx-toolkit coverage ./data.xlsx --threshold 0.5 --sheet Contacts--json (where supported) for machine output.write and to-csv (file-writes) go to stderr, so stdout stays clean for piping.anyhow errors with context on failure.umya-spreadsheet or calamine. Use the in-tree dep directly — don't shell out to global binaries for production logic.libreoffice --headless --convert-to xlsx file.xls) or read it elsewhere.write.calamine (much faster reader, read-only).~/.claude/skills/xlsx-toolkit/
├── SKILL.md
├── Cargo.toml
├── .gitignore ← /target/ and *.skill ignored
├── references/
│ └── patterns.md ← gotchas, advanced usage, umya API notes
├── src/
│ ├── main.rs ← clap entry point
│ └── commands/
│ ├── mod.rs
│ ├── common.rs ← shared read/walk helpers
│ ├── inspect.rs
│ ├── to_csv.rs
│ ├── write.rs
│ ├── diff.rs
│ └── coverage.rs
├── bin/
│ ├── xlsx-toolkit ← shell shim, dispatches to prebuilt or cargo build
│ └── aarch64-apple-darwin/
│ └── xlsx-toolkit ← shipped prebuilt (~4 MB)
└── target/release/xlsx-toolkit ← cargo-built fallback (gitignored)To add another platform: rustup target add <triple>, cargo build --release --target <triple>, then copy target/<triple>/release/xlsx-toolkit to bin/<triple>/xlsx-toolkit. The shim picks it up automatically. For Linux targets from a Mac, use cross (cross build --release --target x86_64-unknown-linux-gnu) to get the right glibc.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.