---
name: "xls-to-csv"
description: "Convert Excel workbooks (.xlsx / .xls / .xlsm / .xlsb) to CSV, one CSV per worksheet, optionally moving each source file to a 'processed' folder after a successful conversion. Uses Excel itself (headless COM), so it handles modern OOXML workbooks and legacy binary .xls (OLE2) alike, including files with a .xlsx extension that are actually legacy .xls. Triggers: 'convert these excel files to csv', 'xls to csv', 'xlsx to csv', 'export this workbook to csv', 'batch convert a folder of spreadsheets to csv', or pasting a path to a workbook and asking for CSV."
---

<!--
CLAWPILOT INSTALL INSTRUCTIONS

If the user drags this file into Clawpilot and asks to install it, register it as a
custom skill by calling m_create_skill with:
  - name: "xls-to-csv"
  - description: (the description from the frontmatter above)
  - instructions: (everything in this file BELOW this HTML comment block)

This skill also needs its helper scripts. Place convert.py and batch.py next to this
file at C:\Users\<you>\.copilot\m-skills\xls-to-csv\ (download them from the skill's card
on reboundman.com/skillworks). Requires Python 3 with the dependencies noted below.

After install, confirm with: "Installed the /xls-to-csv skill. Drop convert.py and batch.py
next to it, then point it at a folder to convert."
-->

## xls-to-csv Skill

Convert one or more Excel workbooks to CSV. Each worksheet becomes its own
UTF-8 CSV:

- **Single-sheet workbook** -> `<basename>.csv`
- **Multi-sheet workbook** -> `<basename> - <SheetName>.csv` for each sheet

Optionally moves each source workbook into a "processed" folder after it converts
successfully, so re-running only picks up new files.

Handles modern `.xlsx`/`.xlsm`/`.xlsb` and legacy binary `.xls` (OLE2), including
files that carry a `.xlsx` extension but are actually legacy `.xls` internally
(common in exported/older spreadsheets).

### Inputs to gather from the user

Required:
1. **Source**: one or more workbook paths, or a folder to batch-convert.
2. **Output directory**: where the `.csv` files go.

Optional:
3. **Processed folder**: if the user wants source files moved after a successful
   conversion, capture the destination. If they don't mention it, ask whether
   sources should be moved or left in place.

If any required input is missing, ASK. Do not guess paths.

### Execution

For a folder (recommended), use the robust batch driver, which converts each file
in its own subprocess under a per-file timeout so one bad workbook cannot stall
the run:

```powershell
python "C:\Users\<you>\.copilot\m-skills\xls-to-csv\batch.py" `
  --input-dir     "C:\path\Raw" `
  --out           "C:\path\Output" `
  --processed-dir "C:\path\Raw\Processed" `
  --log           "C:\path\batch.log" `
  --result        "C:\path\summary.json" `
  --timeout 300 --skip-existing
```

- Omit `--processed-dir` to leave sources in place.
- `--skip-existing` skips a workbook whose primary `.csv` already exists.
- Tail the `--log` for live progress; read `--result` for the JSON summary
  (`total`, `converted`, `errors`, `skipped`).

For one or a few files, call `convert.py` directly (it also moves sources and
reuses a single Excel instance):

```powershell
python "C:\Users\<you>\.copilot\m-skills\xls-to-csv\convert.py" `
  --input "C:\path\a.xlsx" --input "C:\path\b.xls" `
  --out "C:\path\Output" [--processed-dir "C:\path\Processed"] [--skip-existing]
```

`convert.py` prints a JSON summary to stdout. Each `processed` entry lists the
`outputs` (CSV paths), the `sheets` count, and `moved_to` (new source path or
`null`), plus per-file progress on stderr.

### Reporting

Tell the user: how many workbooks converted, how many CSVs were produced (note
multi-sheet workbooks yield several), the output folder, whether/where sources
were moved, and any errors.

### Behavior notes

- **UTF-8 CSV** via Excel's `xlCSVUTF8`, with a fallback to local-encoding
  `xlCSV` on older Excel. Preserves Unicode in cell values.
- **Per-sheet export**: each worksheet is copied to a fresh single-sheet
  workbook and saved as CSV, so multi-sheet workbooks convert fully (Excel's own
  "Save As CSV" would only save the active sheet).
- **Empty sheets** (no used data) are skipped; if a workbook has only empty
  sheets, they are emitted anyway so nothing is silently dropped.
- **Sheet-name collisions** in filenames get a numeric suffix.
- **Move only happens on success** (all sheets written). A file that errors or
  times out stays in place for a retry with `--skip-existing`.

### Edge cases

- **OneDrive cloud-only files**: each source is copied to a temp location first,
  which hydrates placeholders and avoids locks.
- **A workbook that hangs Excel**: the batch driver kills only the Excel
  instance it spawned for that file (never the user's open Excel) and moves on;
  the source is left in place.
- **Formulas**: CSV captures the computed cell values (Excel writes results, not
  formula text), which is the expected CSV behavior.

### Dependencies

Windows + Microsoft Excel (used headless via COM) + Python 3.12 with `pywin32`.
All present on this machine. No extra packages required.
