SyncAgain

pending

by Robin Xiang

Periodically syncs modified vault files to a remote storage backend.

Updated 1d agoAGPL-3.0Discovered via Obsidian Unofficial Plugins
View on GitHub

obsidian-syncagain

An Obsidian plugin for bidirectional vault synchronization via a sync server. Multiple devices can sync simultaneously; changes made on one device appear on others in near real time through an SSE push channel.

Features

  • Bidirectional sync — upload local changes, download remote changes, propagate deletions
  • Multiple simultaneous clients — SSE-based push notifications trigger immediate sync when another client modifies a file
  • Conflict serialization — file locks prevent two clients uploading the same file at the same time
  • Content-based diffing — MD5 comparison avoids redundant transfers
  • Per-user accounts — individual email/password accounts with JWT authentication
  • Trash & recovery — non-permanent deletions are recoverable; permanent deletion option also available

How it works

Obsidian vault
      │
  FileTracker          (watches vault events, queues dirty files)
      │
  SyncManager          (runs on interval or on SSE event)
      │
  ├── upload dirty files
  │     ├── acquire lock  → 409? re-queue and retry next cycle
  │     ├── upload to server
  │     └── release lock
  │
  ├── download newer remote files
  │
  └── delete locally any files removed on server

A persistent SSE connection (EventListener) receives push events from the server. When another client uploads a file, the plugin triggers an immediate sync instead of waiting for the next interval.

Installation

Community plugin directory

  1. In Obsidian, open Settings → Community Plugins and disable Safe Mode if prompted.
  2. Click Browse, search for SyncAgain, and click Install.
  3. Click Enable.

Manual installation

  1. Download main.js, manifest.json, and versions.json from the latest release.

  2. Copy them to:

    <your-vault>/.obsidian/plugins/obsidian-syncagain/
    
  3. In Obsidian → Settings → Community Plugins, enable SyncAgain.

Configuration

Open Settings → SyncAgain:

SettingDescription
Server URLBase URL of your sync server, e.g. http://192.168.1.10:8080
AccountSign up (opens browser) or sign in inline with email + password
Sync intervalHow often (in minutes) to run a full sync cycle (default: 5)
Enable syncToggle to pause sync without changing other settings
Deletion strategyNon-permanent (recoverable, moved to trash) or Permanent (no recovery)

The plugin auto-generates a unique Client ID (UUID) per device, shown in settings for debugging.

Account management

  • Create account — opens your browser to the server's registration page; on completion the server redirects back to Obsidian with a JWT.
  • Sign in — enter email and password directly in the settings tab.
  • Sign out — clears the stored token and stops sync.

A signed-in user's email is shown in the settings tab. Token expiry (30 days by default) shows a notice asking you to sign in again.

Deletion strategies

StrategyBehaviour
Non-permanentFile is moved to server-side trash (_delete/ prefix); recoverable via the Trash view in settings
PermanentFile is deleted and a tombstone is written (_deleted/ prefix); not recoverable

The Trash section in settings lists trashed files with Recover and Delete permanently buttons.

Sync behaviour

Upload

  1. The vault watcher fires on file create, modify, rename, or delete.
  2. The FileTracker queues the file as dirty (last-write-wins per path within a cycle).
  3. On the next sync tick, the manager drains the queue and attempts upload:
    • Acquires a server-side lock on the file.
    • If the lock is held by another client (409), the file is re-queued for the next cycle.
    • Uploads the file; the server stores it in S3 and broadcasts a file_changed event.
    • Releases the lock.

Download

After uploading, the manager fetches the full remote file list and compares MD5 hashes with the local sync state. Files that are newer on the server are downloaded and written to the vault. Downloads are suppressed from re-triggering uploads.

Deletions

Files present in the last local sync state but absent from the current remote list are deleted from the vault locally.

Real-time push

The SSE connection receives events from the server. On file_changed or file_deleted events from other clients, the plugin triggers an immediate sync cycle rather than waiting for the interval.

Development

Prerequisites

Setup

cd obsidian_syncagain
npm install

Build

# Development (watch mode with source maps)
npm run dev

# Production (type-checked + minified)
npm run build

Output: main.js in the project root.

Install to vault for testing

mkdir -p /path/to/vault/.obsidian/plugins/obsidian-syncagain
cp main.js manifest.json versions.json /path/to/vault/.obsidian/plugins/obsidian-syncagain/

Then reload Obsidian or use the "Reload plugin" action.

Source layout

src/
├── main.ts            # Plugin entry point — lifecycle, event wiring, auth callback handler
├── settings.ts        # Settings interface, SettingTab UI, account management, trash view
├── file-tracker.ts    # Tracks dirty files between sync cycles (last-write-wins per path)
├── sync-manager.ts    # Orchestrates upload / download / reconcile
├── api-client.ts      # Typed HTTP client with JWT auth, file/lock/trash/SSE APIs
├── event-listener.ts  # SSE connection manager with exponential-backoff reconnect
└── metadata.ts        # Type definitions (RemoteFileEntry, LocalSyncState, SyncEvent)

Known limitations

  • Locks serialize uploads, not edits. The implementation for the plugin is based on an assumption that files are not modified simultanously from clients. If two clients edit the same file between sync intervals, the second to upload will overwrite the first. The system prevents simultaneous uploads but does not detect or merge divergent edits.
  • No rename tracking on server. A renamed file is treated as a delete + create, which may briefly trigger a deletion on other clients before the new file arrives.
  • In-memory locks. The server holds locks in memory. A server restart clears all locks; clients re-acquire on their next sync cycle.

Requirements

License

GNU Affero General Public License v3.0 — see LICENSE.

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.