Koofr Sync

approved

by bartekmp

Sync your vault with Koofr cloud storage. - This plugin has not been manually reviewed by Obsidian staff.

72 downloadsUpdated 12d agoMIT
Obsidian Koofr Sync logo

Obsidian Koofr Sync

CI License

Sync your Obsidian vault with Koofr cloud storage. Event-driven, bidirectional, mobile-friendly.

[!NOTE] This plugin is not affiliated with Koofr. It's built against Koofr's public REST API v2. Its architecture (sync engine, conflict resolution, settings UI) is adapted from obsidian-onedrive by Jeff Steinbok.

Features

  • Zero OAuth setup — Koofr auth uses just an email + a revocable app-specific password you generate in the Koofr web app. No Azure, no consent screen.
  • Event-driven sync — Syncs on file changes, not polling. Better for battery life.
  • Bidirectional — Automatic two-way sync with configurable conflict resolution.
  • Any mount, any folder — Sync your own Koofr storage or anything shared with you, into any subfolder.
  • Pull-only mode — (Experimental) One-way sync from Koofr for read-only vaults or backup recovery.
  • Conflict resolution — Last-write-wins, create-duplicate, or a manual review pane with inline diffs.
  • Mobile-friendly — Works on iOS and Android; no desktop-only APIs.

Why this over Koofr's native client or a WebDAV mount?

  • Skips device clutter — workspace UI state files (.obsidian/workspace*.json) are intentionally excluded.
  • Event-driven, not filesystem polling — reacts to Obsidian vault events directly.
  • Built-in conflict handling — choose overwrite, duplicate, or manual diff-based resolution.

Installation

Community Plugins (recommended)

  1. Settings → Community Plugins → Browse → search "Koofr Sync"
  2. Install → Enable

Via BRAT (beta / pre-release)

  1. Install BRAT from Community Plugins
  2. BRAT settings → Add Beta Pluginbartekmp/koofr-obsidian-sync

Manual

  1. Download main.js, manifest.json, and styles.css from the latest release
  2. Place them in <vault>/.obsidian/plugins/koofr-sync/
  3. Settings → Community Plugins → enable Koofr Sync

Setup

  1. Generate an app-specific password: Koofr web app → Profile → Preferences → Password → App passwords. Your regular Koofr account password will not work — Koofr requires a scoped, revocable app password for third-party connections.
  2. In Obsidian: Settings → Koofr Sync → enter your email and the app password → Connect to Koofr.
  3. Click Browse… under Sync Folder, pick a mount (your own Koofr storage or anything shared with you) and a folder within it.
  4. Done — your vault syncs automatically on file changes.

Settings reference

SettingDescription
Sync IntervalPeriodic sync interval. Set to "Manual" to disable timer-based sync.
Sync on file changeDisable to only sync on the interval or manually.
Startup Sync DelayDelay before first sync after launch (0 = disabled, 10 s recommended).
Conflict ResolutionLast write wins (default), create duplicate, or manual review.
Sync App SettingsOptional — sync .obsidian/app.json, appearance.json, hotkeys.json.
Sync PluginsOptional — sync plugin lists, manifests, and binaries (not plugin data files).
Sync CSS SnippetsOptional — sync .obsidian/snippets/.
Excluded PatternsGlob patterns for files/folders to skip, stored in .syncIgnore. See below.
Pull-Only Mode(Experimental) Download only, never upload local edits.
Debug LoggingWrites a daily log under _KoofrSyncLogs/YYYY-MM-DD.md (device-local, never synced).

Under Authentication, a Test connection button verifies your stored credentials still work by making a lightweight authenticated request — handy since Koofr has no documented token lifetime.

Excluding files from sync

Add glob patterns — one per line — under Settings → Sync Configuration → Excluded patterns. They're saved to a .syncIgnore file in your vault root and applied on the next sync (you can also edit that file directly).

PatternMatches
*.tmpany .tmp file, in any folder
Attachments/large/**everything under Attachments/large/
Drafts/the whole Drafts/ folder (trailing slash = folder)
# notea comment (ignored)

* matches any characters within a single name; ** matches across folder boundaries.

Commands

Available via the command palette (Ctrl/Cmd+P):

CommandDescription
Sync nowTrigger an immediate sync.
Disconnect from KoofrClear stored credentials and sync state.
Force full syncClear tracked state so the next sync re-evaluates everything from scratch.
Reconcile from cloudDestructive recovery — cloud version wins for every file, confirmation required for large deletes.
Show sync conflictsOpen the manual conflict review pane.

How sync works

Koofr's REST API has no incremental "what changed since X" endpoint. Every sync fetches a single recursive listing of your chosen Koofr folder and diffs it against what this device last saw, by content hash — new, changed, and deleted files are all detected from that diff. This is simpler than a delta-cursor design and works well for typical vault sizes (hundreds to low thousands of files); very large vaults will produce proportionally larger listing payloads per sync.

Known limitations

  • Large file uploads: Koofr's upload endpoint accepts a whole file in a single request — there's no chunked/resumable upload API for very large attachments.
  • Token expiry: Koofr has no documented refresh-token flow. The plugin re-authenticates from your stored app password whenever a request returns 401.
  • English only: The i18n infrastructure is in place (src/i18n/), but only English strings ship currently. Contributions welcome.

Development

npm install
npm run dev      # watch build
npm run build    # production build (typecheck + bundle)
npm test         # unit tests
npm run lint

See src/sync/syncEngine.ts for the sync algorithm and src/api/koofrClient.ts for the Koofr REST API v2 wrapper.

License

MIT — see LICENSE. Architecture adapted from obsidian-onedrive (also MIT).

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.