Your Qor has one chat. Full stop. That chat accepts messages from every chat-family surface — web UI, TUI, Telegram, WhatsApp, Slack DM, and more. Each message keeps a channel tag; per-surface views filter to their slice.
What it looks like

telegram. On WhatsApp you only see messages tagged whatsapp.
Which channels merge
| Channel | Merges into canonical? | Notes |
|---|---|---|
| Web UI | ✅ | The default surface |
| TUI | ✅ | Same canonical as web |
| Telegram DM | ✅ | Groups are separate |
| WhatsApp DM | ✅ | Groups are separate |
| Slack DM | ✅ | In-channel mentions are separate |
| Discord DM | ✅ | Server channels are separate |
| Teams | ✅ | DMs only |
| LINE | ✅ | |
| Signal | ✅ | Via signal-cli |
| iMessage | ✅ | Via Blue Bubbles |
| Facebook Messenger | ✅ | |
| Matrix | ✅ | 1:1 rooms |
| Mattermost DM | ✅ | |
| Feishu / Lark | ✅ | DMs |
| DingTalk | ✅ | DMs |
| WeCom | ✅ | |
| Zalo | ✅ | |
| Webchat | ✅ | Embeddable widget |
| ❌ | Thread-per-subject, own session | |
| SMS | ❌ | Own session |
| GitHub | ❌ | Issues + PRs are not conversations |
| Webhook | ❌ | Custom shape |
| Groups (any channel) | ❌ | Multi-party, group-scoped session |
The data model
sessions.channel column is set to "unified" (or "web" for legacy installs — both work). Each message inside the JSONB array has its own channel field. An index on (session_id, (messages ->> 'channel')) keeps per-channel reads fast.
Per-channel reads
When Telegram asks “show me the last 10 messages”, Qorven runs:What about group chats
Groups are fundamentally different — multi-party, shared context between people, often no single user to bind to. Qorven handles them with group-scoped sessions:- One session row per (tenant, agent, group_id)
- Memories tagged with that group’s scope never leak into the Qor’s 1:1 chats
- Memories tagged with the Qor’s personal scope never leak into groups
- See Groups vs DMs →
What about email
Email is its own thing:- Threads are real (users reply to specific messages)
- Subjects matter (Qor tracks the subject as part of the thread)
- Attachments happen
- Latency is minutes to days, not seconds
Operator migration
If you upgraded from an old multi-session Qorven, run:- Finds every Qor with >1 chat-family session
- Picks the most-recently-updated as canonical
- Merges all other messages into it, preserving
channeltags - Dedupes on
(role, timestamp, content)so re-runs are safe - Emits a memory digest per archived session so nothing’s lost
- Archives the old rows (
status='archived') — not deleted
Where next
Groups vs DMs
How multi-party chats stay separate.
Channel routing
Override the default Qor per sender / keyword.
Memory system
How memory stays coherent across channels.
collapse-sessions
Migrating old fan-out sessions.