[feature] Define multi-machine vault convergence: a Markdown merge driver, node identity, and an explicit sync operation

Author: CryptoJonesCreated Aug 2, 2026Updated Aug 2, 2026

Disclosure: I maintain omind, a separate Apache-2.0 project solving an adjacent problem (durable agent memory in a plain-Markdown Obsidian vault). I read claude-obsidian's source before filing and I'm linking omind's implementation as a worked reference — not proposing you adopt its code. Per CONTRIBUTING's evidence rule, every claim below points at a specific file.

Problem

A vault used from two machines has no defined convergence story today.

What exists: claude_obsidian/checkpoint.py commits one completed operation, and the README scopes git to "development, releases, or an explicit knowledge checkpoint." So git is present as a history mechanism, not a sync mechanism. There is no node identity, no merge strategy, and no documented multi-machine workflow.

That leaves the user to git pull by hand, and the failure is not hypothetical:

  1. Markdown conflict markers land inside vault pages. Git's default text merge on two machines that both appended to wiki/log.md, or both edited different sections of the same page, produces <<<<<<< markers in a file Obsidian then renders as garbage. Every page in this product has a predictable section structure, which is exactly the case a custom merge driver handles well and the default driver handles badly.

  2. It collides with the transaction contract. transaction.py records a precondition SHA-256 for every target. A git pull that rewrites a page out from under a prepared bundle turns into TransactionConflict — correct behavior, but the user is now holding a failed operation and a conflicted worktree with no guidance.

  3. Derived state has no rules. .vault-meta/ (chunks, BM25 index, tiling cache) is ignored runtime state. Nothing says whether it should be gitignored on sync, and if it is not, every machine fights over index.json on every commit.

The single-machine design is coherent and I'm not asking you to abandon it. The ask is for the two-machine case to be defined — even if the definition is "don't."

Proposed solution

Concretely, smallest useful version first:

1. A merge driver for vault Markdown. Register via .gitattributes in the vault template. Section-aware three-way merge: both sides' additions to distinct ## sections merge cleanly; genuinely overlapping edits to the same lines still conflict, loudly. omind does this in src/omind/merge.py (omind merge-driver) — a three-way hunk merge with a union fallback for append-only sections, chosen so that concurrent appends on two machines converge to the same bytes regardless of which side merges first. Symmetric convergence is the property to test for; it is easy to get wrong and easy to pin.

2. Node identity. A per-machine id in the ignored runtime config so an operation and its journal can record which machine produced it. omind keeps this in mesh.py (NodeConfig / new_node_id).

3. Explicit sync as one more reviewed operation. Not a background daemon — that would fight the consent model. claude-obsidian.py sync --vault PATH planning fetch → merge → push, previewing like every other mutating command and refusing to run while a transaction lock is held.

4. At minimum, documentation. If the above is too much, a docs/multi-machine.md saying "put the vault in git, gitignore .vault-meta/, expect conflicts in log.md, recover with transaction recover" would close most of the risk. omind's equivalent is docs/mesh.md.

Alternatives considered

  • Syncthing / Dropbox / iCloud over the vault. What most Obsidian users do, and the worst option here: file-level sync with no merge semantics will interleave writes with an in-flight transaction and corrupt the journal. If the answer is "use a file syncer," the docs should at least say to stop the agent first.
  • Obsidian Sync. Same problem, plus it doesn't know about .vault-meta/.
  • Declare it single-machine. Legitimate! But say so explicitly in the README, because "your vault is a normal directory of Markdown" reads as an invitation to git it.

Scope

  • A new script (scripts/<name>) — merge driver + sync
  • Change to plugin manifest / hooks / setup scripts — .gitattributes in templates/vault/, bin/setup-sync.sh
  • Documentation only — docs/multi-machine.md (viable as a standalone first step)

Compatibility

  • Behavior change for existing v1.x vaults? No for the driver and docs (opt-in, and an unregistered driver simply isn't used). A new .gitattributes in the vault template affects new vaults only; migrate could add it additively.
  • New opt-in (bin/setup-*.sh)? Yes.
  • New dependency? No — git is already required for checkpoints, and a merge driver is a plain executable git invokes with three paths.

Testing

Hermetic; no network needed, since git merges are local. Build two clones of a tmp_path fixture vault, commit divergent edits in each, merge, and assert:

  • distinct-section edits merge with no markers and no data loss;
  • concurrent appends to log.md converge to identical bytes in both merge directions (the symmetry property — this is the test that catches real driver bugs);
  • an overlapping same-line edit still conflicts rather than silently picking a side;
  • .vault-meta/ never enters a commit;
  • a merge attempted while the transaction lock is held fails closed.

tests/test_concurrent_write.sh and tests/test_wiki_lock.sh already establish the shell harness pattern this would follow.

Additional context

Of the four things I'm filing, this is the one I'd argue matters most — a knowledge base that compounds is one people keep for years, and they will eventually own a second machine.

Source: AgriciDaniel/claude-obsidian