> ## Documentation Index
> Fetch the complete documentation index at: https://comis-feature-skill-archive-import.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Multiple users & teams

> Run one Comis install for your whole team - private per person, isolated per agent - across Telegram and every other channel.

One Comis install can serve your whole team. Many people message it, each gets
their own private conversation, and you decide whether they share one assistant
or each get their own - fully isolated. This page explains the model and the
exact configuration, Telegram first, then every other channel.

<Info>
  You don't need to understand the technical details to use this feature. The configuration examples below are copy-paste ready.
</Info>

## The one rule that matters

**Comis isolates by *agent*, not by person.** Each agent has its own memory,
its own secrets, its own budget, and its own tool policy. So the question
"how do I keep my users separate?" comes down to one decision:

* **People who should share knowledge** (one team, one family) → point them at **one shared agent**.
* **People who must stay private from each other** (different clients, departments) → give each their **own agent**, and route to it.

Everything below is how you wire those two cases.

## Do users see each other's messages?

Short answer: **no** - not their messages. The only thing a *shared* agent
pools is what it has *learned* over time. Here is each layer:

| Layer                           | Are two users isolated?                  | Why                                                                                                                                                        |
| ------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Telegram transport (DMs)**    | ✅ Yes                                    | A private 1:1 chat with the bot is invisible to everyone else - Telegram enforces this. One bot serves unlimited private DMs.                              |
| **Telegram transport (groups)** | ❌ No (by design)                         | Everyone in a group sees the group's messages. That is what a group *is* - use DMs for privacy.                                                            |
| **Comis conversation/session**  | ✅ Yes (default)                          | The default `per-channel-peer` session gives each person their own thread. User A's transcript never enters User B's session.                              |
| **Agent long-term memory**      | ⚠️ Only if they use **different agents** | An agent's learned facts are scoped to the agent. Two people on the **same** agent draw on the same memory; give them separate agents for full separation. |

<Warning>
  **A shared agent shares its memory.** Conversations stay private, but the facts
  an agent distills over time are stored per-agent - not per-person. If two people
  talk to the **same** agent, a fact learned from one can surface for the other.
  For real separation between people, give each their **own agent** (Setup B
  below). For a team that *should* pool knowledge, one shared agent is the feature,
  not a leak.
</Warning>

## Setup A - one shared agent (a team that shares knowledge)

The simplest case. Everyone DMs the same bot and talks to the same agent. Their
**conversations are already private** (Telegram DMs + per-peer sessions); they
share the agent's learned memory, which is usually what a single team wants.

```yaml theme={null}
# ~/.comis/config.yaml
channels:
  telegram:
    enabled: true
    botToken: "${TELEGRAM_BOT_TOKEN}"
    # Optional: restrict who can use the bot at all (see "Access control" below)
    allowFrom:
      - "678314278"      # Alice
      - "5900067809"     # Bob

agents:
  default:
    model: claude-sonnet-4-6
```

Nothing else is needed - `routing.defaultAgentId` is `default`, and the default
session scope already keeps each person's chat separate.

## Setup B - one agent per person or team (full isolation)

When people must stay private from each other, give each their own agent and use
top-level **routing** to send each person (or group) to their agent. Because
each agent is its own isolation boundary, this separates **memory, secrets, and
budget** - not just the conversation.

```yaml theme={null}
# ~/.comis/config.yaml
channels:
  telegram:
    enabled: true
    botToken: "${TELEGRAM_BOT_TOKEN}"

agents:
  default:
    model: claude-sonnet-4-6
  alice:
    model: claude-sonnet-4-6
  bob:
    model: claude-sonnet-4-6

routing:
  defaultAgentId: default
  bindings:                 # first match wins; more specific wins ties
    - channelType: telegram
      peerId: "678314278"   # Alice's Telegram user ID -> her own agent
      agentId: alice
    - channelType: telegram
      peerId: "5900067809"  # Bob -> his own agent
      agentId: bob
```

Now Alice and Bob each get an agent with **its own memory** - nothing Alice
tells the bot can surface in Bob's chats, and vice versa. The same pattern
routes a whole **group** to a team agent (use `channelId` for a specific
chat/group, or `guildId` for a Discord server).

<Note>
  Routing bindings are ranked by specificity: **`peerId` (8) > `channelId` (4) >
  `guildId` (2) > `channelType` (1)**, and the first match wins for equal weight.
  Full details and cross-channel examples in [Multi-agent routing](/agents/routing).
</Note>

## The building blocks

Four independent levers cover every multi-user setup. Mix them as needed.

### 1. Access control - who can use the bot at all

`channels.<type>.allowFrom` is an allowlist of **sender IDs**. Empty (the
default) means anyone can talk to the bot; list IDs to lock it down.

```yaml theme={null}
channels:
  telegram:
    allowFrom:
      - "678314278"     # only these Telegram user IDs may reach any agent
      - "5900067809"
```

<Warning>
  `allowFrom` is **sender-keyed, not chat-keyed**. Putting a group's chat ID here
  does nothing - list each individual user's ID. Leave it empty (or omit it) to
  allow everyone.
</Warning>

### 2. Conversation isolation - how sessions are split

Each agent's `session.dmScope.mode` controls how DM conversations are keyed.
The default already isolates per person; change it only if you want a single
shared thread.

```yaml theme={null}
agents:
  default:
    session:
      dmScope:
        mode: per-channel-peer   # default
        threadIsolation: true    # separate Telegram forum topics get their own session
```

| `mode`                         | Effect                                                                                     |
| ------------------------------ | ------------------------------------------------------------------------------------------ |
| `per-channel-peer` *(default)* | One session per channel + person. Each user's DM is its own thread.                        |
| `per-peer`                     | One session per person, shared across channels (their Telegram and Discord DMs merge).     |
| `main`                         | **All** DMs share one session - everyone talks into the same thread. Avoid for multi-user. |
| `per-account-channel-peer`     | Adds the bot-account identifier to the key (for multi-bot session isolation).              |

### 3. Agent routing - who talks to which agent

Top-level `routing` maps people, chats, groups, or whole channels to a specific
agent (Setup B above). This is the lever that gives **memory/secret/budget**
isolation, because each agent is its own tenant. See
[Multi-agent routing](/agents/routing).

### 4. Trust-based replies - different treatment per person *(advanced)*

Give known operators a different model or system prompt than strangers, within
a single agent, via `agents.<id>.elevatedReply`. You assign each sender a trust
**label** (a name you choose), then map labels to model routes and prompt
overrides.

```yaml theme={null}
agents:
  default:
    elevatedReply:
      enabled: true
      defaultTrustLevel: guest          # everyone unlisted
      senderTrustMap:
        "678314278": admin              # Alice is "admin"
        "5900067809": member            # Bob is "member"
      trustModelRoutes:
        admin: claude-opus-4-7          # admins get the stronger model
      trustPromptOverrides:
        guest: "You are a read-only assistant. Be brief and never take destructive actions."
```

<Note>
  Trust labels are free-form strings you define - there is no fixed
  admin/member/guest list. `elevatedReply` changes the **model and system prompt**
  per trust level; it does not replace `allowFrom` (access) or `routing` (agent
  isolation). Use it on top of them when different people need different
  capabilities from the *same* agent.
</Note>

## Telegram specifics

* **For privacy between users, use DMs.** Each person starts a private chat with
  the bot; Telegram keeps those chats mutually invisible. No setup required.
* **Groups are shared by design.** Everyone in a Telegram group sees the group's
  messages. Use a group when you *want* shared context, not for per-user privacy.
* **Finding IDs for `allowFrom` / routing:** a user's numeric Telegram ID and a
  group's chat ID both appear in the logs on every inbound message
  (`senderId`, `chatId`). See
  [Finding a group's chat ID](/channels/telegram#finding-a-groups-chat-id) and
  the `allowFrom` steps on the [Telegram page](/channels/telegram#groups).

## Other channels

The same four levers work on every channel. Only two things change per platform:
the **routing-key field** you bind on, and the **sender-ID format** you put in
`allowFrom`. A private 1:1 (DM / direct chat) is transport-isolated on every
platform; shared spaces (groups, servers, channels) are shared by design.

| Channel  | Private 1:1     | Shared space             | Route a shared space with             | `allowFrom` sender ID |
| -------- | --------------- | ------------------------ | ------------------------------------- | --------------------- |
| Telegram | DM              | group / supergroup       | `channelId` (chat ID, negative)       | numeric user ID       |
| Discord  | DM              | server → channel         | `guildId` (server) and/or `channelId` | numeric user ID       |
| Slack    | DM              | workspace → channel      | `channelId` (`C…`)                    | user ID (`U…`)        |
| WhatsApp | 1:1 chat        | group                    | `channelId` (group JID `…@g.us`)      | E.164 phone (`+1…`)   |
| Signal   | 1:1 chat        | group                    | `channelId` (`group:<id>`)            | phone or UUID         |
| iMessage | 1:1 chat        | group                    | `channelId` (chat GUID)               | phone or email        |
| LINE     | 1:1             | group / room             | `channelId` (group/room ID)           | LINE user ID (`U…`)   |
| IRC      | private message | channel (`#name`)        | `channelId` (`#channel`)              | nick ⚠️               |
| Email    | thread          | - (1:many by recipients) | route by `channelType: email`         | email address         |

`peerId` (the sender) works on every platform. **`guildId` is Discord-only** -
it's the server ID; every other platform routes a shared space with `channelId`.

```yaml theme={null}
# Discord: a whole support server -> support agent; one VIP anywhere -> vip agent.
# WhatsApp: route one group to a team agent (channelId = the group JID).
routing:
  defaultAgentId: default
  bindings:
    - channelType: discord
      guildId: "9876543210"            # server ID -> support agent
      agentId: support
    - channelType: discord
      peerId: "112233445566"           # one user, any channel -> vip agent
      agentId: vip
    - channelType: whatsapp
      channelId: "123456789-1234567890@g.us"   # one WhatsApp group -> team agent
      agentId: team
```

See each channel's page under [Channels](/channels) for how to find its IDs.

### Platform caveats for multi-user

A few platforms need extra care when several people share one install:

* **IRC - nicks are spoofable.** IRC nicknames aren't authenticated by default,
  so `allowFrom` on IRC is **not a security boundary** unless your network
  enforces registration (NickServ) and you trust it. Don't gate a sensitive
  agent on an IRC nick alone.
* **Email - the From address isn't verified.** `channels.email.allowMode` is
  `allowlist` by default (only listed addresses reach the agent; set `open` to
  accept all). But sender addresses can be spoofed and Comis does not check
  SPF/DKIM/DMARC, so treat the email allowlist as convenience, not strong
  authentication, for high-stakes agents.
* **WhatsApp, Signal, iMessage, Email are personal accounts, not bots.** The
  adapter is bound to one phone number (WhatsApp/Signal), one Apple ID on macOS
  (iMessage), or one mailbox (Email) - so "one bot per channel" is really "one
  account per channel." Everyone talks to that single number/address; you still
  isolate people with per-person agents via `routing`, they just all see the
  same identity.
* **Slack & Discord are team-native.** A Slack workspace or Discord server is
  already a multi-user space; `allowFrom` gates at the bot/workspace level (a
  user can or cannot reach the bot at all), and you split people across agents
  with `routing` as usual.

## One identity per channel

Each Comis daemon runs **one** identity per channel type - one Telegram/Discord/
Slack/LINE bot, one WhatsApp or Signal phone number, one iMessage Apple ID, one
mailbox. That is not a limit on users (one identity serves unlimited private DMs
and shared spaces); it only means you can't run two *different* identities of the
same type (two Telegram `@username`s, two phone numbers) in a single daemon. If
you genuinely need a second identity, run one daemon per identity - see
[Routing to a separate bot identity](/channels/telegram#multi-agent-routing) on
the Telegram page.

<CardGroup cols={2}>
  <Card title="Multi-agent routing" icon="route" href="/agents/routing">
    The full routing schema, specificity rules, and cross-channel examples.
  </Card>

  <Card title="Sessions" icon="comments" href="/agents/sessions">
    How conversations are keyed and isolated per person, channel, and topic.
  </Card>

  <Card title="Memory" icon="brain" href="/agents/memory">
    What an agent learns and stores - and why memory is scoped per agent.
  </Card>

  <Card title="Telegram setup" icon="telegram" href="/channels/telegram">
    Step-by-step bot creation, groups, channels, and troubleshooting.
  </Card>
</CardGroup>
