Diffs
Lix diffs rows, not lines.
Plugins parse a file into rows: a CSV record, a spreadsheet cell, a Markdown block. Lix stores every change as a row in lix_change. A diff is a set of changed rows. It names the row that changed and gives its new value.
Example
An agent edits /orders.csv and sets order 1002 to shipped.
Before:
| order_id | product | status |
| -------- | -------- | ------- |
| 1001 | Widget A | shipped |
| 1002 | Widget B | pending |
After:
| order_id | product | status |
| -------- | -------- | ------- |
| 1001 | Widget A | shipped |
| 1002 | Widget B | shipped |
A text diff sees a line:
-1002,Widget B,pending
+1002,Widget B,shipped
Lix sees a row:
| row_pk | schema_key | snapshot_content |
|---|---|---|
["0192f3a1-…-7b2c"] | csv_row | {"id": "0192f3a1-…-7b2c", "order_key": "…", "cells": ["1002", "Widget B", "shipped"]} |
row_pk is the record's primary key. The CSV plugin gives each record a stable id, so the row keeps its identity even when the file is reordered. cells holds the decoded record. One cell changed, and your app renders that:
order_id 1002 status:
- pending
+ shipped
Granularity comes from plugins
A plugin decides what a row is for its format. The Markdown plugin emits blocks, the CSV plugin emits records. Both ship with the JavaScript SDK. JSON, plain text, and Excalidraw plugins are in the repository and install with one SQL statement; see Plugins. Without a plugin, Lix still tracks the file but does not split it into rows, so its diff is the whole file.
Application data that never touches a file works the same way. Register a schema and its rows diff like any other row.
What this buys you
- Review the record, field, or paragraph that changed, not a patch hunk.
- Query diffs by schema, file, row, branch, or time.
- Revert one field without reverting the file.
- Merge concurrent edits to different rows of the same file without a conflict.
Query it
Which rows of /orders.csv changed, most recent first?
SELECT
f.path,
c.created_at,
c.snapshot_content
FROM lix_change AS c
JOIN lix_file AS f
ON f.id = c.file_id
WHERE c.schema_key = 'csv_row'
AND f.path = '/orders.csv'
ORDER BY c.created_at DESC;
Learn more
- Diff Commands: compare two commits.
- History and SQL Surfaces: branch-scoped state and history queries.
- Schemas: define rows for application data.