Skip to content

F.3: Matrix-Dendrite bundle (federated real-time chat)#12

Open
kh0pper wants to merge 1 commit intof2-writefreely-bundlefrom
f3-matrix-dendrite-bundle
Open

F.3: Matrix-Dendrite bundle (federated real-time chat)#12
kh0pper wants to merge 1 commit intof2-writefreely-bundlefrom
f3-matrix-dendrite-bundle

Conversation

@kh0pper
Copy link
Copy Markdown
Owner

@kh0pper kh0pper commented Apr 12, 2026

Summary

First multi-container federated bundle. First exerciser of F.0's caddy_add_matrix_federation_port and caddy_set_wellknown matrix-server paths. Stacked on F.2.

Dendrite instead of Synapse — Go monolith, lighter footprint, same client-server API. Two containers on the shared crow-federation network (dendrite + postgres), no host port publish. First-boot entrypoint generates signing keys, writes dendrite.yaml, and prints the registration shared secret to the log.

Stacked on #11 (F.2). Merge order: #9#10#11 → this.

What ships

Bundle (`bundles/matrix-dendrite/`)

  • `manifest.json` — `consent_required` with explicit EN/ES text on the 8448 either-or federation story, media cache growth (tens of GB from Matrix HQ alone), and hardware-gate threshold. `min_ram_mb: 2048`, `recommended: 4096` — Pi-class (4-8 GB total) will at best be warned once other bundles are co-installed.
  • `docker-compose.yml` — `matrixdotorg/dendrite-monolith:v0.13.8` + `postgres:16-alpine`. Postgres on default network; Dendrite joins both default AND crow-federation so Caddy can reach :8008 client-server and :8448 federation listeners. Entrypoint idempotent — skips key/config generation when they exist (survives recreate), prints a fresh `registration_shared_secret` on first boot.
  • `server/server.js` — 11 MCP tools: `matrix_status`, `matrix_joined_rooms`, `matrix_create_room`, `matrix_join_room`, `matrix_leave_room`, `matrix_send_message`, `matrix_room_messages`, `matrix_sync`, `matrix_invite_user`, `matrix_register_appservice` (F.12 prep), `matrix_federation_health`. Content verbs wrapped with F.0 shared rate limiter. Alias→ID resolution via `/directory/room/{alias}` (federated). Sync is one-shot (compact room deltas, not full tree). `federation_health` calls federationtester.matrix.org and returns structured verdict.
  • `skills/matrix-dendrite.md` — "pick one" federation table for :8448 vs .well-known/matrix/server delegation, first-run bootstrap recipe, F.12 appservice prep notes, moderation model (room-scoped, not instance-scoped), E2EE clarification (MCP sends plaintext — Element handles device keys).
  • `panel/` — status + federation health (colored badge with error list from federation tester) + joined rooms preview. XSS-safe.
  • `scripts/` — `backup.sh` (pg_dump -Fc + signing-key tar, warns that signing key = federation identity), `post-install.sh` (waits for health, scrapes registration secret from logs, prints both federation paths as next-step guide).

F.12 prep

`matrix_register_appservice` returns a YAML registration body + install path + restart instructions. The F.12.1 matrix-bridges meta-bundle calls this tool for each mautrix-* sidecar. Does NOT restart Dendrite itself — the caller owns restart-with-health-wait because Dendrite only reloads appservice registrations at startup (plan round-2 review flagged this explicitly).

Design notes

  • Two-network Dendrite container — postgres lives on the default docker network (private); Dendrite spans both so Caddy on crow-federation can reach it while Postgres stays isolated from other federated bundles.
  • Entrypoint bakes secrets into the config file in place. Alternative was a separate init container, but idempotency is clearer when one container owns its config lifecycle. The secret is printed to container logs once on first boot; `post-install.sh` scrapes it and surfaces it in the operator-facing next-step output.
  • Sync returns compact deltas, not full tree. Matrix's `/sync` can return megabytes on initial sync. The MCP tool deliberately summarizes to `{ next_batch, joined_rooms_delta, invites }` — the panel can stream the full tree via SSE when that lands.
  • Appservice registration via tool (not direct filesystem write) — the MCP server runs on the host but Dendrite's config dir is in the container's volume. Writing a file requires either exec-into-container or host-path knowledge. The tool returns the YAML + path; the bridges meta-bundle writes it via `docker cp`.

Test plan

  • `node --check` on all changed files
  • MCP server boots via `createMatrixDendriteServer()`
  • `docker compose config` parses
  • `registry/add-ons.json` validates (gotosocial + writefreely + matrix-dendrite all present)
  • `bash -n` on scripts
  • Live: install after F.0-F.2 merge → Postgres healthy → Dendrite healthy → entrypoint prints registration secret → admin account created via CLI → client-server login returns access_token → `matrix_status` shows whoami
  • Live: `caddy_add_federation_site` profile=matrix + `caddy_add_matrix_federation_port` — verify cert issuance for both :443 and :8448
  • Live: `matrix_federation_health` on the configured server_name — federationtester.matrix.org returns FederationOK=true
  • Live: `matrix_join_room #matrix:matrix.org` — verify federated join completes within 30s and joined_rooms reflects it
  • Live: `matrix_send_message` to a test room and confirm the event appears on another Matrix client's timeline
  • Live: (F.12 prep) `matrix_register_appservice` with fake values — verify returned YAML parses cleanly

First multi-container federated bundle and the first exerciser of F.0's
:8448 second-cert path. Stacked on F.2 (WriteFreely).

Dendrite instead of Synapse — Go monolith, lighter footprint, same
client-server API semantics. Two containers on the shared
crow-federation network (dendrite + postgres), no host port publish.
First-boot entrypoint generates signing keys, writes dendrite.yaml, and
prints the registration shared secret to the log.

Bundle (bundles/matrix-dendrite/):

- manifest.json  consent_required with explicit EN/ES text on the 8448
                 either/or federation story, media cache growth risk
                 (tens of GB from Matrix HQ alone), and hardware-gate
                 threshold. min_ram_mb=2048, recommended=4096 —
                 Pi-class (4-8 GB total) will at best be warned once
                 other bundles are co-installed
- docker-compose.yml  dendrite v0.13.8 + postgres:16-alpine. Postgres
                 isolated to default docker network; Dendrite joins
                 both default and crow-federation so Caddy can reach
                 :8008 client-server and :8448 federation listeners.
                 Entrypoint idempotent: skips key/config generation
                 when they exist (survives container recreate). Prints
                 a fresh registration_shared_secret on first boot and
                 writes it into dendrite.yaml in place
- server/server.js  10 MCP tools:
                 matrix_status, matrix_joined_rooms,
                 matrix_create_room, matrix_join_room,
                 matrix_leave_room, matrix_send_message,
                 matrix_room_messages, matrix_sync,
                 matrix_invite_user, matrix_register_appservice,
                 matrix_federation_health
                 Content-producing verbs wrapped with the F.0 shared
                 rate limiter. Alias->ID resolution via
                 /directory/room/{alias} (federated). Sync is one-shot
                 (1.5s server timeout by default, returns compact
                 joined-room deltas — full tree would be megabytes).
                 federation_health calls the public
                 federationtester.matrix.org and returns structured
                 verdict incl. .well-known path + 8448 reachability
- skills/matrix-dendrite.md  "pick one" federation table for :8448 vs
                 .well-known/matrix/server delegation, first-run
                 bootstrap recipe, F.12 appservice prep notes,
                 moderation model explanation (room-scoped vs
                 instance-scoped), E2EE clarification (MCP sends
                 plaintext — Element handles device keys)
- panel/  status + federation health (green/red badge with error list
                 from federation tester) + joined rooms preview.
                 XSS-safe
- scripts/  backup.sh (pg_dump -Fc + signing key tar, warns about
                 identity-binding), post-install.sh (waits for health,
                 scrapes secret from logs, prints two-path next-step
                 guide)

F.12 prep:

matrix_register_appservice returns a YAML registration body + the
install path + restart instructions. The F.12.1 matrix-bridges
meta-bundle will call this tool for each mautrix-* sidecar. Does NOT
restart Dendrite itself — the caller owns restart-with-health-wait
because Dendrite only reloads appservice registrations at startup.

Platform wiring:

- registry/add-ons.json  matrix-dendrite entry, federated-comms
                 category
- skills/superpowers.md  EN/ES trigger row
- CLAUDE.md  Skills Reference entry

Verified:

- node --check on all changed files
- MCP server boots via createMatrixDendriteServer()
- docker compose -f docker-compose.yml config parses
- registry JSON validates
- bash -n on scripts
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