No description
  • TypeScript 84.5%
  • JavaScript 8.6%
  • Shell 3.2%
  • CSS 3.1%
  • HTML 0.4%
  • Other 0.2%
Find a file
Cedric Lau 27c889ce5b
All checks were successful
CI / build (push) Successful in 4m14s
CI / e2e (push) Successful in 3m28s
CI / promote (push) Successful in 21s
Point the registry at the Forgejo server's new name
The instance moved off DuckDNS to repositron.nerchure.com, a name we control
in Cloudflare. Only the endpoint hostname changes: the registry stores
packages by owner and name, so hosts still pulling the old name resolve the
same manifests until their compose files are updated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 16:11:20 +01:00
.forgejo Point the registry at the Forgejo server's new name 2026-09-15 16:11:20 +01:00
deploy Point the registry at the Forgejo server's new name 2026-09-15 16:11:20 +01:00
docs Point the registry at the Forgejo server's new name 2026-09-15 16:11:20 +01:00
packages Let the server know which plugin is calling, and refuse one too old 2026-09-15 15:09:06 +01:00
scripts Give the plugin's settings the brand, and make signing out a sign-in screen 2026-09-13 19:00:36 +01:00
site Stop calling it relaying, and stop the two sentences echoing each other 2026-09-13 16:35:33 +01:00
.dockerignore Stage 0: configuration, trusted proxies, drained shutdown, probes, the deploy tree 2026-09-09 20:56:03 +01:00
.gitignore Give every host a deployer that follows :stable on its own 2026-09-15 09:37:15 +01:00
CLAUDE.md Bound the backup bucket's versions, and say why restic needs none 2026-09-11 09:40:47 +01:00
docker-compose.yml Stage 0: configuration, trusted proxies, drained shutdown, probes, the deploy tree 2026-09-09 20:56:03 +01:00
Dockerfile Make a deploy provable, refusable, and quick to recover from 2026-09-15 09:10:52 +01:00
eslint.config.mjs Give every host a deployer that follows :stable on its own 2026-09-15 09:37:15 +01:00
LICENSE Name the licensor correctly, and stop pointing at a repo that 404s 2026-09-02 16:49:47 +01:00
package.json Stop the unit gate failing at random before it becomes the deploy gate 2026-09-15 10:08:17 +01:00
pnpm-lock.yaml Give every host a deployer that follows :stable on its own 2026-09-15 09:37:15 +01:00
pnpm-workspace.yaml Give every host a deployer that follows :stable on its own 2026-09-15 09:37:15 +01:00
README.md Stage 0: configuration, trusted proxies, drained shutdown, probes, the deploy tree 2026-09-09 20:56:03 +01:00
tsconfig.base.json Add Phase 0 scaffold: pnpm monorepo with server, plugin, and shared packages 2026-03-24 14:58:20 +00:00
vitest.shared.ts Measure coverage, and say what the number does not mean 2026-09-02 11:21:41 +01:00

Nectenda

End-to-end encrypted real-time collaboration for Obsidian.

Nectenda gives you real-time multi-user collaborative editing — live cursors, offline editing, shared folders and attachments — on a server that cannot read your notes. Content is encrypted on your device before it is sent; the server stores ciphertext it has no key for, and even the document paths are HMACs rather than filenames.

The plugin's source is published and ships as readable, never-minified JavaScript, so that claim is one you can check rather than one you have to believe. See what the server can and cannot see.

A managed service is coming at nectenda.com. Self-hosting is available on Business and Enterprise plans, for teams whose policy requires that the metadata never leaves their network either.

Features

  • Real-time collaborative editing — multiple users edit the same Markdown file simultaneously with live cursor positions
  • CRDT-based sync — conflict-free merging via Yjs, works offline and reconciles on reconnect
  • Folder sharing — share any vault folder; file creates, renames, and deletes propagate to all users
  • Self-hostable — run your own server and your notes never leave your infrastructure
  • Presence & cursors — see who's online and where they're editing with colored remote cursors
  • Admin controls — invite-only registration, user management, shared folder management
  • Single Docker command — up and running in under a minute

Hosted Service

If you'd rather not manage a server, a hosted version of Nectenda is coming soon. Sign up for early access at nectenda.com — same features, zero setup.

Network Use and Accounts

Nectenda is a client-server plugin. It will not work offline-only, and it requires an account. This section states exactly what leaves your machine, because there are two very different deployment modes.

An account is required. In both modes below you register and log in against a Nectenda server before anything syncs. Registration is invite-only — a server admin issues you a token. Credentials are stored on that server (bcrypt-hashed); the plugin holds only a JWT.

The plugin connects to exactly one server: the one you point it at. There is no telemetry, no analytics, and no third-party service of any kind. The server URL is something you enter yourself in settings; the plugin never contacts a hard-coded endpoint.

Mode 1 — Managed hosting at nectenda.com

The server is operated by us, and it cannot read your notes. Content is encrypted on your device before it is sent; the server stores ciphertext it has no key for. Document paths are HMACs rather than filenames, so it does not learn your folder structure either. Keys are derived from your password on your device and never reach the server.

What it does see: which accounts share which folders, update sizes and timings, device records, and the display name you give a shared folder. That list is exhaustive and explained in the security model, which is written to be checked against the plugin source rather than believed.

Mode 2 — Self-hosted (Business and Enterprise plans)

You run the server on your own infrastructure, shipped as a licensed container image. Nothing reaches us at all — not the ciphertext, and not the metadata above.

Most people do not need this. On the managed service we already cannot read your content, so self-hosting is not what buys you privacy of your notes; it is what buys you privacy of the metadata, which matters when policy or jurisdiction demands it.

Both modes run the same encryption. Choosing managed hosting does not mean trusting us with your notes — that is the entire point of the design, and the full account of its limitations is in the security model and docs/sync-limitations.md.

Quick Start (Docker)

docker run -d \
  --name nectenda \
  -p 1234:1234 \
  -v nectenda-data:/app/data \
  -e JWT_SECRET="your-secret-key-here" \
  -e ADMIN_USERNAME="admin" \
  -e ADMIN_PASSWORD="your-admin-password" \
  nectenda/nectenda

See docs/self-hosting.md for detailed deployment instructions including reverse proxy setup.

Plugin Installation

  1. Build the plugin: pnpm install && pnpm -r build
  2. Copy packages/plugin/main.js, packages/plugin/manifest.json, and packages/plugin/styles.css to your vault's .obsidian/plugins/nectenda/ directory
  3. Enable "Nectenda" in Obsidian Settings → Community Plugins
  4. Configure your server URL and log in

Development

Prerequisites

  • Node.js 22+
  • pnpm 10+

Setup

git clone <repo-url>
cd nectenda
pnpm install

Dev Server

# Set required env vars
export JWT_SECRET="dev-secret"
export ADMIN_USERNAME="admin"
export ADMIN_PASSWORD="admin"
export SQLITE_PATH="$(pwd)/data/docs.db"
mkdir -p data

# Start the server (with hot reload)
pnpm dev:server

Dev Plugin

# Build plugin and watch for changes
pnpm dev:plugin

The plugin builds to packages/plugin/main.js. Symlink or copy it to your test vault's plugin directory.

Project Structure

packages/
  shared/    — Types, constants, helpers shared between server and plugin
  server/    — WebSocket sync server + REST API + SQLite
  ops-common/— Logging, rate limiting, readiness, shutdown: shared by the server and the identity service
  plugin/    — Obsidian plugin (CM6 extensions, sync, file operations)

Architecture

  • Server: Custom Yjs WebSocket sync server (built on ws) with SQLite persistence
  • Plugin: Obsidian plugin using CodeMirror 6 extensions for collaborative editing
  • Sync: Yjs CRDTs for document content + Y.Map meta documents for file operations
  • Auth: JWT tokens, bcrypt password hashing, invite-token registration

Environment Variables

The ones every deployment sets. The full list, with defaults and what each one does, is in docs/self-hosting.md; the server prints its effective configuration (secrets redacted) at boot.

Variable Required Default Description
JWT_SECRET Yes Secret for session tokens (openssl rand -hex 32). The server refuses to start without one.
ADMIN_USERNAME No Auto-create admin user on first run
ADMIN_PASSWORD No Password for auto-created admin
PORT No 1234 Server listen port
HOST No 0.0.0.0 Bind address; 127.0.0.1 behind a proxy
SQLITE_PATH No ./data/docs.db Path to SQLite database
DATA_DIR No ./data Attachments and backups
TRUSTED_PROXIES No Proxies whose X-Forwarded-For is believed
LOG_LEVEL No info Minimum log level: debug, info, warn, error

FAQ

Why choose Nectenda over Obsidian Sync? Obsidian Sync ($4-5/month) is excellent for syncing your vault across devices, but it doesn't offer real-time collaborative editing with live cursors — it syncs files, not keystrokes. Nectenda is built specifically for real-time collaboration, and keeps the end-to-end encryption you would expect from Sync while adding it. That said, Obsidian Sync is well worth considering — paying for it directly supports the team behind Obsidian, the tool we all love and build on top of.

Why is the plugin's source published but the server's not? Because that is where the security actually lives. Every guarantee Nectenda makes is enforced on your device before anything is sent, so the plugin is the part worth reading — and it ships as the exact JavaScript that runs, unminified, on your own disk. No compiled binary, no reproducible-build argument to take on faith. The server relays ciphertext it has no key for; publishing it would prove little, since nobody can verify which build an operator is actually running. This is the same split Threema uses. What we owe you in return is the security model, written plainly enough to check against the plugin source.

To be precise about the word: the plugin is source-available, not open source. The licence lets you read it, audit it, modify it and use it for anything — including commercially — but not build a product that competes with Nectenda. Publishing it was always about letting you verify the encryption, and that is untouched.

Does it work offline? Yes. Nectenda uses CRDTs (Yjs) with local IndexedDB caching. You can keep editing while offline — changes merge automatically when you reconnect.

How many users can it handle? Nectenda is designed for individuals and small teams but there's no hard limit. The server is lightweight (Node.js + SQLite) and scales well for typical collaborative editing workloads.

Do I need technical skills to self-host? Basic familiarity with Docker is all you need — self-hosting ships as a container image on Business and Enterprise plans. See the self-hosting guide. Most people should not need it: on the managed service we cannot read your content either way. Self-hosting is for teams whose policy requires that the metadata — who shares what with whom, and when — stays on their own network too.

License

Licensed per package — see LICENSE.

  • Plugin and shared library: PolyForm Shield 1.0.0. Source-available, not open source. Read it, audit it, build it yourself and compare the result to what you installed — all expressly permitted, and the reason it is published at all. Any purpose is permitted except building a product that competes with Nectenda. It holds your keys and does your encrypting, so it is the part you should be able to check.
  • Server: proprietary. It stores ciphertext it cannot read. Self-hosting is offered as a licensed container on Business and Enterprise plans.