Skip to content

What SuperMessage is

SuperMessage is a Matrix client. It talks to any Matrix homeserver, and the people you message can use Element, Cinny, or anything else.

What makes it different is who else is in the room.

Most tools put an agent in a sidebar: a chat box bolted onto an app, separate from the conversation your team is actually having.

SuperMessage puts the agent in the room. When an agent takes a turn, asks permission, or reaches a gate that needs a human answer, that appears in the timeline, in sequence, next to what everybody else said.

Each of those is rendered as what it is:

What arrives How it reads
dev.agentpod.turn.v1 Turn — what the agent did
dev.agentpod.permission.v1 Permission — what it wants to do, and your answer
dev.superpipeline.gate.v1 Approval — a card waiting on a decision

An agent that needs an answer is usually asking while you are somewhere else, so the timeline is not the only place a decision can be answered.

  • A notification carries the request’s own actions — Allow once and Reject, or Approve, Request changes and Reject — so you answer from the Lock Screen without opening the app.
  • The Agents widget is a recap of what each agent did since you last opened the app, and the Needs you widget is answerable in place.
  • A Live Activity shows the whole fleet — what needs you, and what is happening now — pushed by the hub so it stays live with the app closed.

A push carries ids, not what was said: the app fetches and decrypts the event on your device and words the notification from that. The Live Activity is the single deliberate exception, and says so.

This is a constraint the project holds itself to, not a side effect.

Every custom event carries a plain-text fallback body. Open the same room in Element and you see a readable sentence, not an error. Nothing about using SuperMessage locks a room, a homeserver, or the people in it to SuperMessage.

An agent’s live output arrives over to-device messages, which are deliberately temporary — not stored on the homeserver, not paginated, gone after a restart. That is the right shape for partial text being typed, and a hard ceiling: anything that should be readable tomorrow is a real message in the room instead.

desktop (macOS · Windows · Linux) iOS Android
┌───────────────────────────────┐ ┌─────────────┐ ┌─────────────┐
│ Svelte in the Tauri webview │ │ SwiftUI │ │ Compose │
├─── Tauri commands / events ───┤ ├─────────────┴───┴─────────────┤
│ │ │ UniFFI (supermessage-ffi) │
└───────────────┬───────────────┘ └───────────────┬───────────────┘
└──────────────┬────────────────────┘
┌──────────────┴────────────────────┐
│ Rust core (supermessage-core) │
│ matrix-sdk · sliding sync · E2EE │
└───────────────────────────────────┘

Three user interfaces, one core. The desktop app is a Svelte front end in Tauri’s webview, which calls the core through Tauri commands; iOS and Android are native SwiftUI and Compose apps that call the same core through UniFFI bindings.

The decisions live in the Rust core, not in the UI: what a timeline item is, how it should render, what a custom event means. Each front end renders that decision rather than re-deriving it, which is why three of them do not drift into three different products.

It is not a harness — it does not run agents. AgentPod manages where they run, and SuperPipeline decides what they work on. SuperMessage is where you and they talk.