Skip to content

Matrix integration in the Electron app — options & tradeoffs #120

Description

@dmarzzz

Context

The OS app currently talks to swf-node over 127.0.0.1:7777 for peer search. Open question: how should the app talk to the cohort Matrix server (mtrx.shaperotator.xyz, Phala TEE, source at teleport-computer/shape-rotator-matrix)?

Prior art worth re-reading first:

  • docs/MATRIX.md (currently on a worktree, not main) — onboarding flow, signup-code mechanics, and the explicit warning that programmatic E2EE is hard: mautrix-python is the recommended SDK; matrix-nio dead-ended on cross-signing.
  • apps/os/swf-node.js — the supervisor pattern (state machine, IPC events, bundled binary) we'd likely mirror for any in-process daemon.
  • matrix-bot-setup skill — currently a stub.

Two distinct use cases that should be named up front, because they pull in opposite directions:

  • A. User-facing client: render rooms, send messages, read history in the OS app's renderer.
  • B. Agent / bot channel: the app (or a sidecar) acts as the user's automated identity — posts status, listens for commands, reacts to events.

(A) cares about UX, (B) cares about reliable E2EE on a headless account. Same homeserver, very different shapes.


Client-side options

1. matrix-js-sdk in the renderer

Cheapest path. npm i matrix-js-sdk, instantiate in renderer, sync over HTTPS.

  • 👍 ~1 day to working send/receive.
  • 👎 Credentials + E2EE store live in renderer IndexedDB. With our current preload (contextIsolation on, no nodeIntegration), the SDK works in-browser fine, but secrets aren't isolated from page JS.
  • 👎 E2EE in JS is the known-hard area docs/MATRIX.md calls out. For headless/agent use (B), this is the worst option.

2. matrix-js-sdk in main, IPC bridge to renderer

Mirrors the swf-node supervisor pattern.

  • A matrix-node.js module in main owns the MatrixClient, persists tokens in userData/, exposes IPC (matrix:login, matrix:send, matrix:onTimeline) alongside the existing getSwfNodeStatus etc.
  • E2EE via @matrix-org/matrix-sdk-crypto-wasm, WASM bundled through electron-builder extraResources (same mechanism as the swf-node binary).
  • 👍 Tokens out of renderer; matches existing architecture.
  • 👎 Still the JS-crypto path docs/MATRIX.md warns against. Likely fine for (A), risky for (B).
  • Est: 2–3 days for login + room list + send/receive; +1–2 for E2EE.

3. mautrix-python sidecar, supervised like swf-node

Bundle a Python mautrix process as an extra resource; main spawns + supervises it; renderer talks to its local HTTP/WS surface.

  • 👍 Uses the SDK we already know works for our headless accounts (knock-approver is the reference impl).
  • 👍 Cleanly separates (A) renderer client from (B) agent identity.
  • 👎 Adds Python to our build matrix — non-trivial for Win/Linux packaging (we already ship Python-derived swf-node binaries, so the muscle exists, but it's another moving part).
  • Est: 3–5 days end-to-end.

Server-side options (we own the homeserver)

These don't replace a client-side choice — they make whichever client-side option we pick dramatically easier.

4a. Pantalaimon E2EE proxy

Pantalaimon is a Matrix-developed transparent proxy that handles E2EE itself and exposes the plain client-server API.

  • Bundle a per-user Pantalaimon either (i) on the homeserver host as a per-account proxy or (ii) shipped inside the OS app and run locally.
  • Renderer (option 1) or main-process client (option 2) speaks plain HTTP, no crypto WASM, no key store.
  • 👍 Eliminates the JS E2EE problem entirely.
  • 👎 If hosted alongside the homeserver, keys live there — degrades the E2EE threat model (though the TEE deployment recovers some of it). If shipped locally, we're packaging Python anyway, at which point option 3 becomes more attractive.

4b. Application Service registration

Register the OS app's machine identity as an Application Service on mtrx.shaperotator.xyz.

  • AS users get a privileged token, can puppet namespaced users (@_srwk_*:mtrx.shaperotator.xyz), and live in non-E2EE namespaces by convention.
  • Good fit for (B) agent channel: status broadcasts, presence, structured events to a dedicated #srwk-bot-noise room.
  • 👎 Requires homeserver config (operator action, low cost since we control it).
  • 👎 Not a fit for (A) — humans still want E2EE in cohort rooms.

4c. Non-encrypted cohort rooms

Configure #announcements, #general, #bot-noise as non-encrypted from the start.

  • 👍 Any Matrix client (including option 1 in the renderer) works with zero crypto work.
  • 👍 The homeserver is in a TEE — transport confidentiality is provided by TLS + the attestation story, so the marginal value of E2EE on top is debatable for cohort-wide rooms.
  • 👎 DMs and small-group rooms still want E2EE; this is rooms-by-room.
  • 👎 Reversal is hard once messages exist — needs to be a setup-time decision.

4d. Custom shim API on the homeserver host

A small service co-located with Synapse exposing cohort-opinionated endpoints (POST /srwk/status, GET /srwk/feed, etc.) that proxy to the Matrix client-server API with an AS token.

  • 👍 Renderer becomes trivial — just fetch() calls, no Matrix SDK at all.
  • 👎 We're now maintaining a bespoke API. Couples us tighter to the cohort homeserver and makes it harder to ever federate this with off-cohort Matrix accounts.

4e. Sliding Sync proxy

Run matrix-org/sliding-sync alongside Synapse.

  • Orthogonal to the E2EE question, but makes building a custom client cheaper — incremental room-list sync instead of full /sync deltas.
  • Worth doing eventually regardless of which client option we pick.

Recommendation

For (A) user-facing client: option 2 (matrix-js-sdk in main, IPC bridge) combined with 4c for cohort-wide rooms. The crypto WASM path is fine if the only rooms that need it are DMs and small groups. Mirrors our existing supervisor pattern; tokens stay out of the renderer.

For (B) agent channel: option 3 (mautrix-python sidecar) gated by 4b (Application Service namespace). This is the path the knock-approver already validated; the AS registration prevents agent-noise from leaking into human-encrypted rooms.

Net work: roughly 1 week for (A) end-to-end, plus separate scoping for (B). Server-side changes (4b/4c) are operator actions on teleport-computer/shape-rotator-matrix — small cost, large payoff.

Open questions

  • Is the AS namespace something Andrew is willing to grant per app, or does this need a cohort-wide convention first?
  • Are cohort rooms currently E2EE? (If yes, 4c isn't retroactive; if no, we've already paid the decision.)
  • Do we want one shared bot identity per user, or one per app surface (OS app vs. field-kit rotate vox etc.)?

cc @amiller for server-side feasibility on 4b/4c.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions