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
| Feature | Chatto → Matrix | Matrix → Chatto | Notes |
|---|---|---|---|
| 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:
- Password: your Chatto username or email and password.
- Browser (OAuth): needs the bridge reachable at a public
https://address, because Chatto fetches the bridge's client metadata itself. - Token: a bot API key, or a session refresh token that the bridge takes over.
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
- Several servers. Add an entry to
network.serversand restart. Each server appears as its own space. - Metrics.
/metrics,/healthzand/readyz, covering connection state, event lag, RPC latency and bridging failures. - Dashboards and alerts. A Grafana dashboard and Prometheus alert rules are in
deploy/monitoring. The NixOS module adds the alert rules to a local Prometheus and the dashboard to a local Grafana. - Server version. Each bridge release is built against one pinned Chatto release. An older server is logged at startup, or refused with
network.strict_server_version. Chatto 0.4 is not supported.
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.