mautrix-chatto

A Matrix bridge for Chatto. Use your Chatto servers from any Matrix client.

Status: feature-complete against Chatto v0.5.0-beta.21. It is tested against an in-memory fake of Chatto's API and a mock homeserver, but has not been run against a real Chatto server yet. Expect rough edges, and please report what you find.

What it does

mautrix-chatto is a puppeting bridge built on mautrix-go bridgev2. You log in with your Chatto account and the bridge acts as you on Chatto. Other Chatto users show up as ordinary Matrix users. It connects one or more Chatto servers (the 0.5 line, realtime protocol v4) to your homeserver:

Chatto server→Matrix space
Channels, DMs, group DMs→Rooms in that space
Room groups→Subspaces (optional, network.group_spaces)
Chatto users→Ghost users with names and avatars

Messages, edits, deletions, reactions, replies, threads, attachments, typing, read state and presence flow both ways. Encryption, double puppeting, relay mode and backfill come from bridgev2.

Features

FeatureChatto → MatrixMatrix → ChattoNotes
Formatted text✓✓Chatto's Markdown ↔ Matrix HTML, including code blocks, tables and footnotes
Mentions✓✓@login ↔ pills; @all/@here → @room, using Chatto's own mention rules
Edits✓✓Chatto allows edits for 3 hours
Deletes✓✓Single attachments of a message can be removed
Reactions✓✓Unicode ↔ gemoji shortcodes; custom emoji are rejected
Replies✓✓
Threads✓✓In rooms without threads, a thread message becomes a reply
Attachments✓✓Chunked uploads; videos still processing are replaced when ready
Link previews✓–Chatto generates its own previews for messages from Matrix
Stickers, voice, GIFs–✓Sent as attachments
Locations–~Sent as text with a geo: link
Typing✓✓
Read receipts~✓Chatto only has your own read state (needs double puppeting)
Presence and status✓~Ghost presence plus custom status message
Room name and topic✓✓Channels only
User names and avatars✓–
Membership✓~Leave, invite and kick in channels
DMs✓✓Start one with start-chat @login
Group DMs✓✗Chatto no longer allows creating new group DMs
Pins✓✗bridgev2 has no hook for pins made on Matrix
Voice calls~✗Start and end notices only, no media
Backfill✓–Initial history, threads, and catch-up after downtime
Encryption✓✓bridgev2 built-in, pure-Go olm

✓ supported · ~ partial · – not applicable · ✗ not supported. The README has the full list.

Install

NixOS

The flake ships a package, an overlay and a NixOS module. The module writes the registration file to /var/lib/mautrix-chatto/chatto-registration.yaml (see below).

{
  inputs.mautrix-chatto.url = "github:elsbrock/mautrix-chatto";

  outputs = { nixpkgs, mautrix-chatto, ... }: {
    nixosConfigurations.homelab = nixpkgs.lib.nixosSystem {
      modules = [
        mautrix-chatto.nixosModules.default
        {
          services.mautrix-chatto = {
            enable = true;
            settings = {
              # id is permanent: it is part of every bridged ID
              network.servers = [ { id = "main"; url = "https://chat.example.com"; } ];
              homeserver = {
                address = "http://127.0.0.1:8008";
                domain = "example.com";
              };
              bridge.permissions = {
                "example.com" = "user";
                "@you:example.com" = "admin";
              };
            };
            metrics.enable = true;
          };
        }
      ];
    };
  };
}

Any Linux host

nix build github:elsbrock/mautrix-chatto   # or: go build -tags goolm ./cmd/mautrix-chatto
./result/bin/mautrix-chatto -e -c config.yaml    # write the example config
$EDITOR config.yaml                              # network.servers, homeserver.*, bridge.permissions
./result/bin/mautrix-chatto -g -c config.yaml -r registration.yaml
./result/bin/mautrix-chatto -c config.yaml -r registration.yaml

Container

nix build github:elsbrock/mautrix-chatto#docker && docker load < result
docker run --rm -v $PWD/data:/data mautrix-chatto -e -c /data/config.yaml
# set appservice.hostname to 0.0.0.0 in data/config.yaml, then:
docker run --rm -v $PWD/data:/data mautrix-chatto -g -c /data/config.yaml -r /data/registration.yaml
docker run -d -v $PWD/data:/data -p 29340:29340 mautrix-chatto

Connect it to your homeserver

The bridge runs next to your homeserver as an appservice. The homeserver forwards it the events for bridged rooms and lets it act as the @chatto_… users. The two trust each other through a registration file that the bridge generates. It holds two shared tokens, the bridge's address and the user names the bridge owns. You load that file into your homeserver once.

tuwunel or conduwuit: open the admin room (#admins:example.com) and send this message, with the whole content of the registration file between the fences:

!admin appservices register
```
id: chatto
as_token: …
hs_token: …
# …rest of the file
```

The server confirms in the admin room. Then start the bridge.

Synapse: add the file to app_service_config_files and restart Synapse. The NixOS module does this for you when Synapse runs on the same host.

The annotated example-config.yaml covers every option. The Chatto-specific part is the network: section.

Logging in

Send login to the bridge bot. Three flows are available:

You can have several logins, on one server or across several. Matrix users without a Chatto account can still take part through relay mode, or through per-user ghost bots that post under their own name.

Running it

Development

nix develop          # go, gopls, golangci-lint, buf, protoc plugins
scripts/check.sh     # vet, lint, race tests
nix flake check      # build, tests, lint, alert rules, NixOS module

The tests run against an in-memory Chatto built on the real generated API handlers. See CONTRIBUTING.md for the layout and the upgrade process, and docs/decisions for why things are the way they are.