Koofr Sync
approvedby bartekmp
Sync your vault with Koofr cloud storage. - This plugin has not been manually reviewed by Obsidian staff.
Obsidian Koofr Sync
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)
- Settings → Community Plugins → Browse → search "Koofr Sync"
- Install → Enable
Via BRAT (beta / pre-release)
- Install BRAT from Community Plugins
- BRAT settings → Add Beta Plugin →
bartekmp/koofr-obsidian-sync
Manual
- Download
main.js,manifest.json, andstyles.cssfrom the latest release - Place them in
<vault>/.obsidian/plugins/koofr-sync/ - Settings → Community Plugins → enable Koofr Sync
Setup
- 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.
- In Obsidian: Settings → Koofr Sync → enter your email and the app password → Connect to Koofr.
- Click Browse… under Sync Folder, pick a mount (your own Koofr storage or anything shared with you) and a folder within it.
- Done — your vault syncs automatically on file changes.
Settings reference
| Setting | Description |
|---|---|
| Sync Interval | Periodic sync interval. Set to "Manual" to disable timer-based sync. |
| Sync on file change | Disable to only sync on the interval or manually. |
| Startup Sync Delay | Delay before first sync after launch (0 = disabled, 10 s recommended). |
| Conflict Resolution | Last write wins (default), create duplicate, or manual review. |
| Sync App Settings | Optional — sync .obsidian/app.json, appearance.json, hotkeys.json. |
| Sync Plugins | Optional — sync plugin lists, manifests, and binaries (not plugin data files). |
| Sync CSS Snippets | Optional — sync .obsidian/snippets/. |
| Excluded Patterns | Glob patterns for files/folders to skip, stored in .syncIgnore. See below. |
| Pull-Only Mode | (Experimental) Download only, never upload local edits. |
| Debug Logging | Writes 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).
| Pattern | Matches |
|---|---|
*.tmp | any .tmp file, in any folder |
Attachments/large/** | everything under Attachments/large/ |
Drafts/ | the whole Drafts/ folder (trailing slash = folder) |
# note | a comment (ignored) |
* matches any characters within a single name; ** matches across folder boundaries.
Commands
Available via the command palette (Ctrl/Cmd+P):
| Command | Description |
|---|---|
| Sync now | Trigger an immediate sync. |
| Disconnect from Koofr | Clear stored credentials and sync state. |
| Force full sync | Clear tracked state so the next sync re-evaluates everything from scratch. |
| Reconcile from cloud | Destructive recovery — cloud version wins for every file, confirmation required for large deletes. |
| Show sync conflicts | Open 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.