Sync Model
MindWiki keeps your vault in sync across the macOS app, the web app, and any connected MCP / API clients. This page explains how that sync actually works so you can predict its behavior and trust it.
The big picture
Your vault has two homes: a server-side store and (if you use the macOS app) a folder on your Mac. The web app reads and writes against the server-side store directly. The macOS app writes locally first, then syncs through the same server-side store. Every device sees the same vault.
The event log
Every page write or delete generates one event in an append-only log. Events carry:
- A monotonic
seqnumber - The path that changed
- A content hash of the new state (or a tombstone for deletes)
- The device that originated the change
- An
origin(web,desktop,mcp,api) - A timestamp
This log is the source of truth for sync. Reconstructing the current state of any page is a matter of finding the most recent event for that path.
How clients pull
When the macOS app starts, and on a heartbeat every ~15 seconds while running, it calls:
GET /vault/changes?since={cursor}&exclude_device={device_id}The server returns every event newer than the cursor, excluding events the calling device originated (so devices don't echo their own changes). The client applies each event to the local files: writes pull down content if the local hash differs, deletes remove the file.
The web app uses the same endpoint to power its live activity dashboard.
How clients push
When the macOS app detects a local change, it sends:
POST /vault/page
{
"path": "...",
"content": "...",
"base_hash": "<hash from last known server state>"
}The base_hash is optimistic concurrency. The server checks whether the page's current hash matches base_hash:
- Match — the write applies and a new event lands in the log.
- No match (HTTP 409) — your push raced another change. The server returns the actual current hash so you know what's there. The client writes a
.conflict-...file to preserve your local work without clobbering the remote.
This is how multi-device editing stays sane: nothing overwrites silently.
What you'll see
In normal use, sync is invisible. Edits propagate within a few seconds. The macOS app's status bar shows the most recent sync time. The web app shows a live activity panel on the dashboard.
When something interesting happens, you'll see one of these:
- A `.conflict-...md` file — your push lost a race. See Conflicts.
- A failed sync notice — usually transient (network blip). The next heartbeat retries.
- An out-of-date status — typically resolves when you reopen the app or wait for the next heartbeat.
What gets synced
- All `.md` pages — full body content
- All files in `_assets/` — images, audio, video, PDFs, attachments
- Folder structure — additions, renames, deletions
What does not sync:
- Files outside the vault folder (the macOS app only operates on the vault you chose).
- Files in
.trash/(kept locally for recovery, not synced). - Files in
.mindwiki/(local sync state — internal). - Hidden files like
.DS_Store,.git,node_modules.
Origins
Every event has an origin field that tells you which surface created the change. Useful when debugging:
| Origin | Means |
|---|---|
web | Edit made via the web app |
desktop | Edit made via the macOS app |
mcp | Change made via an MCP tool call |
api | Change made via REST API key |
You can see origins in the activity log on /account/connections and in the macOS Agents → Sessions & Activity view.
Multi-device behavior
You can run the macOS app on more than one Mac. Each device gets its own device ID; each pushes and pulls against the same vault on the server. Edits made on one Mac propagate to the other through the standard pull/push cycle.
Where to go next
- Conflicts — what happens when two devices race
- Devices — manage your connected devices
- Export & Backup — your vault, on demand