---
name: Sheet Studio
description: Use to clean a CSV the operator has in data/ or files/ — sort and filter it, look at a column, find duplicate rows, and write a cleaned copy as <name>.clean.csv beside the original without ever changing the original.
tagline: Tidy up a spreadsheet: sort, filter, spot duplicates and save a clean copy without touching the original.
version: 1
situations: clean this csv, dedupe the spreadsheet, remove duplicate rows, tidy the export, look at the leads list, sort the csv, column stats, drop these rows, sheet studio, clean a spreadsheet
requires-secrets:
requires-packages:
---

# Sheet Studio

## Why a screen

You can dedupe a spreadsheet blind; what you cannot do is know which rows the operator *meant*. The
app puts the file in front of them — sorted, filtered, with a preview showing exactly which rows a
dedupe would drop — and they answer with a click and four words instead of a paragraph describing
row 41.

## Where the CSVs are

Two folders, both of which this skill reads and writes:

- **`data/`** — the usual home for a spreadsheet the operator handed over or you pulled down.
- **`files/`** — where everything you generate lands, exports included.

The app sees every `.csv` under either one (up to three folders deep). Nothing else is in scope: not
`.00/`, not the workspace root, not another agent's folder.

This skill also ships an **AI App** (`Sheet Studio`, in the agent's Apps list) and a **New Session**
button ("Clean a spreadsheet"). The app is the fast path for anything the operator wants to *see*: a
sortable, filterable table with a sticky header, a column summary with a small histogram, a
duplicate preview, and one button that writes the cleaned copy.

## The one file it writes

`<name>.clean.csv`, beside the original:

```
data/leads.csv          the operator's file — never written, never renamed, never deleted
data/leads.clean.csv    what the app writes, RFC 4180: CRLF records, "" for a literal quote
```

The app has no code path that spells a write target without the `.clean.csv` suffix. Read the
cleaned file and carry on from it; if they want it to *become* the source, you move it — that is
your decision to take with them, not the app's.

What "cleaned" means, exactly: every row except the ones the duplicate preview would drop, with
surrounding spaces trimmed off each value when the operator leaves "Trim spaces" ticked (it is
ticked by default). Duplicate means *the same value in the chosen column, ignoring case and
surrounding whitespace*, and the **first** row of each group is the one kept. Nothing is reordered,
no column is dropped, no value is rewritten beyond the trim.

## Reading a "drop these rows because…" message

The app's prefill is the one you will see most. It arrives as a composer message shaped like:

> Drop these 14 rows from data/leads.csv because… (I have not written anything yet — the cleaned
> copy would be data/leads.clean.csv.)

with the rows themselves attached as the selection — a CSV fragment, header row first, the operator's
chosen rows under it (at most 40; the count in the sentence is the real total).

Read it like this:

1. **The count is the truth.** If the sentence says 14 and the attached fragment shows 40 lines of
   which 39 are rows, the rest were elided — ask for the rule, do not guess at row 15.
2. **They finished the sentence, or they did not.** "…because they are all test accounts" is a rule:
   apply it to the whole file, not just to the rows attached, and say which extra rows it caught.
   With nothing after "because…", ask what these rows have in common before you touch anything.
3. **Match on the values, not on positions.** Row numbers in the app are positions in the file as it
   was when they clicked; a re-sort or your own edit moves them. Find the rows by their key column.
4. **Write the cleaned copy, not the original.** `data/leads.clean.csv` (or the next free name
   beside it). Then tell them the path and the count, and let them re-open it in the app.

## Working with it

- **Find the file first.** `ls data/` and `ls files/` before you invent a filename. If both are
  empty, ask where the export is — or offer to fetch it — rather than writing a placeholder CSV.
- **Suggest the app** the moment they say anything about *looking*, *checking*, *which ones*, or ask
  a second question about the same file: "Open Sheet Studio and pick the rows — I'll take it from
  what you select." A screen beats three rounds of describing row 41.
- **Let them press the button.** The app writes the cleaned copy itself. If you write one too you
  have two files disagreeing about the same day's work.
- **Never write over a source.** `data/` and `files/` are theirs. A "cleaned up" original is a
  deleted afternoon; the `.clean.csv` copy costs nothing and can be thrown away.
- **A big file is fine.** The table draws a window above 500 rows, so 5 000 rows scroll smoothly.
  Text over 4 MB is more than the bridge carries in one read — split it before you hand it over.

## Notes for me

Write here what you learn about this workspace's spreadsheets — which column identifies a row, which
exports arrive dirty, what the operator always wants dropped — so the next session does not start
from nothing.
