Skip to content

feat: Concord — E2EE community protocol (replaces MLS/Marmot)#67

Merged
JSKitty merged 3 commits into
masterfrom
concord
Jun 8, 2026
Merged

feat: Concord — E2EE community protocol (replaces MLS/Marmot)#67
JSKitty merged 3 commits into
masterfrom
concord

Conversation

@JSKitty

@JSKitty JSKitty commented Jun 8, 2026

Copy link
Copy Markdown

Replaces the MLS/Marmot group-chat stack with Concord, an E2EE community protocol over Nostr (Discord-style servers/channels). Instead of MLS's key-agreement handshake and ratchet trees, Concord is key-possession-based: membership is holding the current epoch's symmetric key (distributed via NIP-17 gift-wraps), authority is an owner-rooted signed roster re-verified by everyone, and removal is a re-key ("re-founding") to a new epoch the removed member never receives.

Feature highlights

  • Channels — a community is a server with channels, each with its own per-epoch key (the server/channel model is native to the protocol).
  • Roles — owner + admin roles via an owner-signed, member-verifiable roster; moderation (ban/kick/grant) is authority-checked by every client, with member-list crowns (gold owner, green admin).
  • Public invite links — per-creator, attributed, registry-authoritative links whose secret lives in the URL fragment (never sent to a web server); the only real access cut is a re-key, which the link-retirement flow triggers.
  • Seamless multi-device sync — your joined communities follow you across devices via an encrypted self-list (kind 30078), carrying the full invite bundle (channel keys), so a join on one device surfaces on the others. Live-validated across two devices.

Also: text + voice messages, reactions, edits/deletes, private gift-wrapped invites, @mentions + admin @everyone, and full desktop + Android notifications (Android keeps the embedded MessagingStyle design — community name, sender + community avatars). Community keys + metadata are encrypted at rest under Local Encryption.

Breaking: the MLS/Marmot stack and its patches/mdk tree are removed; existing MLS groups do not migrate. DB migrations for retired designs are squashed; Community migrations start at 40.

Docs: docs/concord/README.md — a semi-technical explainer of the protocol.

Testing: 923 vector-core tests green; live-validated end-to-end (invite → join → message → voice → reactions → roles → notifications) across two accounts/devices.

JSKitty and others added 3 commits June 8, 2026 13:14
Concord is Vector's keyless, relay-based group-chat protocol: Discord-style
communities and channels with no central server. Membership is key possession,
authority is an owner-rooted signed roster every member re-verifies, and removal
is a re-key ("re-founding") to a new epoch. This replaces the prior MLS/MDK stack
entirely.

vector-core (crates/vector-core/src/community/):
- Crypto core: HKDF derivations + NIP-44 envelope (kind/channel/epoch binding triad),
  per-recipient rekey blobs, all golden-vector pinned.
- Control plane: per-entity version-chained editions, epoch-primary refuse-downgrade
  floors, same-version convergence, bootstrap-vs-tracking fold.
- Re-founding by compaction, read-cut (forward exclusion), multi-epoch read,
  concurrent-refounder convergence (authority-before-tiebreak).
- Keyless authority: real-npub roster ranks, granular permissions, hierarchy;
  owner derived from a signed attestation.
- Invites: direct (NIP-17 gift-wrap) + public links (token-derived locator/key/signer);
  cross-device community list (kind 30078, NIP-44-self-encrypted).
- Transport unified with NIP-17 DMs (shared parser, dedup ledger, ms resolver).

At-rest encryption: Concord secrets + identifying metadata are now wrapped by Local
Encryption — steady-state in db/community.rs plus the enable/disable/PIN-rekey
lifecycle and a one-time login backfill (AEAD-tag idempotency, no content heuristic).

DB: Concord migrations squashed to three (40 create community tables, 41 purge legacy
MLS, 42 processed_wrappers transport column). MLS relational tables + per-account
store fully removed.

Docs: docs/concord/README.md — public, semi-technical explainer of the protocol.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ad + private-invite tooling

Voice notes in community channels now send and render correctly: routed through
send_community_voice_bytes with an empty attachment name, so the renderer shows the
voice player + transcription instead of a named .wav file (round-trips via the imeta
m=audio/wav field).

@mention autocomplete works in communities: candidates are built from observed message
senders (community rosters aren't mirrored into chat.participants). @everyone is restored
to the original design (placeholder avatar, bottom of list) and gated to owner/admin.

Community admin rosters now preload at boot, on surface, and on control refresh, so admin
tags and @everyone render from the first paint instead of only after opening Group Info
(get_community_admins was previously the sole roster loader). Owner status comes from
owner_npub; this fills the non-owner admin set.

Member-list crowns: gold for the owner, green for admins — matching the in-chat tags.

Tooling: concord-cli gains an --invites network probe (paged, password-from-DB login),
and the agent can now SEND a private invite via VectorCore::invite_to_community +
the send_private_invite MCP tool.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… embedded design

Realtime community messages now raise OS notifications, mirroring the DM/group rules:
a normal message notifies only when the channel isn't muted; a direct @mention or an
authorized @everyone (owner or admin) breaks through a muted channel — unless the sender's
DM is muted, they're blocked, or @everyone pings are globally disabled. @everyone authority
is resolved backend-side from the folded roster, and only when the text contains @everyone.
Notifications fire on the realtime path only, never the boot/catch-up sweep.

Android keeps the embedded MessagingStyle design: the Community name as the conversation
title, the sender's name + avatar inline, and the Community icon as the large icon (resolved
from the image cache, falling back to the sender avatar until the icon is cached).

The muted-community unread pill (countPingMessages) already counted pings, but only credited
admins for @everyone — now the owner counts too (owner_npub), matching the in-chat render.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@VectorPrivacy VectorPrivacy deleted a comment from github-actions Bot Jun 8, 2026
@JSKitty JSKitty merged commit 195c16f into master Jun 8, 2026
4 of 5 checks passed
@JSKitty JSKitty deleted the concord branch June 8, 2026 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant