A Redtail export, an Access dump, 47 CSVs from a CRM nobody remembers buying. Point Claude at the folder and get back a five-tab Excel workbook that says what the tables are, how they connect and where the problems are. The client data never leaves your computer.
On this page
A folder of CSVs and a bad feeling.
Every migration starts the same way. The client sends a zip file, you unzip it, and you are looking at 47 CSVs with names like tbl_CONTACT_ADDR_X.csv and no documentation. Somebody in 2011 knew what ParentRefID pointed to. That somebody is retired.
You could open each file in Excel, squint at the columns, guess the keys and build a data dictionary by hand. I did that for years. It takes a day or two per source system, and you still miss things, because a human cannot eyeball 200,000 rows to confirm that a column is actually unique.
So I built a Claude skill that does it for me. You point it at the folder, it reads every file on your own computer, and it hands back one Excel workbook that tells you what the tables are, how they relate and where the problems are. The CSVs never leave your machine. Claude only ever sees the workbook, which holds table and column names and counts, and zero client data.
A script reads your data. Claude reads the workbook.
The skill is two things in a folder: a SKILL.md that tells Claude how to run the analysis and how to walk you through the results, and a Python script that does the actual reading. Claude never reads the CSVs.
It works on any CSV extract: another CRM, an ERP, a SQL Server / MySQL / Postgres / Access dump, or a Salesforce Data Export from an org you are consolidating. Optional profiles (JSON files) teach it the quirks of a specific system, and it auto-detects a Salesforce Data Export and a RedTail extract without you asking.
What it works out on its own
- File basics: delimiter, encoding, ragged rows, missing or duplicate headers,
dbo.andtblprefixes. - Primary keys: candidates verified unique and never blank across every row. A key that is not actually unique becomes a High finding.
- Foreign keys: matched by naming convention and, for GUIDs and Salesforce Ids, by value, then scored against live rows so the best resolver wins. Handles
007vs7, GUID braces, and 15- vs 18-character Salesforce Ids. - Polymorphic keys:
WhatId-style columns that point at several tables, andX_id+X_typepairs. - Table classification: Entity, Child / Detail, Lookup / Picklist, Junction, Polymorphic Child, Audit / History, Staging / Backup, System / Config, each with its reason.
- Column profile: inferred type, max length, line breaks, leading zeros, populated %, distinct values, picklist candidates.
What the workbook contains
| Tab | What is on it | When you read it |
|---|---|---|
| Findings | Every data-quality and structural issue, ranked High / Medium / Low | First. High rows first. |
| Engagement Intake | The questions you need the client to answer before scoping | Before the kickoff call |
| Source Data Analysis | One row per table: classification, row count, proposed Salesforce object, include or exclude | To build the migration scope |
| Key Map | Every primary and foreign key found, with a confidence rating | Focus on Low confidence and amber rows |
| Schema | Every column with inferred type, max length and stats | As a reference while mapping |
No data values anywhere in the workbook. Table names, column names, counts, percentages, types, lengths. That is it, and that is the point.
Five things, and you probably have four of them.
- A Claude plan that runs skills. Custom skills work on Pro, Max, Team and Enterprise.
- The Claude desktop app, on the computer that holds the client extract. Not the browser. The whole point is that the script runs locally, so Claude needs a shell on your machine. Claude Code works too if you live in a terminal; the steps below assume the desktop app.
- Python 3. Mac has it. On Windows, grab it from python.org and tick “Add to PATH” during install. Then one package:
python3 -m pip install openpyxl. - A client extract as CSV files in one folder. I use a standard engagement layout:
01_Source_Extractfor the CSVs,02_Analysis_Workbooksfor the output. Any folder works. If what you have is a.sqlbackup rather than CSVs, here is how to get CSVs out of it with Navicat first. - The skill itself, which is the next step.
You do not need to know Python. You never edit the script. You do not need to know what a foreign key is either, although by the end of this you will.
Get the skill from GitHub.
The skill lives in a public repo: elisesfdc/source-analysis. It is MIT licensed, so use it, change it, build it into your own thing.
A skill is just a folder. This one looks like:
source-analysis/
SKILL.md the instructions Claude reads
scripts/
source_analysis.py the script that reads your CSVs locally
profiles/
_template.json starter for a new source system
redtail.json RedTail CRM
salesforce_data_export.json
- Go to the repo’s Releases page and download
source-analysis-v1.0.0.zip. - That zip is already shaped for the upload in Step 2: one folder at the root, named
source-analysis, withSKILL.mddirectly inside it. Nothing to rename. - Unzip a second copy somewhere you will find it again. You will copy
scripts/andprofiles/out of it every time you run an analysis.
Prefer git? git clone https://github.com/elisesfdc/source-analysis.git gives you the same files and makes updates a git pull. What you should not use for the Claude upload is the green Code → Download ZIP button: it wraps everything in a source-analysis-main folder, which the uploader rejects. Avoiding that is exactly why the release zip exists.
Install it in Claude.
Claude takes custom skills as a zip uploaded in Settings. The upload is per account, so each person on your team does this once.

- In the Claude desktop app, open Settings, find the Skills section, and choose Upload skill. Pick the zip you downloaded.
- Make sure the skill’s toggle is on. Claude reads the
descriptionline inSKILL.mdto decide when to use it, so from now on “analyze these CSVs” or “what is in this export” in any chat will pull it in.
Quick test: start a new chat and ask “What does the source-analysis skill do?” If Claude describes a five-tab workbook and tells you the CSVs never leave your computer, you are installed.
Claude Code instead? Skip the zip entirely: /plugin install source-analysis --marketplace elisesfdc/source-analysis, or clone it into ~/.claude/skills/source-analysis and type /skills to confirm. Skills installed in Claude Code do not show up in the desktop app and vice versa, so do both if you use both.
Point it at your export folder.
This is the step that makes it safe, so do not skip it.

- Put the client’s CSVs in a folder on your computer. Mine is
ClientName/01_Source_Extract/. Make an empty sibling folder for the output:ClientName/02_Analysis_Workbooks/. - Connect that client folder to Claude. In the desktop app, click the + next to the message box and choose Add folder, then pick the
ClientNamefolder. This gives Claude a shell on your machine scoped to that folder, and nothing else. - Start a new chat and ask for the analysis.
Run a source analysis on 01_Source_Extract for Acme Wealth. The source is their old CRM, “Junxure”. Put the workbook in 02_Analysis_Workbooks.
Claude picks up the skill from the words “source analysis” and the CSV folder. The skill tells it to do two things before anything else: copy the script and profiles into a _source-analysis-tool/ folder next to your output, which brings the tool to the data, and never read, preview or upload the CSVs themselves.
If Claude asks whether a profile exists for the source system, say no unless you have built one. RedTail and Salesforce Data Export are detected automatically.
If you would rather not connect a folder at all, ask Claude for the command instead and run it yourself in Terminal:
python3 scripts/source_analysis.py "01_Source_Extract" \
--client "Acme Wealth" --source "Junxure" \
-o "02_Analysis_Workbooks/Acme_Wealth_Source_Data_Analysis.xlsx"
Then drag the finished workbook into the chat. Same result, and Claude still never touched the data.
Run it, and what to expect while it runs.
A typical CRM extract of 30 to 60 files and a few hundred thousand rows finishes in under a minute. Big SQL dumps take a few minutes.
The script makes two passes over every file: the first to profile columns and find primary keys, the second to test every foreign-key candidate against live rows. What you will see Claude do, in order:
- Copy
scripts/andprofiles/into02_Analysis_Workbooks/_source-analysis-tool/. - Run
python3 source_analysis.py ...in the connected folder. Ifopenpyxlis missing, it will tell you the one-line install. - Read the finished workbook. Only the workbook. Watch the tool calls if you are nervous; you will see it open the
.xlsxand nothing from01_Source_Extract. - Walk you through the tabs: Findings (High first), Engagement Intake, Source Data Analysis, Key Map, Schema.
The walkthrough is the useful part. Claude does not just dump the workbook on you; it reads the High findings out loud, tells you which key assignments it is unsure about, and asks the intake questions you will need the client to answer.
Flags you can add if a file looks odd: --delimiter tab|comma|semicolon|pipe and --encoding, both auto-detected per file so you rarely need them, --recursive for sub-folders, and --target if the destination is not Salesforce.
Reading the workbook, tab by tab.
Open the .xlsx in Excel and go left to right. Each tab answers one question.
What is broken?
One row per issue, ranked High / Medium / Low. High means it will break a load: a primary key that is not unique, a file with ragged rows, a lookup column where 30% of the values point at records that do not exist, which is the Data Loader error you would otherwise meet mid-load. Medium is cleanup work. Low is good to know.
Read every High row before the kickoff call, so the client hears about their orphaned records from you and not from a failed deployment.
What do I need to ask the client?
The questions the script could not answer from structure alone. “Do you use the Opportunities module?” “Are archived contacts in scope?” When a profile is in play, a No answer can automatically flip whole tables to Not Included, so the answers shape the scope directly.
What are these tables?
One row per file: the classification, the reason it was classified that way, row count, the proposed Salesforce target object, and an include or exclude call. This tab is your first draft of the migration scope. Audit, Staging and System tables are excluded by default; the Entity and Child tables are where the work is.
How does it all connect?
Every primary and foreign key found, with the source column, the table it resolves to, the percentage of live values that resolved, and a confidence rating. Green rows you can trust. Amber and Low rows need a human: usually a column with an integer id and no naming hint, or an id that matched two tables about equally well, reported as Ambiguous rather than guessed. Fix those with fk_overrides in a profile and re-run.
What is in every column?
The reference tab. Every column of every table with its inferred type, max length (anything over 255 is flagged as a Long Text Area candidate), populated %, distinct-value count, and whether it looks like a picklist. You will live in this tab during field mapping.
What to do with it next.
The workbook is step one of a migration, not the migration. Three things come straight out of it.
- 1
The scoping call
Take the Engagement Intake questions and the High findings to the client. You now know which tables matter, roughly how many records, and the three ugly things you need them to decide on. That is a scoping call that takes 45 minutes instead of three meetings, and from there the six phases that follow are the rest of the job.
- 2
The field mapping
Filter Source Data Analysis to Included, open Schema for those tables, and map column by column to the target objects. The inferred types and max lengths tell you what custom fields to create before a single record moves, and there are faster ways to grab the target field API names than clicking through Setup.
- 3
A profile for next time
If you will see this source system again, and if you do acquisitions you will, ask Claude to start a profile with
--write-profile-template. Fill it with what you confirmed. Profiles hold knowledge about the system, never about the client, so they are safe to keep and reuse.
One honest limit, so you plan for it: the script will not find a foreign key that has neither a naming hint nor GUID-style values, an integer ShipVia column pointing at a Shippers table being the classic case, and it does not detect composite primary keys. Those show up as “no single-column primary key” and you add them as overrides. Worth getting right, because the keys the Key Map hands you are exactly the ones that become External Id fields on the Salesforce side. Classification is structural; confirm every row. Nothing in the workbook replaces the client signing off on scope.
The things that go wrong, and the fixes.
Claude says it cannot reach my computer
It tried to run in the cloud
The upload rejected my zip
source-analysis-v1.0.0.zip from the Releases page, not Code → Download ZIP (which adds a -main suffix) and not GitHub’s auto-generated “Source code (zip)” on the release itself (which unzips to source-analysis-1.0.0). Open the zip to check: the root must be exactly one folder named source-analysis, with SKILL.md directly inside it.openpyxl not found
python3 -m pip install openpyxl once. On a Mac with several Pythons, use the same python3 the error came from.My files are tab-delimited, UTF-16, or otherwise weird
--delimiter explicitly.Is my client data really safe?
Crm::Contact, do get written to the workbook, because they are needed to map tables. Those are system values, not client records. Never paste raw CSV rows into chat to “help” it.Can I use it for a non-Salesforce target?
--target is just a label on the proposed-object column. The key discovery and classification are target-agnostic.Free, MIT licensed, and it runs on your machine.
If you build a profile for a source system that is not in there yet, send me a pull request and I will add it.
Know someone staring at an undocumented export?
Share on LinkedIn