Inspiration
Two exports can describe the same inventory and still disagree in confusing ways: rows move, column names change, and an ID appears twice. A student society reviewing its supplies needs to know which items changed and when the comparison itself cannot be trusted. TwinSheet turns that review into visible decisions about identity, field mapping, and comparison rules. Its demonstration uses invented inventory records, not a real organization or user study.
What it does
Load two CSV files, select each file's record key, and map corresponding fields. TwinSheet validates the keys before comparing. Empty identifiers and duplicates—including collisions caused by selected normalization rules—stop the result instead of silently choosing one row.
The result separates added, removed, changed, and unchanged records. Original compared values remain visible. Optional whitespace trimming and case-insensitive comparison are explicit; values stay strings, so numeric-looking identifiers retain their leading zeros and an empty value is not silently converted to zero.
In the included synthetic example, renamed headers and reordered records produce three changed items, one addition, two removals, and seven unchanged items. Four mapped cells change within matched records. For example, SUP-004 changes both quantity and condition. Those counts describe this fixture, not a performance or accuracy benchmark.
Export a comparison CSV or a full JSON report. The report records settings, original compared values, and SHA-256 source fingerprints. Reload the same original files and verify the saved report: TwinSheet validates metadata, matches fingerprints and delimiters, recomputes the comparison from the recorded settings, and checks the complete result. This establishes consistency with those files, not the truth of their contents or the identity of their author.
How it was built
TwinSheet uses React and TypeScript, bundled as a static site with Vite. A deterministic comparison engine handles CSV parsing, key validation, explicit field mapping, normalization, and change classification. Web Crypto hashes original file bytes. Browser file and download APIs support local input and export. Lucide supplies interface icons, and Vitest supports the engine and report tests.
The app has no account, upload service, database, analytics, or runtime model calls. CSV processing stays in browser memory, and a page reload clears the workspace. Downloaded files remain on the device. Hosting still involves ordinary requests for static application resources; local processing is not a claim of protection against malicious extensions or an altered application bundle.
Challenges and design decisions
The hardest question is not whether two cells look different, but whether two rows represent the same item. TwinSheet makes uncertain identity a blocker instead of presenting an authoritative-looking but ambiguous diff. Normalization is also a review choice: a setting that suppresses harmless formatting can hide a meaningful difference in another dataset.
The evidence itself needs boundaries. JSON preserves original values, while CSV export conservatively escapes potential spreadsheet formulas. A report is not anonymized. Exact-byte fingerprints intentionally fail when the source bytes change, even if a spreadsheet viewer renders the same visible table. Verification ignores object-key ordering and the creation timestamp, but preserves the meaning of the complete comparison result.
What is different
csv-diff already offers key-based structured diffs; daff provides rich table comparison and patching; Diffchecker compares spreadsheets in a browser. TwinSheet does not claim to invent CSV diffing. Its contribution is a compact review workflow: establish unambiguous identity, inspect visible mappings, explain changes, and retain decisions with evidence that can be checked against the originals. It avoids automatic merging and spreadsheet execution.
Validation and limits
The implementation has 115 passing automated tests across the comparison engine and report workflow. These cover the implemented rules and adverse inputs; they are not real-user validation, a security certification, or proof of universal correctness.
Inputs are UTF-8 CSV files, up to 2 MiB, 10,000 data records, and 100 columns each. Comparisons are capped at 100,000 cells, calculated as the union of keys multiplied by mapped fields. JSON/CSV exports and imported JSON reports have a 20 MiB limit. Oversized work stops rather than silently truncating evidence. Displayed row references identify logical CSV records, which may span several physical lines.
TwinSheet does not open Excel workbooks, evaluate formulas, infer the right key, resolve conflicts automatically, or certify source accuracy. Reports may contain sensitive source values and file metadata and need the same care as the originals.
Work completed during LovHack and AI disclosure
Initial preparation consisted of the name, problem outline, comparison plan, and Devpost draft. No completed product was brought into LovHack. The comparison engine, interface, report export and verification, synthetic examples, automated tests, and documentation were created during the event's September 26–October 4 build period. React, TypeScript, Vite, Vitest, and other general-purpose dependencies predate the event and retain their licenses.
OpenAI Codex, including parallel implementation and review agents, provided substantial assistance with research, code, design, tests, debugging, documentation, and submission preparation. This is AI-assisted work, not a claim of unaided implementation. The demonstration data is synthetic. No interviews, adoption, saved hours, or paid usage are claimed.
What's next
The next useful step is observing consenting users completing a small export review and learning where the decisions remain confusing. Support for additional formats or workflows should follow that evidence, rather than expanding the prototype without a demonstrated need.
The 2:30 demo is a captioned walkthrough of authentic software captures using synthetic data.
Built With
- lucide
- openai-codex
- react
- typescript
- vite
- vitest
- web-crypto
Log in or sign up for Devpost to join the conversation.