Relay feature parity, with end-to-end encryption (tracking) #37

Closed
opened 2026-09-21 18:02:03 +01:00 by cruelacid · 1 comment
Owner

Relay feature parity, with end-to-end encryption

Tracking issue for the parity programme. Every issue below carries a
relay:* label classifying the feature's status at Relay, so this backlog
doubles as a live competitive ledger.

Label Meaning
relay:supported 1 — Relay ships it today
relay:planned 2 — on their roadmap as Active or Planned, or has an open PR
relay:requested 3 — asked for by their users or under "Considering"; not committed
relay:absent 4 — not supported, not requested, not planned at Relay

Risk labels are ours: risk:none (client-only, server untouched),
risk:additive (new message type or table, backward compatible),
risk:contract (changes something existing accounts or stored data depend on).

Why this exists, and what was wrong before it

Relay was last surveyed in docs/competition-relay.md on 1 September 2026.
They shipped 0.8.12 on 9 September. Our own records were stale in both
directions:

  • We credit Relay with role-based access control they do not ship. Their docs
    say read-only access is unsupported; an enableReaderRole flag exists, default
    off. Their marketed "RBAC" is private shared folders — subsetting which
    members may access a folder — which we already have via folder_members.
  • Canvas multiplayer is no longer beta: default-on and free on every tier.
  • New in 0.8.12 and unrecorded by us: disk-edit ingestion for AI agents (their
    headline, with a relay-skills repo for Claude Code), Plugin API v0, Bases
    sync, and Relay-Comments as a separate beta plugin.
  • Continuous background sync reached them only in 0.8.12. We have had it since
    Phase 6
    and no document says so.
  • docs/plan-master.md says Phase 13 is "next, not built", Phase 14 is
    half-built and store submission has not happened. All three are stale — we are
    listed and accumulating downloads, and 13 and 14 are complete.

The two findings that set the sequence

Both verified in code, not assumed.

1. Structured documents need no server change. packages/server/src/doc-store.ts
says in its own header "Nothing in this file interprets payload", and the
code matches: a document is a folder-id prefix, an HMAC'd name, a sequence
counter and opaque bytes. The folder listing is already a Y.Map
(file-sync.ts:109) on the identical encrypted pipeline, and Phase 8 set the
precedent of a second root that older clients replicate without acting on.
So Canvas, Bases, Kanban, frontmatter, comments and change attribution are
client-only work.

2. Nothing requires taking the product offline. The master key is cached
per-device in the OS credential store (docs/security-model.md; main.ts:613),
so the one contract-changing item — a signing keypair — can enrol silently,
with no passphrase prompt
. Separating enrolment from enforcement removes
the deadline entirely: enrol now, decide about enforcement whenever.

What is actually urgent

doc-store.ts:190 deletes doc_updates up to every snapshot, and
doc_snapshots keeps exactly one row per document. With the plugin live,
real users' edit history is being discarded daily and cannot be recovered.
Under this repo's central principle that is closer to a defect than a gap. It is
the first issue in Phase 15 and should ship alone if anything slips.

Sequence

Irreversible first, visible second, large last. Phases 13 and 14 are done, so
none of this competes with a launch path.

Milestone Theme Rough size
Phase 15 Retention and enrolment ~3 wk
Phase 16 The plugin becomes a plugin 3–4 wk
Phase 17 Structured documents 6–8 wk
Phase 18 Agents and headless 8–10 wk
Phase 19 Review and history 7–9 wk
Phase 20 Enterprise, on demand 2–3 wk

Roughly 32–42 developer-weeks to broad parity.

One finding worth stating plainly

Category 4 is nearly empty. Almost nothing we could build is novel to this
category — Relay either ships it or has been asked for it. The encryption is the
exception, and it is the whole position. Per docs/positioning.md: lead with the
server that cannot read your notes, and never compete on licence terms.

Open question

Self-hosting pricing. Relay gives self-hosting free on every tier and
markets it as "we don't charge for privacy". We gate it behind a licence at
Business/Enterprise (Phase 12). Since our whole position is privacy, charging for
the deployment mode they give away is the one place our pricing reads worse than
theirs on our strongest ground. Matching them costs no engineering — it deletes
Phase 12.


Relay data read 21 September 2026 from relay.md, docs.relay.md,
github.com/No-Instructions/Relay (README, manifest, flags.ts, issues, PRs) and
their roadmap. Re-fetch rather than trusting this summary; it will drift.


The backlog

Classification is at Relay: 1 relay:supported · 2 relay:planned ·
3 relay:requested · 4 relay:absent.

Phase 15 — Retention and enrolment (urgent; history is being lost now)

  • #38 Checkpoint writer: stop discarding edit history — 2
  • #39 Signing keypair enrolment (silent; enforces nothing) — 2
  • #73 plan-master.md misstates Phases 10, 13, 14 and the store listing
  • #74 positioning.md / competition-relay.md credit Relay with RBAC they do not ship
  • #75 Refresh the Relay snapshot to 0.8.12
  • #76 Walk the stale gates in launch-readiness.md

Phase 16 — The plugin becomes a plugin

  • #40 Command palette commands and a ribbon icon — 1
  • #41 Status icons and a sync-state inspector — 1
  • #42 Conflict differ UI — 1
  • #43 Follow a collaborator's viewport — 3

Phase 17 — Structured documents

  • #44 A structured file kind beside text and blob — 1 (prerequisite)
  • #45 Canvas structural merge over disk — 1
  • #46 Canvas live in-view multiplayer — 1 (separate decision)
  • #47 Bases (.base) sync — 1
  • #48 Kanban plugin multiplayer — 1
  • #49 Frontmatter as a Y.Map — 1

Phase 18 — Agents and headless

  • #50 Ingest disk edits to a file open in the editor — 1 (cheapest strategic win)
  • #51 packages/headless on the vault-adapter seam — 3
  • #52 Git mirror of a shared folder — 1
  • #53 Document API — 2
  • #54 Ignore rules (.nectendaignore) — 2
  • #55 Per-folder and per-file disconnect — 1
  • #56 Agent skills repository — 1

Phase 19 — Review and history

  • #57 Comments as CriticMarkup, with a review sidebar — 1
  • #58 Version browser over retained checkpoints — 2
  • #59 Plugin API v0 — 1

Phase 20 — Enterprise, on demand

  • #60 Per-organisation OIDC — 1
  • #61 Read-only billing page for dunning email — 1

Backlog — unscheduled

  • #62 Viewer role enforcement (server refuses unsigned writes) — 2
  • #63 Change attribution — 2
  • #64 Excalidraw support — 3 (check first whether we corrupt these today)
  • #65 Sync .obsidian configuration — 3
  • #66 Notifications and mentions — 3
  • #67 Web shareable read links — 3
  • #68 Decide: self-hosting free on every tier — 1 (a decision, not engineering)
  • #69 Server-side search, previews and link graph: state the trade — 1

Where we are ahead — category 4

  • #70 Keep the client unminified and auditable — 4
  • #71 True air-gapped self-hosting — 4
  • #72 End-to-end encryption: hold the position — 3 (their "Considering")

How to keep this current

Update the issues, not a markdown file. When Relay ships something, change its
relay:* label; when we ship something, close it. The parity label returns the
whole programme:

tea issues --repo Nectenda/nectenda --labels parity --state all
# Relay feature parity, with end-to-end encryption Tracking issue for the parity programme. Every issue below carries a `relay:*` label classifying the feature's status **at Relay**, so this backlog doubles as a live competitive ledger. | Label | Meaning | |---|---| | `relay:supported` | 1 — Relay ships it today | | `relay:planned` | 2 — on their roadmap as Active or Planned, or has an open PR | | `relay:requested` | 3 — asked for by their users or under "Considering"; not committed | | `relay:absent` | 4 — not supported, not requested, not planned at Relay | Risk labels are ours: `risk:none` (client-only, server untouched), `risk:additive` (new message type or table, backward compatible), `risk:contract` (changes something existing accounts or stored data depend on). ## Why this exists, and what was wrong before it Relay was last surveyed in `docs/competition-relay.md` on **1 September 2026**. They shipped **0.8.12 on 9 September**. Our own records were stale in both directions: - We credit Relay with **role-based access control they do not ship**. Their docs say read-only access is unsupported; an `enableReaderRole` flag exists, default off. Their marketed "RBAC" is *private shared folders* — subsetting which members may access a folder — **which we already have** via `folder_members`. - Canvas multiplayer is no longer beta: default-on and free on every tier. - New in 0.8.12 and unrecorded by us: disk-edit ingestion for AI agents (their headline, with a `relay-skills` repo for Claude Code), Plugin API v0, Bases sync, and Relay-Comments as a separate beta plugin. - Continuous background sync reached them only in 0.8.12. **We have had it since Phase 6** and no document says so. - `docs/plan-master.md` says Phase 13 is "next, not built", Phase 14 is half-built and store submission has not happened. All three are stale — we are **listed and accumulating downloads**, and 13 and 14 are complete. ## The two findings that set the sequence Both verified in code, not assumed. **1. Structured documents need no server change.** `packages/server/src/doc-store.ts` says in its own header *"Nothing in this file interprets `payload`"*, and the code matches: a document is a folder-id prefix, an HMAC'd name, a sequence counter and opaque bytes. The folder listing is *already* a `Y.Map` (`file-sync.ts:109`) on the identical encrypted pipeline, and Phase 8 set the precedent of a second root that older clients replicate without acting on. So Canvas, Bases, Kanban, frontmatter, comments and change attribution are **client-only work**. **2. Nothing requires taking the product offline.** The master key is cached per-device in the OS credential store (`docs/security-model.md`; `main.ts:613`), so the one contract-changing item — a signing keypair — can enrol **silently, with no passphrase prompt**. Separating *enrolment* from *enforcement* removes the deadline entirely: enrol now, decide about enforcement whenever. ## What is actually urgent `doc-store.ts:190` deletes `doc_updates` up to every snapshot, and `doc_snapshots` keeps exactly one row per document. With the plugin live, **real users' edit history is being discarded daily and cannot be recovered.** Under this repo's central principle that is closer to a defect than a gap. It is the first issue in Phase 15 and should ship alone if anything slips. ## Sequence Irreversible first, visible second, large last. Phases 13 and 14 are done, so none of this competes with a launch path. | Milestone | Theme | Rough size | |---|---|---| | Phase 15 | Retention and enrolment | ~3 wk | | Phase 16 | The plugin becomes a plugin | 3–4 wk | | Phase 17 | Structured documents | 6–8 wk | | Phase 18 | Agents and headless | 8–10 wk | | Phase 19 | Review and history | 7–9 wk | | Phase 20 | Enterprise, on demand | 2–3 wk | Roughly **32–42 developer-weeks** to broad parity. ## One finding worth stating plainly **Category 4 is nearly empty.** Almost nothing we could build is novel to this category — Relay either ships it or has been asked for it. The encryption is the exception, and it is the whole position. Per `docs/positioning.md`: lead with the server that cannot read your notes, and never compete on licence terms. ## Open question **Self-hosting pricing.** Relay gives self-hosting free on *every* tier and markets it as "we don't charge for privacy". We gate it behind a licence at Business/Enterprise (Phase 12). Since our whole position is privacy, charging for the deployment mode they give away is the one place our pricing reads worse than theirs on our strongest ground. Matching them costs no engineering — it deletes Phase 12. --- *Relay data read 21 September 2026 from relay.md, docs.relay.md, github.com/No-Instructions/Relay (README, manifest, flags.ts, issues, PRs) and their roadmap. Re-fetch rather than trusting this summary; it will drift.* --- ## The backlog Classification is **at Relay**: 1 `relay:supported` · 2 `relay:planned` · 3 `relay:requested` · 4 `relay:absent`. ### Phase 15 — Retention and enrolment *(urgent; history is being lost now)* - [ ] #38 Checkpoint writer: stop discarding edit history — **2** - [ ] #39 Signing keypair enrolment (silent; enforces nothing) — **2** - [ ] #73 `plan-master.md` misstates Phases 10, 13, 14 and the store listing - [ ] #74 `positioning.md` / `competition-relay.md` credit Relay with RBAC they do not ship - [ ] #75 Refresh the Relay snapshot to 0.8.12 - [ ] #76 Walk the stale gates in `launch-readiness.md` ### Phase 16 — The plugin becomes a plugin - [ ] #40 Command palette commands and a ribbon icon — **1** - [ ] #41 Status icons and a sync-state inspector — **1** - [ ] #42 Conflict differ UI — **1** - [ ] #43 Follow a collaborator's viewport — **3** ### Phase 17 — Structured documents - [ ] #44 A `structured` file kind beside text and blob — **1** *(prerequisite)* - [ ] #45 Canvas structural merge over disk — **1** - [ ] #46 Canvas live in-view multiplayer — **1** *(separate decision)* - [ ] #47 Bases (`.base`) sync — **1** - [ ] #48 Kanban plugin multiplayer — **1** - [ ] #49 Frontmatter as a `Y.Map` — **1** ### Phase 18 — Agents and headless - [ ] #50 Ingest disk edits to a file open in the editor — **1** *(cheapest strategic win)* - [ ] #51 `packages/headless` on the vault-adapter seam — **3** - [ ] #52 Git mirror of a shared folder — **1** - [ ] #53 Document API — **2** - [ ] #54 Ignore rules (`.nectendaignore`) — **2** - [ ] #55 Per-folder and per-file disconnect — **1** - [ ] #56 Agent skills repository — **1** ### Phase 19 — Review and history - [ ] #57 Comments as CriticMarkup, with a review sidebar — **1** - [ ] #58 Version browser over retained checkpoints — **2** - [ ] #59 Plugin API v0 — **1** ### Phase 20 — Enterprise, on demand - [ ] #60 Per-organisation OIDC — **1** - [ ] #61 Read-only billing page for dunning email — **1** ### Backlog — unscheduled - [ ] #62 Viewer role enforcement (server refuses unsigned writes) — **2** - [ ] #63 Change attribution — **2** - [ ] #64 Excalidraw support — **3** *(check first whether we corrupt these today)* - [ ] #65 Sync `.obsidian` configuration — **3** - [ ] #66 Notifications and mentions — **3** - [ ] #67 Web shareable read links — **3** - [ ] #68 Decide: self-hosting free on every tier — **1** *(a decision, not engineering)* - [ ] #69 Server-side search, previews and link graph: state the trade — **1** ### Where we are ahead — category 4 - [ ] #70 Keep the client unminified and auditable — **4** - [ ] #71 True air-gapped self-hosting — **4** - [ ] #72 End-to-end encryption: hold the position — **3** *(their "Considering")* ## How to keep this current Update the issues, not a markdown file. When Relay ships something, change its `relay:*` label; when we ship something, close it. The `parity` label returns the whole programme: ``` tea issues --repo Nectenda/nectenda --labels parity --state all ```
Author
Owner

Moved to the Vikunja board as NEC-14: https://projectron.nerchure.com/tasks/14

Moved to the Vikunja board as **NEC-14**: https://projectron.nerchure.com/tasks/14
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Nectenda/nectenda#37
No description provided.