Sift
An AI import studio: model a messy CSV or Excel file once into clean, validated data, then deliver it where it belongs. Postgres today, Xero and QuickBooks next.
Model the file once. Deliver it anywhere.
Every messy file drags you through the same detour today. Export it, and another vendor CSV lands in your downloads. Fix it in Excel, cell by cell: dates, dupes, stray header rows. Fight the importer on the other side, because every system wants its own template and rejects yours. Ship it, and hope nothing's silently wrong. Then do the whole thing again for the next file.
Sift replaces that loop with one flow. It's an AI import studio: drop in a CSV or Excel file however messy, and Sift models it. Columns get matched and typed, bad rows get caught at the gate, and the whole file gets a quality grade. You confirm what it proposes, and clean, validated rows are delivered where they belong. The live destination today is a real Postgres table you own. Xero and QuickBooks are next.
Four moves, no throwaway code
- Drop the file. Sift parses it server-side, finds the real header row, reads the sheet you pick. No pre-cleaning in Excel.
- Sift models it. AI matches each column with a confidence score you can see and override, and every value gets typed (
text,email,date,currency, …) against required and unique constraints. Save the mapping as a template and the recurring file imports itself next month. - You confirm. Bad values get flagged with proposed fixes you accept or reject per cell. Nothing lands without your say-so.
- It's delivered. Every cell is coerced and validated before commit, then accepted rows insert transactionally into a real table in your own schema. Define that table by hand, or let Sift infer it straight from the file's own shape.
The model is the asset
The idea underneath is that destinations should plug into the clean, validated model of the file rather than the file itself. Model it once and delivery becomes a detail: a Postgres insert today, a draft bill in Xero or an invoice in QuickBooks later. That's also the honest state of the roadmap. Postgres is live, the accounting destinations sit on the landing page marked coming soon, and I'd rather show the seam than oversell it.
Built to be doubted
The reason you hand-fix files isn't that uploading them is hard. It's that you don't trust anything else to touch your data. Sift is designed around that suspicion:
- It suggests, never invents. Bad values (invalid emails, impossible dates, dupes, missing required fields) get flagged with proposed fixes you accept or reject per cell. Nothing is ever auto-applied.
- Validation is total. Locale-aware numbers, explicit date formats, no
Date.parseguessing. A bad row never reaches your table. - You get a receipt. Every import ends in a quality report: six dimensions scored, a letter grade per column. The script version of you shipped on hope.
- You own the destination. The live destination is a real Postgres table in your database, not an export file or somebody's walled garden. Delete Sift tomorrow and your data doesn't notice.
It's for the finance and ops people who live in Xero or QuickBooks and keep receiving other people's messy exports, and for anyone with their own database who has written substantially the same import script three times. Live at sift.kr0w.zip, free to start.
How it got built
First, a confession. Sift is a rebuild of an older repo of mine, react-spreadsheet-import-ai. The README promised pretty much the product you just read about. The app faked all of it. The progress bars ran on setTimeout. The quality scores came from Math.random(). The CSV parser never finished, the multi-sheet reader always returned sheet one, and the AI calls could never have worked because nothing ever authenticated. I opened it expecting some mess and found a movie set.
So the rebuild had one rule: nothing fake. The schema builder runs real DDL and creates real Postgres tables. Files get parsed for real, on the server. The AI makes real calls, and it's allowed to fail: when the model is down or the daily budget runs out, Sift falls back to plain heuristics and keeps going.
I didn't type most of the code. Claude did, working from a written spec, and every task had to pass two reviews before it landed: one against the spec, one on the code itself. That sounds like ceremony for a side project. It caught things I would have shipped. The end-to-end test found middleware that only checked auth on GET requests, so in production every POST from the browser would have bounced to the sign-in page. The review of that same test then found a security hole the test setup had introduced. 759 unit tests, one Playwright run through the whole flow, three days from spec to live.
The positioning moved once since then, and on purpose. Sift started life sold as the import step between a messy file and the Postgres you already own. Then I did the April Dunford exercise properly and noticed that the people with the worst version of this problem don't own a database at all. They live in Xero and QuickBooks, and their importers fight back harder than any database ever did. So the frame became the model layer, and Postgres went from being the point to being the first destination. Even the footer got the memo (hover the last row of the landing page and watch it clean itself).
The last thing I wrote was the product description at the top of this page, and I wish I'd written it first. My original hero line was "Messy spreadsheets in. Clean, typed data out." True, and it says nothing. Any importer could run that line. The version that stuck starts from the loop instead, because the loop is the thing you'd actually recognize. The product didn't change that day. The words did.
One caveat. Sift has zero customers, so everything up top about who it's for is a guess about a person I've repeatedly been. Sample size of one, and I'm biased. If your downloads folder is full of vendor CSVs, whether they're headed for a database or your books, try it and tell me if the loop I described is the one you're in.
