The Multi-User Problem
To understand the patch system, let's first understand why it's needed.
Why Not Just Commit the Database?
The naive approach would be to track .deciduous/deciduous.db in git. This doesn't work well:
- Binary files don't merge. When two people add nodes, git can't merge the databases.
- ID conflicts. Alice's node #47 and Bob's node #47 are different nodes.
- Large diffs. SQLite files change in non-obvious ways, creating noisy diffs.
The Dual-ID Solution
Deciduous solves this with a dual-ID model (inspired by jj/Jujutsu):
| ID | Scope | Purpose |
|---|---|---|
id |
Local | SQLite auto-increment, different on each machine |
change_id |
Global | UUID assigned at creation, same everywhere |
When you create a node:
$ deciduous add goal "Add authentication" -c 90 Created node #47: goal "Add authentication" # Internally: id=47, change_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890
The id (#47) is local. The change_id (UUID) is global.
How Patches Work
When you export a patch, it contains the change_id, not the id:
{
"nodes": [
{
"change_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"node_type": "goal",
"title": "Add authentication",
"confidence": 90
}
]
}
When a teammate applies this patch:
- Their database might assign it
id=123(different local ID) - But the
change_idstays the same - Edges reference
change_id, so connections are preserved
Idempotent Application
Patches are idempotent—you can apply them multiple times safely:
$ deciduous diff apply alice-auth.json Applied 5 nodes (5 new, 0 existing) $ deciduous diff apply alice-auth.json Applied 5 nodes (0 new, 5 existing)
The second application recognizes the nodes by their change_id and skips them.
Migration
If you're upgrading from an older deciduous version, run:
$ deciduous migrate Added change_id column to nodes table Added change_id columns to edges table Generated UUIDs for 47 existing nodes Generated UUIDs for 52 existing edges
This adds change_id columns and generates UUIDs for existing data.