name: importer-scaffolder
description: "Use when asked to build an importer from a competitor's export, migrate users' data from another tool, map a CSV or JSON export onto my data model, or make switching to my project easy. Given a sample export (CSV or JSON), produces a field mapping table, an importer code skeleton, a rule that unmatched records are kept rather than dropped, and test fixtures including the awkward cases. For a database migration inside one system, use database-migration-plan."
version: 1.0.0
Importer Scaffolder
People switch tools when leaving costs them nothing, and an importer is how a small project removes that cost. Importers fail quietly: a column is renamed, a date is in another format, a record has no match, and data disappears without anyone noticing. This skill builds an importer from a real sample export, with a mapping that is explicit and a rule that nothing is silently dropped.
Required Inputs
Ask for these if not provided:
- A sample export: a few rows of CSV or a JSON excerpt, with any personal data replaced
- The source tool and how users produce the export
- Your data model: the target fields, types and required fields
- Your language and stack for the importer
- Where unmatched data should go: a notes field, an extras column, or a separate file
Output Structure
1. Source profile
What the sample shows: format, encoding, delimiter, header names, date and number formats, nested fields, and anything ambiguous. List assumptions explicitly.
2. Field mapping table
| Source field | Example value | Target field | Transform | Required? | If missing or invalid |
|---|
Every source field appears in the table, mapped or not. Unmapped fields go to the extras destination named in the inputs.
3. The keep-everything rule
State it in the code and the docs: no source record is dropped. A record that fails validation is imported with what could be parsed, flagged, and listed in an import report; its raw source is preserved in the extras destination.
4. Importer skeleton
Code in the requested language with these parts, each a small function:
read(source): streams rows; detects encoding and delimiter; never loads a huge file whole
mapRow(row): applies the mapping table; returns { record, warnings, extras }
validate(record): required fields and types; returns problems without throwing
write(record): idempotent upsert keyed on a stable source ID, so re-running an import does not duplicate data
report(): counts of imported, imported with warnings, and per-warning examples
Include a dry-run mode that prints the report without writing.
5. Test fixtures
Fixture files plus the expected result for each:
- the happy path (three normal rows)
- a renamed or reordered header
- an empty required field
- a malformed date and a number with a thousands separator
- non-ASCII text (accents, Chinese characters, emoji)
- a duplicate row (checks idempotency)
- a row with extra unknown columns (checks they land in extras)
6. User-facing instructions
Five to eight steps telling users how to export from the source tool and import, including what the import report means.
Quality Checks
Anti-Patterns
- Silent drops. A skipped row is lost data the user may never notice.
- Mapping by column position. Exports reorder columns; map by header name.
- Loading the whole file into memory. Real exports are bigger than samples.
- Guessing ambiguous dates. If 03/04 could be either order, ask or detect from the whole file, and record the choice.
Example Trigger Phrases
- "Build an importer for Trello JSON exports into my app."
- "Here's a CSV export from Notion, map it onto my data model."
- "Make it easy for users to switch from [competitor] to my project."
- "Write a CSV importer that never drops rows."