No description
  • TypeScript 76%
  • JavaScript 16.9%
  • CSS 3.5%
  • Shell 2.9%
  • PLpgSQL 0.3%
  • Other 0.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Cedric Lau 4f3a999663
All checks were successful
Release note / release-note (pull_request) Successful in 12s
CI / build (pull_request) Successful in 4m51s
CI / e2e (pull_request) Successful in 5m50s
CI / promote (pull_request) Has been skipped
Deploy site / deploy (push) Successful in 50s
CI / build (push) Successful in 5m8s
CI / e2e (push) Successful in 5m22s
CI / promote (push) Successful in 31s
Link the social profiles from the footer, and verify Mastodon with rel="me"
The five profiles close the footer's legal row as glyphs, on every page of
nectenda.com and on the status page. The design is the Nectenda Design
System's Footer section, approved as option A; the glyphs are its
assets/social files, each platform's own mark unaltered, inlined so they
take the footer's tokens.

The Mastodon link carries rel="me" on every page, which is what verifies the
profile's Website and Changelog fields. The status page draws the same
glyphs as masks, embedded like the mark and wordmark so they survive the
site being down, and a test holds its links to the site's SOCIAL list.

Task: NEC-154

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StURdiv33xnMfE2XRyg8Lt
2026-09-29 17:16:26 +01:00
.forgejo Declare the previous-release pass with its own flag, not the plugin dir 2026-09-29 00:24:42 +01:00
.vscode Give each agent slot a session: a plugin, a skill, and a terminal that stays 2026-09-23 19:52:54 +01:00
brand Link the social profiles from the footer, and verify Mastodon with rel="me" 2026-09-29 17:16:26 +01:00
deploy Link the social profiles from the footer, and verify Mastodon with rel="me" 2026-09-29 17:16:26 +01:00
docs Let a sign-out with a pushed-out refresh token end the session 2026-09-29 14:37:47 +01:00
eslint-rules Refuse characters that are in the bytes but not on the screen 2026-09-23 08:59:24 +01:00
packages Let a sign-out with a pushed-out refresh token end the session 2026-09-29 14:37:47 +01:00
release-notes Release notes for #188 2026-09-26 20:06:02 +01:00
scripts Shoot Obsidian's plugin browser for the install guide, the last hand-taken shot 2026-09-29 11:31:29 +01:00
site Link the social profiles from the footer, and verify Mastodon with rel="me" 2026-09-29 17:16:26 +01:00
.dockerignore Stage 0: configuration, trusted proxies, drained shutdown, probes, the deploy tree 2026-09-09 20:56:03 +01:00
.gitignore Record every e2e scenario's verdict and duration in a ledger outside CI 2026-09-28 14:51:50 +01:00
CLAUDE.md Stop counting the toolchain pin sites 2026-09-25 17:06:49 +01:00
docker-compose.yml Cap every container's logs, and alert on a rate rather than an event 2026-09-16 07:32:11 +01:00
Dockerfile Move the toolchain to Node 26 and pnpm 12.5.1, and stop repeating a dead claim 2026-09-21 13:35:02 +01:00
eslint.config.mjs Fail lint on a warning nobody accepted, via a register beside the linters 2026-09-27 09:56:35 +01:00
LICENSE Name the licensor correctly, and stop pointing at a repo that 404s 2026-09-02 16:49:47 +01:00
lint-register.json Fail lint on a warning nobody accepted, via a register beside the linters 2026-09-27 09:56:35 +01:00
manifest.json Run the community directory's own rules here, and clear what they find 2026-09-25 21:14:59 +01:00
package.json Parse workflow and action YAML in pnpm lint 2026-09-28 12:14:08 +01:00
pnpm-lock.yaml Parse workflow and action YAML in pnpm lint 2026-09-28 12:14:08 +01:00
pnpm-workspace.yaml Move the toolchain to Node 26 and pnpm 12.5.1, and stop repeating a dead claim 2026-09-21 13:35:02 +01:00
README.md Stop the README saying keys are password-derived and never reach the server 2026-09-28 14:33:41 +01:00
renovate.json Stop counting the toolchain pin sites 2026-09-25 17:06:49 +01:00
stylelint.config.mjs Run the community directory's own rules here, and clear what they find 2026-09-25 21:14:59 +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
  • Invite to a folder — invite someone by email from the folder itself; they get it as soon as they join
  • Admin controls (self-hosted) — 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, the hosted service is live. Install the plugin and sign in; signing in creates your own organisation on the free plan. Prices are at nectenda.com/pricing, and plans are bought inside Obsidian — an account cannot be created for you remotely, because your encryption keys are derived on your own device.

There has never been an early-access signup, and this paragraph promised one until 18 September 2026.

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. Nothing syncs until you sign in. On the hosted service you sign in with a passkey, an emailed code, or Google, Apple or Microsoft, at accounts.nectenda.com; your encryption passphrase is chosen afterwards and never leaves your device. On a self-hosted server registration is invite-only: its admin issues you a token, and credentials are stored on that server (bcrypt-hashed) while the plugin holds only a session token.

The plugin talks to the servers you point it at, and to no third party. There is no analytics and no tracking of what you do. Self-hosted server URLs are ones you enter yourself; signing in to the hosted service uses accounts.nectenda.com, which is the only address the plugin knows without being told.

Crash reports, when signed in to the hosted service and not turned off, go to an error tracker we run ourselves — never a third party. They carry the exception, stack frames as line numbers in our own published file, the plugin and Obsidian versions, the platform, and the install id every request already carries; never note content, names, paths, the vault name, tokens or keys. packages/plugin/src/error-report.ts builds the payload from an allowlist, docs/security-model.md states the rule, and a self-hosted vault sends none because the address comes from the server and a self-hosted one names none. Off in one click under Settings → Nectenda → Troubleshooting.

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. The keys that decrypt your notes never leave your device unencrypted.

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.