# Syncidian

Syncidian

[![CI](https://github.com/shangeethsivan/Syncidian/actions/workflows/ci.yml/badge.svg)](https://github.com/shangeethsivan/Syncidian/actions/workflows/ci.yml) [![Latest release](https://img.shields.io/github/v/release/shangeethsivan/Syncidian)](https://github.com/shangeethsivan/Syncidian/releases) [![License: MIT](https://img.shields.io/github/license/shangeethsivan/Syncidian)](LICENSE) [![Obsidian](https://img.shields.io/badge/Obsidian-plugin-7C3AED?logo=obsidian&logoColor=white)](plugin/) [![Discord](https://img.shields.io/badge/Discord-join-5865F2?logo=discord&logoColor=white)](https://discord.gg/sSpQQcV7K9) [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-FFDD00?logo=buymeacoffee&logoColor=black)](https://buymeacoffee.com/shravzdev) > **Your data stays with you.** Sync your knowledge. Back it up. Connect your AI. **Obsidian plugin:** install **Syncidian** from Community plugins (or [BRAT](https://github.com/TfTHacker/obsidian42-brat) / sideload). Point it at your Syncidian server with a `sk_sync_…` token. This plugin does not use Obsidian Sync. Syncidian is an open-source, self-hostable **Obsidian synchronization and AI bridge**. It runs as an Obsidian plugin on your devices and connects to a lightweight Syncidian server that coordinates synchronization between them. Each signed-in user can connect **one private GitHub repository**. GitHub is the durable, versioned **source of truth** for that user's vault. The public site is a one-page story: join the waitlist and sign in with GitHub on Syncidian.com, or sign in with email on a self-hosted host. GitHub sign-in is hidden on the hosted landing (tap the app name six times to reveal it) and limited to `SYNCIDIAN_GITHUB_ALLOWED_EMAILS` until public launch. Operators use a private hostname (`SYNCIDIAN_ADMIN_HOST`, for example `admin.syncidian.com` on Tailscale) or an unlisted path (`SYNCIDIAN_ADMIN_PATH`, default `/admin`) β€” neither is linked from the landing page. Admins manage users and an optional instance GitHub App, and never see vault or GitHub data. Syncidian also includes a built-in **MCP server**, allowing compatible AI tools and agents to securely interact with your Obsidian knowledge base. The server is designed to be written in **Go** and deployed with a simple **Dockerfile**, making self-hosting as easy as: ```bash docker build -t syncidian . docker run -d \ --name syncidian \ -p 8080:8080 \ syncidian ``` **Self-host Syncidian for free.** A managed service is planned at $1/month; it is not available yet. [![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/new/template?template=https://github.com/shangeethsivan/Syncidian&utm_medium=integration&utm_source=button&utm_campaign=syncidian) One click deploys this repo on [Railway](https://railway.com). Attach a volume at `/data` before you create the admin so users survive redeploys. Details: [Deploy on Railway](#deploy-on-railway). [Buy me a coffee](https://buymeacoffee.com/shravzdev) if Syncidian is useful. --- # πŸš€ Quick start (Mac, Linux, or Windows with Docker) This repository is ready to run. Clone it, start the server, install the Obsidian plugin, and sync. ## 1. Start the server **With Docker (recommended):** ```bash git clone https://github.com/shangeethsivan/Syncidian.git cd Syncidian docker compose up --build -d ``` Self-host operators open [`/admin`](http://localhost:8080/admin). You can skip Tailscale β€” leave `SYNCIDIAN_ADMIN_HOST` unset, or set `SYNCIDIAN_ADMIN_PRIVATE=0`. Optional mesh lock-down: **[Hide admin.syncidian.com on Tailscale](docs/tailscale-admin.md)**. Open [http://localhost:8080](http://localhost:8080). The public page explains Syncidian and, on a self-hosted instance, lets people **sign up with email** β€” a GitHub App is not required to create an account. On Syncidian.com people use **Continue with GitHub** (hidden until you tap the app name six times). Operators open [`/admin`](http://localhost:8080/admin) (or `SYNCIDIAN_ADMIN_PATH`), or a private hostname (`SYNCIDIAN_ADMIN_HOST`, see [Hide admin.syncidian.com on Tailscale](docs/tailscale-admin.md)) once to create the first admin β€” that surface is not advertised on the landing page. Persist `/data` so that admin and later users survive deploys. Follow [Set up the GitHub App](docs/github-app.md) only if you want GitHub sign-in or per-user backup. A **Help** button on the operator page and the signed-in dashboard walks through the rest. After sign-in, a regular user can connect **one GitHub repository**, then creates an access token (`sk_sync_…`). Admins can also mint a one-time token for a vault user from **Users** (they still cannot sync as admin). Copy the token once β€” it is not shown again. **Without Docker (Go 1.22+):** ```bash go run ./cmd/syncidian serve ``` Data is stored in `./data` by default (`SYNCIDIAN_DATA` to change it). Docker Compose persists it at `/data` via a named volume (not a Dockerfile `VOLUME`, which Railway and some builders reject). **Without that volume, a new deploy starts with an empty database** β€” no users, no GitHub App, empty vaults. ### Deploy on Railway [![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/new/template?template=https://github.com/shangeethsivan/Syncidian&utm_medium=integration&utm_source=button&utm_campaign=syncidian) Users, GitHub App credentials, and vault files live in SQLite on disk. Railway’s container filesystem is **empty on every deploy** unless you attach a volume. 1. Click **Deploy on Railway** (or New project β†’ this GitHub repo). Railway clones the repo and builds the `Dockerfile` from `railway.json`. 2. **Settings β†’ Volumes β†’ Add volume**, mount path **`/data`**. Do this before creating the admin or registering the GitHub App. `railway.json` sets `requiredMountPath` to `/data` so a deploy without a volume fails instead of silently resetting the instance, and `overlapSeconds` to `0` so two replicas do not share SQLite during a rollout. 3. Generate a public domain. The server listens on Railway’s `PORT` and uses `RAILWAY_PUBLIC_DOMAIN` for the dashboard URL unless you set `SYNCIDIAN_PUBLIC_URL`. 4. Optional variables: `SYNCIDIAN_BOOTSTRAP_USER`, `SYNCIDIAN_BOOTSTRAP_PASSWORD`. To keep the GitHub App if the volume is missing, also set `SYNCIDIAN_GITHUB_APP_*` (see [Set up the GitHub App](docs/github-app.md)). Set `SYNCIDIAN_DATA_KEY` (32-byte hex) so GitHub App secrets stay encrypted even if `syncidian.db` is copied off the volume. Until public GitHub sign-in, set `SYNCIDIAN_GITHUB_ALLOWED_EMAILS` to the GitHub emails that may complete OAuth (JSON array, commas, or one per line). Hosted should include `Shangeeth95@gmail.com`. Joining the waitlist does not grant access β€” add each person to this variable, then redeploy. 5. Open the public URL. Create the admin at `/admin`. People can then sign up with email on `/`. Register the GitHub App ([walkthrough](docs/github-app.md)) only if you want GitHub sign-in or backup. `/admin` warns if the data directory is still ephemeral. On the hosted landing, tap **Syncidian** six times to reveal GitHub sign-in. Point the plugin at that URL with that user's token. Health check: `GET /health`. Agents can also fetch `/robots.txt`, `/auth.md`, `/.well-known/mcp/server-card.json`, and markdown for `GET /` (`Accept: text/markdown`). `/robots.txt` disallows the operator path (`/admin` by default) and operator APIs; that HTML also sends `X-Robots-Tag: noindex` so search engines should not list it. The operator page is not in `/sitemap.xml` and is not linked from `/`. If a CDN (Cloudflare AI Crawl Control) injects its own `robots.txt`, turn that off so the origin file is what crawlers see. ## 2. Install the Obsidian plugin You still run a Syncidian server (step 1). The plugin is only the Obsidian client. **From Community plugins:** 1. Settings β†’ Community plugins β†’ turn **Restricted mode** off. 2. Browse β†’ search **Syncidian** β†’ Install β†’ Enable. 3. Settings β†’ Syncidian: * Server: **Syncidian.com** (default), or **Custom Domain** if you self-host * Custom domain: your server URL (enabled only when Custom Domain is selected) * Access token: the `sk_sync_…` value from the dashboard * Device name: e.g. `MacBook Pro` 4. Click **Connect**. If Browse does not show Syncidian yet, install [BRAT](https://github.com/TfTHacker/obsidian42-brat), then add `shangeethsivan/Syncidian`. BRAT needs a GitHub Release whose **tag** matches `manifest.json` `version` **and** whose **Assets** list includes `main.js`, `manifest.json`, and `styles.css` (not only the automatic source zip). See [Publishing](#-publishing-the-obsidian-plugin). **Sideload** from a running Syncidian server (no git clone) or from this repo: Syncidian is a **mobile-capable** community plugin (`isDesktopOnly: false`). It does **not** use Node.js, Electron, or a local Git binary β€” that is why [Obsidian Git](https://github.com/denolehov/obsidian-git) and similar plugins never run on Android or iOS, and why this one can. ```bash # from a deployed instance β€” downloads only the three plugin files ./scripts/install-plugin.sh "/path/to/YourVault" "https://your-syncidian.example" # or open https://your-syncidian.example/assets/obsidian.zip ``` ```bash # from this repository chmod +x scripts/install-plugin.sh ./scripts/install-plugin.sh "/path/to/YourVault" ``` On a Mac this is often something like: ```bash ./scripts/install-plugin.sh "$HOME/Documents/Obsidian/MyVault" ``` Or copy these files by hand into `{Vault}/.obsidian/plugins/syncidian/`: * `plugin/manifest.json` * `plugin/main.js` * `plugin/styles.css` Then Settings β†’ Community plugins β†’ turn **Restricted mode** off β†’ enable **Syncidian** β†’ Connect as above. Repeat the token (and install, if you sideloaded) on each device (Windows, Mac, Android, iOS). Create one token per person; the same user can register many devices. ### Android and iOS Step-by-step (Restricted mode, Community plugins / BRAT / copying files, then Connect): **[Enable on Android and iOS](docs/install-mobile.md)**. On a phone, leave **Syncidian.com** selected or choose **Custom Domain** with a public `https://` address. `http://localhost:8080` is the phone itself, not your computer. iOS often blocks plain `http://`. ## 3. Optional: GitHub backup (per user) Create **one GitHub App for this instance** before people sign in with GitHub. Step-by-step: [Set up the GitHub App](docs/github-app.md). Short version: create the first admin at `/admin`. Self-hosted users sign in with email. The GitHub App is optional β€” open `/admin` β†’ **Create GitHub App**, or set `SYNCIDIAN_GITHUB_APP_*`, if you want GitHub sign-in or backup. After identity, a user can install the app on **one** repository. Syncidian always uses the **main** branch β€” other branches are not supported. Personal access tokens and deploy keys are not used. That repository is bound to **that user only**. Admins do not connect a vault repo and cannot see another user's repo or GitHub App credentials. The plugin never needs GitHub credentials. Until that user connects GitHub, their devices still sync through the server. ## 4. Optional: MCP / AI Dashboard β†’ **Overview** and **MCP / AI** list connected MCP clients, how often they call tools (last 24 hours, 7 days, and all time), and per-tool counts. **MCP / AI** also sets tool permissions (search/read on by default). Point an MCP client at: ```text POST http://localhost:8080/mcp Authorization: Bearer sk_sync_… ``` Create a token on the **Tokens** page, or exchange a password for one: ```text POST http://localhost:8080/api/v1/mcp/login {"username":"you","password":"…"} ``` Dashboard session cookies also work on `/mcp`. **MCP does not save notes on the Syncidian server.** Create/update/delete write to your connected GitHub repository on `main` and notify live Obsidian clients. Connect GitHub before using write tools. Tools cover search, graph/backlinks, create/update/append, moving any vault file type (including images), and bulk organize when permissions allow. --- # πŸ“¦ Publishing the Obsidian plugin There are **two** places plugin metadata lives. Neither is a `tests/` folder (a test only *checks* the root files exist). 1. **Git repo (community directory crawler):** `manifest.json` and `versions.json` at the **repository root**, kept identical to `plugin/manifest.json` and `plugin/versions.json` with `make plugin-manifest`. Obsidian reads these at HEAD of the default branch. 2. **GitHub Release Assets (what BRAT and in-app install actually download):** three **attached files** on the release whose tag equals `version` (`0.1.0`, not `v0.1.0`): * `main.js` * `manifest.json` * `styles.css` β€œAssets” here means that downloadable list on the release page. Creating a tag or clicking **Create release** in the GitHub UI does **not** attach those files by itself. `.github/workflows/release.yml` builds the plugin and uploads them. If a previous run left a release with no plugin files (for example attestation failed on a **private** repo before upload), merge this workflow, then **Actions β†’ Release Obsidian plugin β†’ Run workflow** and enter the existing tag. That uploads or overwrites the three files. You can also attach `plugin/main.js`, `plugin/manifest.json`, and `plugin/styles.css` by hand on the release page. Publish: 1. Edit the plugin under `plugin/`. **Bump `plugin/manifest.json` `version` in the same change** (required before merging plugin updates to `main`). Then copy metadata to the root: ```bash make plugin-manifest ``` 2. Push an annotated tag matching `plugin/manifest.json` `version`: ```bash git tag -a 0.1.0 -m "0.1.0" git push origin 0.1.0 ``` The workflow skips GitHub attestations on private repositories (that feature is not available there) so the three files still upload. 3. Submit (or update) the listing at [community.obsidian.md](https://community.obsidian.md): sign in with your Obsidian account, link GitHub, and add this repository (`shangeethsivan/Syncidian`). The directory uses the root `manifest.json` on the default branch; the `id` is `syncidian`. 4. Address automated review feedback, then bump the version and tag again. After approval, people install from Community plugins β†’ Browse β†’ **Syncidian**. You can also install with [BRAT](https://github.com/TfTHacker/obsidian42-brat) pointed at this GitHub repo **after the three files are on the Release**, or with `scripts/install-plugin.sh`. Keep `isDesktopOnly` **false** so Android and iOS can install it. Mobile install: [`docs/install-mobile.md`](docs/install-mobile.md). Packaging notes: [`docs/community-plugin.md`](docs/community-plugin.md). Rebuilding the plugin after TypeScript changes: ```bash cd plugin && npm install && npm run build ``` `plugin/main.js` is the compiled artifact Obsidian loads. Commit it so people can sideload without Node.js. --- # ✨ What is Syncidian? Syncidian brings three capabilities together: * πŸ”„ **Sync** β€” Synchronize your Obsidian vault across devices. * πŸ™ **Backup** β€” Use a private GitHub repository as the durable source of truth. * πŸ€– **AI** β€” Connect your knowledge base to AI tools through MCP. The goal is simple: > **Your Obsidian vault should belong to you, be backed up by you, and be accessible to the AI tools you choose.** --- # 🧠 The Vision Syncidian isn't just another file synchronization tool. The long-term goal is to make synchronization almost invisible. ```mermaid flowchart TB AI["AI tools
Claude Β· Gemini Β· agents"] -->|"MCP"| Server Win["Obsidian Windows"] <--> Server Mac["Obsidian macOS"] <--> Server And["Obsidian Android"] <--> Server iOS["Obsidian iOS"] <--> Server Server["Syncidian server
Sync + Git + MCP + Auth + Dashboard"] --> GH["Per-user private GitHub repo
optional source of truth"] ``` Eventually, Syncidian should be able to detect a conflict, have a small LLM resolve it automatically, validate the result, commit it to GitHub, and propagate the resolution to every device. > **Let AI handle the boring conflicts. Let humans handle the important ones.** --- # πŸ—ΊοΈ App workflow The public site is a one-pager. Hosted visitors join a waitlist and sign in with GitHub (hidden until the app name is tapped six times, allowlisted via `SYNCIDIAN_GITHUB_ALLOWED_EMAILS` until public launch). Self-hosted visitors sign in with email. Operators use a private hostname (`SYNCIDIAN_ADMIN_HOST`) or an unlisted path (`SYNCIDIAN_ADMIN_PATH`, default `/admin`) to create the first admin. ```mermaid flowchart TD Open["Open dashboard URL"] --> Land["Public landing: what Syncidian is"] Land --> Wait["Hosted: join the waitlist"] Land --> Email["Self-host: email signup or login"] Land --> GHSign["Hosted: GitHub sign-in hidden until app name tapped 6 times"] Ops["Private operator host or unlisted path"] --> First{"Any users yet?"} First -->|no| Admin["Create first admin"] First -->|yes| AdminLogin["Admin sign in"] Admin --> Ready["Optional: register GitHub App"] AdminLogin --> Ready Ready --> Users["Optional: create vault users"] Email --> Role{"Who signed in?"} GHSign --> Role{"Who signed in?"} Role -->|admin| AdminHome["Operator dashboard β€” no vault"] Role -->|user| UserHome["User dashboard"] UserHome --> Repo["Optional: install GitHub App
one repo for this user Β· main"] UserHome --> Tok["Create sk_sync_ token"] Tok --> Plug["Install plugin
Community plugins Β· desktop Β· Android Β· iOS"] Plug --> Sync["Devices sync through the server"] Repo --> Backup["Server commits/pushes that user's vault"] ``` When this workflow changes, update this diagram, [`docs/architecture.md`](docs/architecture.md), and follow [`AGENT.md`](AGENT.md). --- # πŸ—οΈ Architecture Syncidian separates the system into four major components. GitHub renders the chart below; full sync, auth, MCP, and data-model diagrams live in [`docs/architecture.md`](docs/architecture.md). ```mermaid flowchart TB Plugin["Obsidian plugin
desktop + Android + iOS"] -->|"requestUrl HTTPS / WS or poll"| SyncSrv subgraph SyncSrv [Syncidian server] Sync[Sync engine] Auth[Authentication] Devices[Device management] Git[Git integration] MCP[MCP server] Conflicts[Conflict resolution] Dash[Web dashboard] end SyncSrv --> GitHub["Per-user GitHub repo
after login"] SyncSrv -.->|"planned"| LLM["Small LLM
conflict resolver"] ``` --- # πŸ”Œ Obsidian Plugin Syncidian lives inside Obsidian as a plugin. There is no separate sync application that the user needs to manually operate. The plugin handles: * Detecting vault changes * Sending changes to the Syncidian server * Fetching changes * Registering the device * Detecting conflicts * Showing conflict resolution UI * Connecting to MCP * Reporting client status * Reporting synchronization state The user configures the plugin once. After that, Syncidian works automatically in the background. --- # πŸ’» Supported Platforms Syncidian is designed to work wherever Obsidian plugins are supported. ### Desktop * πŸͺŸ Windows * 🍎 macOS * 🐧 Linux ### Mobile * πŸ€– Android * πŸ“± iOS The plugin is **not** desktop-only. It uses the Obsidian Vault API and `requestUrl` so it loads on phones; Git community plugins that depend on Node or a local `git` binary cannot. On Android and iOS, leave **Syncidian.com** selected or point **Custom Domain** at a public HTTPS server (not `localhost`). Enable steps: [`docs/install-mobile.md`](docs/install-mobile.md). The goal is to maintain one consistent synchronization experience across all supported platforms. --- # βš™οΈ Setup Syncidian is designed around a **server-first configuration model**. The Obsidian plugin should require as little configuration as possible. ## 1. Deploy Syncidian Server Run Syncidian on your own infrastructure. The simplest deployment is Docker Compose from this repository: ```bash docker compose up --build -d ``` Equivalent one-container flow: ```bash docker build -t syncidian . docker run -d \ --name syncidian \ -p 8080:8080 \ -v syncidian-data:/data \ syncidian ``` That container is the complete Syncidian server: * API * Sync engine * Authentication * GitHub integration * MCP server * Web dashboard * Device management * Conflict resolution * Health checks No separate services are required for a basic deployment. --- # πŸ™ Configure GitHub GitHub identity lives on the public site. GitHub **backup** is still **per user**, not a shared vault. **Self-hosting?** Use the full walkthrough: **[Set up the GitHub App](docs/github-app.md)**. That page is the operator README for creating the app, filling GitHub’s callback / setup / webhook URLs, and wiring credentials. The public landing never asks for a repository name. It sends people through GitHub OAuth, then the GitHub App setup URL. The Obsidian plugin does not need GitHub credentials. Admin login at `/admin` registers the instance App and does not connect a vault repo. ## Create the GitHub App You need one App **per Syncidian instance**, not per vault user. ### From the dashboard (recommended) 1. Deploy Syncidian so `{base}` is the URL you will keep (`https://syncidian.example.com` or `http://localhost:8080`). 2. Open `{base}/admin` and create the first admin. 3. Click **Create GitHub App**. GitHub opens with permissions and URLs already filled in. 4. Click **Create GitHub App** on GitHub. You return to `/admin` with the app **Registered**. ### By hand 1. [New GitHub App](https://github.com/settings/apps/new). 2. Paste the three URLs below (also listed on `/admin` and `GET /api/v1/github/app/urls`). 3. Repository permissions: **Contents** read and write, **Metadata** read. Account permissions: **Email addresses** read. 4. Enable **Request user authorization (OAuth) during installation**. 5. If other GitHub users on this instance must install the app on their own accounts, allow installation on **Any account**. 6. Copy App ID, slug, Client ID, a new client secret, and a generated private key (`.pem`). 7. Set `SYNCIDIAN_GITHUB_APP_ID`, `SYNCIDIAN_GITHUB_APP_SLUG`, `SYNCIDIAN_GITHUB_CLIENT_ID`, `SYNCIDIAN_GITHUB_CLIENT_SECRET`, and `SYNCIDIAN_GITHUB_APP_PRIVATE_KEY`, then restart. Put literal `\n` in the PEM env value for newlines. Then each vault user signs in from `/` and installs the app on one repository (`main` only). Details, localhost notes, and a failure checklist are in [docs/github-app.md](docs/github-app.md). ## GitHub App URLs When you create the GitHub App (from `/admin` β†’ **Create GitHub App**, or by hand), GitHub asks for these. Open this instance at its public hostname and copy them from the admin page, or from `GET /api/v1/github/app/urls`. Replace `{base}` with your public URL, for example `https://syncidian.example.com`: | GitHub field | URL | Why | | --- | --- | --- | | **Callback URL** / User authorization callback URL / redirect URI | `{base}/api/v1/auth/github/callback` | GitHub sends people here after **Sign in with GitHub**, and after **Install & Authorize** when OAuth during installation is enabled. Syncidian binds `installation_id` here in that case. | | **Setup URL** | `{base}/api/v1/github/app/setup` | Used when OAuth during installation is off. GitHub sends people here after they **install** the app so Syncidian can bind that installation. | | **Webhook URL** | `{base}/api/v1/github/app/webhook` | GitHub requires a webhook URL so it can **ping** the app when you create or update it. Syncidian answers that ping with HTTP 200 even if you do not subscribe to extra events. | Optional env vars if you prefer not to use the in-dashboard manifest flow: `SYNCIDIAN_GITHUB_APP_ID`, `SYNCIDIAN_GITHUB_APP_SLUG`, `SYNCIDIAN_GITHUB_CLIENT_ID`, `SYNCIDIAN_GITHUB_CLIENT_SECRET`, `SYNCIDIAN_GITHUB_APP_PRIVATE_KEY`. See [docs/github-app.md](docs/github-app.md) for exact GitHub UI fields and Docker examples. Rules: * **Public landing, private operator surface.** Create the first admin at `SYNCIDIAN_ADMIN_HOST` (Tailscale) or `SYNCIDIAN_ADMIN_PATH` (default `/admin`). Self-hosted vault users sign in with email from `/`. The GitHub App is optional. On hosted Syncidian.com, GitHub sign-in is hidden until the app name is tapped six times and limited by `SYNCIDIAN_GITHUB_ALLOWED_EMAILS`. * **One repository per user.** `github_config` is keyed by `user_id`. * **GitHub App only.** Connect with GitHub, install on a repository, Contents read and write. No personal access tokens and no deploy keys. * **Main branch only.** Syncidian always uses `main`. * **Admin does not need repo sync.** Admins only manage users (username + role) and the instance App. They do not see vaults, tokens, activity, or per-user GitHub credentials. * **Optional backup.** Devices still sync through the server if a user has not connected GitHub. ```mermaid flowchart LR Land["Public landing"] --> OAuth["GitHub OAuth callback"] OAuth --> User["store.User"] Admin["/admin"] --> Manifest["Create GitHub App"] Manifest --> URLs["callback Β· setup Β· webhook"] User --> Install["Install and Authorize"] Install --> Callback["Callback with installation_id"] Install --> Setup["Setup URL when no OAuth-on-install"] Callback --> Map["Store installation_id + repo for that user_id"] Setup --> Map Map --> Git["Server git commit / push on main"] Git --> Repo["That user's private repo"] ``` ```text Syncidian Server β”œβ”€β”€ Admin β€” manage users only β”œβ”€β”€ User A β€” one GitHub repo └── User B β€” one GitHub repo ``` This keeps GitHub credentials on the server and scoped to the account that entered them. --- # πŸ‘€ Create a User The Syncidian server can support multiple users. Each user can have: * Multiple devices * Access tokens * A configured vault * A GitHub repository * Synchronization history Example: ```text Syncidian Server User A β”œβ”€β”€ Windows β”œβ”€β”€ macOS └── Android User B β”œβ”€β”€ Windows └── iOS User C └── macOS ``` Users are isolated from one another. --- # πŸ”‘ Access Tokens Once a vault user exists, the server generates an access token. ```text sk_sync_******************************** ``` The token is used by the Obsidian plugin to authenticate with the Syncidian server. Create one from the user’s **Tokens** page, or as an admin via **Users β†’ Create Obsidian token** (shown once). Admins cannot use tokens themselves. The token should provide access only to the user's configured resources. Future authentication options may include: * Personal access tokens * Device-specific tokens * Token rotation * Token revocation * OAuth * Passkeys * SSO --- # πŸ”Œ Configure the Obsidian Plugin Install **Syncidian** from Community plugins (or BRAT / sideload), then open Settings β†’ Syncidian. The plugin configuration should remain intentionally small: ```text Syncidian ──────────────────────────────── Server Syncidian.com Custom Domain Custom domain https://sync.example.com (enabled when Custom Domain is selected) Access Token β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’β€’ Device Name MacBook Pro Connect Status: ● Connected ``` The client does **not** require: * GitHub credentials * GitHub repository configuration * Git credentials * Manual Git commands --- # πŸš€ Activate Once the plugin authenticates successfully: 1. Register the device. 2. Connect to the Syncidian server. 3. Identify the user's sync group. 4. Check the current source of truth. 5. Determine local changes. 6. Fetch required changes. 7. Start monitoring the vault. 8. Begin synchronization. Repeat the process on other devices. --- # πŸ”„ Synchronization The Syncidian server is the **coordination layer**. GitHub is the **primary source of truth**. ```mermaid flowchart TB GH["GitHub β€” source of truth"] Srv["Syncidian server"] GH <-->|"Git"| Srv Srv --> Win["Windows Obsidian"] Srv --> Mac["macOS Obsidian"] Srv --> And["Android Obsidian"] Srv --> iOS["iOS Obsidian"] ``` The server coordinates changes between clients and synchronizes the durable state with GitHub. --- # πŸ“ Editing a Note When a user edits a note: ```mermaid flowchart TD Edit[Edit note] --> Plugin[Obsidian plugin] Plugin -->|Detect change| Srv[Syncidian server] Srv --> Other["Other devices
WS or manifest poll"] Srv --> GH[GitHub] GH --> SoT[Source of truth] ``` The user does not need to manually: * Commit * Push * Pull * Refresh * Trigger sync The plugin handles this automatically. Edits are queued until typing stops, then pushed after a 3 second idle. Simple replacements merge on their own; large conflicts still open a resolver. Deleting or moving a folder (or file) is synced as a Git delete or rename so a later sync does not restore the old path. --- # πŸš€ Opening Obsidian Whenever Obsidian starts: ```text Open Obsidian β”‚ β–Ό Syncidian Plugin Starts β”‚ β–Ό Authenticate β”‚ β–Ό Connect to Syncidian β”‚ β–Ό Check GitHub β”‚ β–Ό Compare Local State β”‚ β–Ό Fetch / Merge / Sync β”‚ β–Ό Vault Ready ``` Coming back to an already-open vault (switching apps, focusing the window, or bringing the phone app to the foreground) also polls the server and pulls any notes that arrived while Obsidian was in the background. The goal is: > **Open Obsidian and start working.** Synchronization should happen automatically in the background. --- # βš”οΈ Conflict Resolution Conflicts happen when the same file is modified on multiple devices before synchronization completes. Syncidian should never silently overwrite user data. The first version can provide an Obsidian-native conflict UI. ```text β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ⚠️ Sync Conflict β”‚ β”‚ β”‚ β”‚ "Project Ideas.md" was modified on β”‚ β”‚ another device. β”‚ β”‚ β”‚ β”‚ Local version Remote version β”‚ β”‚ ───────────── ───────────── β”‚ β”‚ Modified 10:32 Modified 10:34 β”‚ β”‚ β”‚ β”‚ Keep Local Keep Remote β”‚ β”‚ β”‚ β”‚ Merge β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` Users can: * Keep Local * Keep Remote * Review differences * Merge manually * Resolve later --- # 🧠 AI-Assisted Conflict Resolution A major future goal is to make merge conflicts almost invisible. Instead of requiring the user to manually resolve every conflict, Syncidian can use a **small LLM** running alongside the Syncidian server. ```text Device A β”‚ β”‚ Change β–Ό Syncidian Server β”‚ β”‚ Conflict detected β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Conflict Resolver β”‚ β”‚ β”‚ β”‚ Small LLM β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Local Version β”‚ β”‚ Remote Version β”‚ β”‚ Git History β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό Resolved File β”‚ β–Ό Validation β”‚ β–Ό GitHub Commit β”‚ β–Ό Other Devices ``` ## How it works When a conflict occurs: 1. Syncidian detects the conflict. 2. The server collects the relevant versions. 3. The conflict resolver sends the required context to a small LLM. 4. The model proposes a merged version. 5. Syncidian validates the result. 6. If confidence is high enough, the server commits the result. 7. The resolved state is propagated to other devices. 8. If the conflict is ambiguous, the user is asked to resolve it manually. --- # πŸ‘€ Human-in-the-Loop AI should not blindly overwrite important information. ```text Conflict β”‚ β–Ό Small LLM Resolver β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ High confidence Ambiguous β”‚ β”‚ β–Ό β–Ό Auto-resolve User review β”‚ β”‚ β–Ό β–Ό GitHub Obsidian UI ``` The goal is: > **Let AI handle the boring conflicts. Let humans handle the important ones.** --- # πŸ€– MCP Server Syncidian includes a built-in **Model Context Protocol (MCP) server**. This provides a controlled interface between your Obsidian knowledge base and AI tools (Cursor, Claude, and other MCP clients). ```mermaid flowchart TB Tools["AI tools
Cursor Β· Claude Β· agents"] -->|"Bearer token or login"| MCP["Syncidian MCP server"] MCP --> Vault["Obsidian vault"] MCP --> Graph["Wikilink graph"] ``` **Authenticate** with a dashboard access token (`Authorization: Bearer sk_sync_…`), a dashboard session cookie, or `POST /api/v1/mcp/login` with username/password to mint a token. Capabilities: * Search and list notes * Read notes and append under headings * Create and update notes * Wikilink backlinks and outgoing links * Vault graph as JSON + Mermaid for visualization * Suggest where to store ideas (`suggest_note_path`) and find related notes * Bulk move / bulk link for organizing the vault Permissions default to search + read. Enable create/modify in **Dashboard β†’ MCP / AI**. --- # 🧠 Your Knowledge, Connected to AI An Obsidian vault can contain years of: * Ideas * Projects * Research * Documentation * Meeting notes * Technical knowledge * Personal notes Syncidian makes that knowledge available to AI through MCP. Instead of permanently moving your knowledge into an AI platform, Syncidian provides a bridge between your local knowledge and the AI tools you choose. > **Your knowledge stays yours. AI comes to your knowledge.** --- # πŸ” MCP Permissions AI access should be independently controllable. Example: ```text MCP Permissions β˜‘ Search notes β˜‘ Read notes ☐ Create notes ☐ Modify notes ``` Future controls can include: * Read-only access * Read/write access * Tool-level permissions * Vault-level permissions * Client-level permissions * AI client authentication * Token revocation The default configuration should follow **least privilege**. --- # πŸ“Š Web Dashboard Syncidian includes a lightweight web dashboard. The dashboard answers: > **What is happening with my devices?** Example: ```text β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Syncidian β”‚ β”‚ β”‚ β”‚ DEVICES β”‚ β”‚ β”‚ β”‚ ● MacBook Pro macOS Active β”‚ β”‚ ● Pixel 10 Android Active β”‚ β”‚ ● Windows Desktop Windows Active β”‚ β”‚ β—‹ iPhone iOS Offline β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ SYNC ACTIVITY β”‚ β”‚ β”‚ β”‚ Total Syncs 1,248 β”‚ β”‚ Files Synced 6,482 β”‚ β”‚ Last Sync 2 min ago β”‚ β”‚ Active Clients 3 β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Dashboard capabilities The dashboard should provide: * Active clients * Offline clients * Device list * Platform * Last seen * Last successful sync * Number of syncs * Files synchronized * Recent sync activity * Server health The dashboard is for monitoring and management, not editing the vault. --- # πŸ‘₯ Multi-User Server A single Syncidian server can support multiple users. ```text Syncidian Server β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β–Ό β–Ό β–Ό User A User B User C β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”Όβ”€β”€β”€β” β”Œβ”€β”€β”€β”Όβ”€β”€β”€β” β”Œβ”€β”€β”€β”Όβ”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Win Mac Android Win Mac iOS Mac Linux Android ``` Each user is isolated. A user can only see their own: * Devices * Clients * Sync activity * Tokens * Repository configuration * Vault synchronization --- # πŸ“± Device Management A user can connect multiple Obsidian installations. Example: ```text My Devices ● MacBook Pro macOS Active ● Windows Desktop Windows Active ● Pixel Android Active β—‹ iPhone iOS Offline ``` The server tracks: * Device name * Platform * Plugin version * Connection status * Last active time * Last successful sync * Sync count --- # πŸ”‘ Authentication Syncidian uses access tokens to authenticate Obsidian clients. ```text Server: Syncidian.com (default) or Custom Domain: https://sync.example.com Access Token: sk_sync_******************************** ``` Tokens should be: * Revocable * Scoped * Rotatable * Associated with users/devices Future authentication options: * Personal access tokens * Device-specific tokens * OAuth * Passkeys * SSO --- # πŸ” Security & Privacy Syncidian is designed around several principles. ### Encrypted communication Client-to-server communication should use encrypted channels. ### GitHub credentials stay on the server, per user Obsidian clients never need direct GitHub credentials. Each user connects at most one GitHub App installation and repository. Those values are never returned to admins. ### User isolation Multiple users can safely share a Syncidian server. Admin APIs list public account fields only (`id`, `username`, `is_admin`, `created_at`). Vault files, tokens, activity, devices, MCP permissions, and GitHub config are always loaded by the authenticated `user_id`. ### Least privilege Clients and AI tools should only receive required access. ### User-controlled infrastructure Self-hosted users control their Syncidian server. ### Git-backed durability GitHub provides durable versioned storage. ### Minimal relay persistence The synchronization layer should avoid becoming a permanent storage location for vault data. > **Security is still under active development. Do not use early builds for highly sensitive or critical vaults until the implementation and security model have been reviewed.** --- # πŸ› οΈ Technology The initial architecture is intentionally simple. ### Server **Go** Go is a good fit for: * Lightweight deployment * Excellent concurrency * Small container images * Simple networking * Easy cross-platform builds * Long-running services ### Client **Obsidian Plugin** The client integrates directly with the Obsidian vault and lifecycle. ### Storage / Source of Truth **Git + GitHub** Private repositories provide durable, versioned vault storage. ### AI **MCP + Small LLM** MCP provides the interface to AI tools. A small LLM can eventually provide automated conflict resolution. ### Deployment **Docker** The server should ideally be deployed as a single container. --- # 🐳 Docker The repository should contain a simple Dockerfile. Example: ```dockerfile FROM golang:alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build \ -o syncidian ./cmd/syncidian FROM alpine:latest WORKDIR /app COPY --from=builder /app/syncidian /app/syncidian EXPOSE 8080 ENTRYPOINT ["/app/syncidian"] ``` The exact build configuration may evolve. The important goal is: > **Clone β†’ Build β†’ Run.** --- # 🏠 Self-Hosted Syncidian is completely free to self-host. A basic installation can provide the entire system: ```text β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Syncidian Server β”‚ β”‚ β”‚ β”‚ Sync Engine β”‚ β”‚ GitHub Integration β”‚ β”‚ MCP Server β”‚ β”‚ Web Dashboard β”‚ β”‚ Authentication β”‚ β”‚ Device Management β”‚ β”‚ Conflict Resolver β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Cost **$0 for the Syncidian software.** You only pay for your own infrastructure. This could be: * Existing VPS * Home server * Raspberry Pi * Cloud VM * Docker host * Local infrastructure GitHub sign-in and backup need a GitHub App for this instance. Operators follow [Set up the GitHub App](docs/github-app.md) after `/admin` first-boot. --- # 🌐 Hosted Syncidian Don't want to manage your own server? A managed Syncidian service is in development. It is not for sale yet. ### Planned pricing > **Starting at $1/month** The hosted service will provide: * Managed infrastructure * GitHub integration * Web dashboard * Monitoring * Server maintenance * Multi-device management * Easier setup The self-hosted version will remain free and open source. --- # 🧩 Feature Roadmap ## πŸ”„ Sync Engine * [x] Obsidian plugin * [x] File change detection * [ ] Encrypted communication * [x] Device registration * [x] Multi-device synchronization * [ ] Offline synchronization * [x] Conflict detection * [x] Conflict resolution UI * [x] Background synchronization ## πŸ™ GitHub * [x] Per-user GitHub configuration (after login; one repo per account; admins do not configure repo sync) * [x] GitHub authentication * [x] Private repository support * [x] User-to-repository mapping (one repo per user) * [x] Admin user management without repo sync or private-data access * [x] Automatic commits * [x] Pull latest changes * [ ] Restore from history * [x] Git conflict handling ## πŸ‘₯ Multi-User * [x] User accounts * [x] User isolation * [x] Multiple devices per user * [x] Access tokens * [x] Device management * [ ] Sync groups ## πŸ“Š Dashboard * [x] Web dashboard * [x] Active clients * [x] Offline clients * [x] Last seen * [x] Last successful sync * [x] Sync count * [x] Files synchronized * [x] Recent activity * [x] Server health ## πŸ€– MCP / AI * [x] Built-in MCP server * [x] Vault search * [x] Read notes * [x] Create notes * [x] Update notes * [x] Related-note discovery * [x] Backlinks and vault graph * [x] Bulk organize tools * [x] Permission management * [x] MCP authentication (token + password login) * [x] Dashboard: connected clients * [x] Dashboard: tool-call frequency * [x] MCP writes go to GitHub, not the server working copy ## 🧠 AI Conflict Resolution * [ ] Conflict extraction * [ ] Small LLM integration * [ ] Merge proposal generation * [ ] Confidence scoring * [ ] Result validation * [ ] Automatic safe merges * [ ] Human fallback * [ ] Local model support * [ ] Ollama-compatible inference * [ ] Configurable AI provider ## πŸ” Authentication * [x] Access tokens * [x] Token revocation * [ ] Token rotation * [ ] Device tokens * [ ] OAuth * [ ] Passkeys ## πŸš€ Deployment * [x] Dockerfile * [x] Single-container deployment * [x] Docker Compose * [ ] Community Plugin directory * [ ] Pre-built container images * [ ] GHCR publishing * [x] VPS deployment guide * [x] Home server deployment * [x] Health checks * [ ] Monitoring ## 🌐 Hosted Service * [ ] Managed infrastructure * [ ] User management * [ ] Device management * [ ] Monitoring * [ ] Billing * [ ] Launch at $1/month --- # πŸ—ΊοΈ Development Phases ### Phase 1 β€” Obsidian Plugin + Core Sync Build the fundamental synchronization experience. ```text Obsidian ↕ Syncidian Server ↕ Obsidian ``` ### Phase 2 β€” GitHub Source of Truth Add Git-backed persistence, version history, recovery, and conflict handling. ### Phase 3 β€” Multi-User Server Allow one Syncidian server to securely serve multiple users and devices. ### Phase 4 β€” Web Dashboard Introduce device monitoring and synchronization statistics. ### Phase 5 β€” MCP / AI Connect Obsidian knowledge to AI tools through MCP. ### Phase 6 β€” Hosted Syncidian Provide a managed experience starting at $1/month. ### Phase 7 β€” AI Conflict Resolution Use small LLMs to automatically resolve safe conflicts and fall back to human review when necessary. --- # πŸ€” Syncidian vs Obsidian Sync | | Syncidian | Obsidian Sync | | ------------------------------- | ----------------- | ------------- | | Open source | βœ… | ❌ | | Self-hosted | βœ… | ❌ | | GitHub backup | βœ… | ❌ | | Git version history | βœ… | ❌ | | Server-side Git configuration | βœ… | β€” | | Multi-user server | βœ… | β€” | | Device dashboard | βœ… | β€” | | Built-in MCP | βœ… | ❌ | | AI knowledge bridge | βœ… | β€” | | AI-assisted conflict resolution | 🚧 Planned | β€” | | Hosted service | Planned | βœ… | | Self-hosted cost | **Free** | β€” | | Hosted Syncidian | **From $1/month** | β€” | Syncidian isn't trying to reproduce every feature of Obsidian Sync. It takes a different approach: > **The plugin is the client. Syncidian is the coordination layer. GitHub is the source of truth. MCP connects your knowledge to AI.** --- # πŸ’‘ Philosophy Syncidian is built around four principles. ### 1. Sync should be lightweight The sync server coordinates devices instead of becoming another permanent copy of your vault. ### 2. Storage should be yours Git provides transparent version history, recovery, and change tracking. ### 3. AI should come to your knowledge Your knowledge base shouldn't need to be permanently copied into every AI platform. ### 4. Self-hosting should be accessible Running your own Syncidian instance should be simple enough for anyone comfortable with Docker. --- # 🚧 Project Status **Syncidian is currently under active development.** The architecture, synchronization protocol, plugin implementation, Git integration, dashboard, and MCP interface may change significantly before the first stable release. The initial milestone is a reliable self-hosted synchronization experience with: * Obsidian plugin * Multi-device synchronization * Server-side GitHub integration * GitHub as the source of truth * Conflict resolution * Multi-user support * Basic web dashboard * Docker deployment AI/MCP capabilities will be developed alongside the core synchronization system. AI-assisted conflict resolution is a longer-term goal. **Do not use early builds for critical or highly sensitive vaults.** --- # 🀝 Contributing Syncidian is open source and contributions are welcome. You can contribute through: * Code * Architecture discussions * Bug reports * Documentation * Testing * Security reviews * Feature proposals * Platform-specific improvements Contribution guidelines will be added as the project matures. --- # β˜• Support [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-FFDD00?logo=buymeacoffee&logoColor=black)](https://buymeacoffee.com/shravzdev) If Syncidian is useful, you can [buy me a coffee](https://buymeacoffee.com/shravzdev). The repo also lists that link on GitHub’s Sponsor button. --- # πŸ“„ License Syncidian is licensed under the **MIT License**. You are free to use, modify, distribute, and self-host Syncidian, including for commercial purposes, subject to the terms of the MIT License. See [`LICENSE`](LICENSE) for the full license text. ---

Syncidian
Your data stays with you.