diff --git a/communication/api.mdx b/communication/api.mdx
new file mode 100644
index 000000000..b86e23fb2
--- /dev/null
+++ b/communication/api.mdx
@@ -0,0 +1,190 @@
+---
+title: "API messages"
+description: "Talk to your assistant from your own code"
+---
+
+Every other channel puts a person at one end — a phone, an inbox, a chat
+window. This one puts your code there instead. Send your assistant a message
+with an HTTP request, poll for its reply, and wire it into whatever you're
+building. No browser, no phone number, no connected account — just your API
+key.
+
+It's the same assistant either way. Something you ask for over the API is
+something you can follow up on in [Chat](/communication/console-chat) an hour
+later, and it'll know what you mean.
+
+## What you need
+
+- **Your API key** and **your assistant's ID**, both from the
+ [Console](https://console.unify.ai).
+- The base URL: `https://api.unify.ai/v0`
+- A Bearer token header on every request:
+
+```
+Authorization: Bearer YOUR_API_KEY
+```
+
+
+ Assistants running in a [local deployment](/local-deployment/overview) don't
+ receive API messages — this channel is for assistants hosted by Unify.
+
+
+## Sending a message
+
+`POST /messages` with the assistant's ID and your message:
+
+```bash
+curl -X POST https://api.unify.ai/v0/messages \
+ -H "Authorization: Bearer $UNIFY_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "assistant_id": ,
+ "message": "Add milk to my shopping list."
+ }'
+```
+
+You get back a `message_id` straight away, before your assistant has done
+anything with it:
+
+```json
+{
+ "info": {
+ "message_id": "msg_abc123",
+ "assistant_id": 42,
+ "message": "Add milk to my shopping list.",
+ "status": "processing",
+ "response": null,
+ "tags": [],
+ "attachments": [],
+ "response_tags": null,
+ "response_attachments": null,
+ "created_at": "2026-08-10T12:00:00Z",
+ "completed_at": null
+ }
+}
+```
+
+## Polling for the reply
+
+Your assistant works on the message in the background — it might answer in a
+second, or go off and actually do the thing first. Poll
+`GET /messages/{message_id}` until `status` flips from `processing` to
+`completed`:
+
+```bash
+curl https://api.unify.ai/v0/messages/msg_abc123 \
+ -H "Authorization: Bearer $UNIFY_KEY"
+```
+
+```json
+{
+ "info": {
+ "message_id": "msg_abc123",
+ "assistant_id": 42,
+ "message": "Add milk to my shopping list.",
+ "status": "completed",
+ "response": "Done! I've added milk to your shopping list.",
+ "tags": [],
+ "attachments": [],
+ "response_tags": [],
+ "response_attachments": null,
+ "created_at": "2026-08-10T12:00:00Z",
+ "completed_at": "2026-08-10T12:00:05Z"
+ }
+}
+```
+
+`response` can come back `null` on a completed message. That's not an error —
+your assistant decides whether a reply is warranted, the same way it does on
+any other channel, and sometimes doing the task quietly is the right answer.
+
+## From Python
+
+The SDK wraps both calls:
+
+```python
+import unisdk
+
+status = unisdk.agent.send_message(
+ assistant_id=,
+ message="Add milk to my shopping list.",
+)
+
+status = unisdk.agent.get_message_status(status["message_id"])
+print(status["status"], status["response"])
+```
+
+## Sending files
+
+Upload each file first, then reference it in the message.
+
+
+
+ ```bash
+ curl -X POST https://api.unify.ai/v0/messages/attachments \
+ -H "Authorization: Bearer $UNIFY_KEY" \
+ -F "file=@report.pdf" \
+ -F "assistant_id="
+ ```
+
+ You get back the file's metadata:
+
+ ```json
+ {
+ "id": "att_xyz789",
+ "filename": "report.pdf",
+ "gs_url": "gs://bucket/path/report.pdf",
+ "content_type": "application/pdf",
+ "size_bytes": 204800
+ }
+ ```
+
+
+ ```bash
+ curl -X POST https://api.unify.ai/v0/messages \
+ -H "Authorization: Bearer $UNIFY_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "assistant_id": ,
+ "message": "Please summarise this report.",
+ "attachments": [
+ {
+ "id": "att_xyz789",
+ "filename": "report.pdf",
+ "gs_url": "gs://bucket/path/report.pdf"
+ }
+ ]
+ }'
+ ```
+
+
+
+Files are capped at **25 MB** each. Your assistant can send files back too —
+they arrive as `response_attachments` on the completed message, each with a
+download URL.
+
+## Tags
+
+Tags are arbitrary strings you can hang off a message. Your assistant treats
+them as opaque routing labels — it doesn't read anything into them — and
+echoes them back on its reply as `response_tags`.
+
+```bash
+curl -X POST https://api.unify.ai/v0/messages \
+ -H "Authorization: Bearer $UNIFY_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "assistant_id": ,
+ "message": "Summarise today'\''s sales figures.",
+ "tags": ["source:slack", "channel:#analytics"]
+ }'
+```
+
+That's what makes them useful for bridging: if you're relaying messages from
+somewhere else, tag the inbound message with wherever it came from and the
+reply tells you where to send it back.
+
+
+ Tags are how you keep one assistant serving several surfaces at once without
+ losing track of which reply belongs to which request.
+
diff --git a/communication/behavior.mdx b/communication/behavior.mdx
index 5a44c0ddd..d2c677c06 100644
--- a/communication/behavior.mdx
+++ b/communication/behavior.mdx
@@ -20,6 +20,14 @@ It won't send you play-by-play updates unless you want them, and in group
settings — Slack channels, meetings, calls with several people — it speaks
when addressed or when it genuinely has something to add.
+In a room with several AI teammates — a [group or team
+chat](/communication/group-chats), a Slack or Teams channel — exactly one of
+them should answer any given message. Name the teammate you want and the
+rest stay out of it; name nobody and whoever the work belongs to picks it
+up. Assistants also mostly don't reply to *each other*: acknowledging a
+teammate is noise, and two assistants trading acknowledgements is a loop
+that costs real money.
+
## It can reach out first
Your assistant isn't purely reactive:
@@ -28,10 +36,11 @@ Your assistant isn't purely reactive:
tells you on an appropriate channel.
- **Scheduled work** — [tasks](/tasks/overview) you've scheduled can end
with a message, an email, or a call at the time you chose.
-- **Gentle follow-ups** — if a conversation with your T-W1N goes quiet while
- something needs your input, it may send a friendly follow-up email. This
- re-engagement is specific to your T-W1N; hired teammates don't do it. Ask it
- to stop and it stops.
+- **Gentle follow-ups** — if you've been away from the platform for a while,
+ your T-W1N sends a short check-in email. At most three per quiet spell, and
+ then it leaves you alone until you're active again. This re-engagement is
+ specific to your T-W1N; hired teammates don't do it. Ask it to stop and it
+ stops, until you ask it to resume.
- **Ringing you** — when a live conversation beats a wall of text, it can
ring you on [Unify Meet](/communication/unify-meet), and falls back to chat
if you don't pick up.
diff --git a/communication/console-chat.mdx b/communication/console-chat.mdx
index fd920d119..2ce783dec 100644
--- a/communication/console-chat.mdx
+++ b/communication/console-chat.mdx
@@ -56,6 +56,13 @@ brings you back to now.
For history *beyond* this one thread — email, SMS, WhatsApp, and every
other channel — see [Transcripts](/communication/recordings-and-transcripts).
+## Beyond your own thread
+
+This page is your one-to-one thread with one assistant. In an organization
+the same composer also runs [group chats](/communication/group-chats) —
+rooms shared with colleagues, teams, and several assistants at once, where
+naming the teammate you want decides who answers.
+
## Always on, and honest when it isn't
Chat is your assistant's home channel: updates, links, and deliverables
diff --git a/communication/developers/conversation-manager.mdx b/communication/developers/conversation-manager.mdx
index 60eb24ea9..50758aaac 100644
--- a/communication/developers/conversation-manager.mdx
+++ b/communication/developers/conversation-manager.mdx
@@ -32,8 +32,7 @@ plus call-lifecycle events (`PhoneCallReceived`, `PhoneCallAnswered`,
`PhoneCallEnded`, `UnifyMeetStarted`…), per-utterance voice events
(`InboundPhoneUtterance`, `OutboundUnifyMeetUtterance`…), reactions,
voice-control events (`FastBrainNotification`, `VoiceInterrupt`), and
-lifecycle events (`StartupEvent`, `TaskDue`, `InactivityFollowup`,
-`PreHireMessage`).
+lifecycle events (`StartupEvent`, `TaskDue`, `PreHireMessage`).
Two mapping layers connect the world to handlers:
@@ -56,7 +55,7 @@ Two mapping layers connect the world to handlers:
defines the `Medium` enum — the single source of truth for channel types
(`UNIFY_MESSAGE`, `EMAIL`, `SMS_MESSAGE`, `WHATSAPP_MESSAGE`,
`WHATSAPP_CALL`, `PHONE_CALL`, `UNIFY_MEET`, `GOOGLE_MEET`, `TEAMS_MEET`,
-Slack/Discord variants, and both the delegated-Graph
+`API_MESSAGE`, Slack/Discord variants, and both the delegated-Graph
(`TEAMS_MESSAGE`, `TEAMS_CHANNEL_MESSAGE`) and org-installed bot
(`MS_TEAMS_BOT_MESSAGE`, `MS_TEAMS_BOT_CHANNEL_MESSAGE`) Teams mediums…).
The two org-installed bot send tools are gated behind the assistant's
@@ -121,9 +120,8 @@ concern:
| [`renderer.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/renderer.py) | State → prompt snapshots and diffs |
| [`contact_index.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/contact_index.py) | Live per-medium message threads |
| [`notifications.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/notifications.py) | The `NotificationBar` surfaced in prompts |
-| [`task_activation.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/task_activation.py) | `TaskDue` wake-ups and live task execution |
-| [`inactivity.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/inactivity.py) | Re-engagement follow-ups |
-| [`proactive_speech.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/proactive_speech.py) / [`speech_urgency.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/speech_urgency.py) | Breaking silence on calls / preempting the slow brain for urgent speech |
+| [`task_execution.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/task_execution.py) | `TaskDue` wake-ups and live task execution |
+| [`proactive_speech.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/proactive_speech.py) | Breaking silence on calls |
| [`comms_utils.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/comms_utils.py) | HTTP calls to the gateway's channel endpoints |
| [`managers_utils.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/managers_utils.py) | Manager init and `log_message()` → transcripts |
@@ -154,6 +152,32 @@ Outbound events published by the brain's own sends set
`suppress_slow_brain_wake` so the assistant isn't re-woken by its own
confirmations.
+### The API message round trip
+
+The [developer API channel](/communication/api) is the one send path that
+doesn't originate a conversation — it completes a caller that is already
+waiting, so it runs request/response rather than fire-and-forget:
+
+1. **Inbound.** Orchestra's `POST /v0/messages` persists an `ApiMessage`
+ row and dispatches it to the adapters, which publish an `api_message`
+ envelope. `CommsManager.events_map` maps that thread to
+ `ApiMessageReceived`, whose handler parks the `api_message_id` and the
+ caller's tags on the `ConversationManager` as
+ `_pending_api_message_id` / `_pending_api_message_tags`.
+2. **Outbound.** `send_api_response` reads that pending id, so it is only
+ meaningful while a call is in flight — with nothing pending it returns
+ `{"status": "ok", "note": "no pending api message"}` rather than opening
+ a new outbound conversation. It uploads any attachments, then
+ `comms_utils.complete_api_message()` issues
+ `PUT {ORCHESTRA_URL}/messages/{id}/complete`, which is what flips the
+ caller's poll from `processing` to `completed`.
+3. **Record.** An `api_message_sent` event writes the transcript row,
+ anchored to the boss contact — the API exchange lands in the same
+ durable history as every other medium (`Medium.API_MESSAGE`).
+
+Tags are opaque to the runtime; the prompt tells the brain to echo them
+back by default so the developer can route the reply on their own side.
+
## Transcripts
[`unify/transcript_manager/transcript_manager.py`](https://github.com/unifyai/unify/blob/main/unify/transcript_manager/transcript_manager.py)
@@ -175,8 +199,13 @@ machinery](https://github.com/unifyai/unify/blob/main/unify/conversation_manager
in two directions. Downward: every in-flight `act(...)` is a steerable
handle the brain can `ask`, `interject`, `pause`, `resume`, or `stop` via
dynamically generated tools. Upward: when a user speaks while the slow
-brain is mid-turn, `SpeechUrgencyEvaluator`
-([`domains/speech_urgency.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/speech_urgency.py))
-classifies the utterance and may cancel the running turn so the new input
-takes priority — the runtime-level implementation of "you can always
-interrupt."
+brain is mid-turn, the input does **not** cancel the running turn. The
+`Debouncer`
+([`domains/utils.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/utils.py))
+holds one running turn plus at most one pending turn — a new submission
+replaces whatever was pending and starts when the current turn finishes.
+Preemption used to exist (a `SpeechUrgencyEvaluator` that classified the
+utterance and cancelled the running turn) and was removed: the queue of two
+is the whole mechanism. What makes interruption feel immediate on a call is
+the fast brain — barge-in and the interim turn — not turn cancellation; see
+[Voice calls](/communication/developers/voice).
diff --git a/communication/developers/voice.mdx b/communication/developers/voice.mdx
index 9b5e718b4..f3079d4aa 100644
--- a/communication/developers/voice.mdx
+++ b/communication/developers/voice.mdx
@@ -71,25 +71,44 @@ browser automation rather than SIP.
records the `spoken_prefix` actually delivered and the
`unheard_remainder`, so the slow brain knows exactly what the user did
and didn't hear and can re-weave the rest.
-- **Urgency preemption.** If the user says something urgent while the slow
- brain is mid-turn, `SpeechUrgencyEvaluator`
- ([`domains/speech_urgency.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/speech_urgency.py))
- can cancel the running turn in favor of the new input.
+- **No turn preemption.** Speaking mid-turn does not cancel the running
+ slow-brain turn. The new input queues as the single pending turn (see
+ [the conversation runtime](/communication/developers/conversation-manager)),
+ and the fast brain covers the gap. Urgency-based preemption was tried and
+ removed.
- **Proactive speech.** During long silences while work runs,
`ProactiveSpeech`
([`domains/proactive_speech.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/domains/proactive_speech.py))
decides whether the assistant should say something unprompted.
-## Speakers and enrollment
-
-Diarized speakers who aren't engaged contacts are transcribed as context
-but don't get replies; the slow brain's `engage_speaker` /
-`disengage_speaker` tools flip that, mirrored in the call manager's
-engagement state. Voice profiles (`VoiceEnrollmentCaptured`,
-`VoiceEnrollmentSuggested`, and `speaker_id.SpeakerTracker` in
-[`medium_scripts/`](https://github.com/unifyai/unify/tree/main/unify/conversation_manager/medium_scripts))
-let known voices be pinned across calls — enrolled embeddings ride along
-in the dispatch metadata.
+## Who said what
+
+Attribution comes from the meeting roster and the platform's own
+participant signals — never from matching voices.
+
+In a browser meeting the two halves arrive separately: the transcriber
+tags each finalised utterance with an anonymous diarization id (`S0`,
+`S1`), while the meeting platform reports spans of who was speaking over
+the Recall relay.
+[`meet_speaker_map.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/meet_speaker_map.py)
+pairs them by **overlap of time spans** rather than by sampling who is
+speaking when a final lands — by then the speaker has stopped and the
+platform has already sent `speech_off`, so instantaneous sampling fires
+only when someone talks over the previous speaker's tail, exactly when
+it's most likely to name the wrong person. Votes accumulate rather than
+binding on first sight, because diarization ids are per-call and drift.
+Elsewhere, an unresolved turn is attributed to the call contact and the
+slow brain infers the real speaker from the conversation.
+
+Enrolled voice embeddings are **not** compared against live audio to
+decide who is speaking. That path was removed after production audio
+showed the cosines conflated distinct speakers — including the
+assistant's own TTS voice — about as often as they separated them, so a
+matched label was as likely to be wrong as right. `SpeakerTracker`
+([`speaker_id.py`](https://github.com/unifyai/unify/blob/main/unify/conversation_manager/speaker_id.py))
+remains as capture-only machinery: clustering keeps auto-enrollment
+single-voice pure and counts distinct voices behind
+`VoiceEnrollmentCaptured` / `VoiceEnrollmentSuggested`.
## Hang-up semantics
diff --git a/communication/email.mdx b/communication/email.mdx
index 533f691da..278b0c379 100644
--- a/communication/email.mdx
+++ b/communication/email.mdx
@@ -8,10 +8,15 @@ threads, handling attachments, and looping in cc'd colleagues, just like any
teammate.
- **If this is your T-W1N** (your digital twin): its email is platform-managed
- and already set up — there's nothing to create or configure. T-W1N acts on
- *your* behalf, so it uses your own connected account rather than a mailbox of
- its own. The setup below is for **hired teammates**.
+ **If this is your T-W1N** (your digital twin): its address is
+ platform-managed and already set up — there's nothing to create or
+ configure. T-W1N's address is shared across the platform, and mail you send
+ to it reaches *your* T-W1N because your own contact details are
+ [verified](/communication/setup) — which is why verifying them matters.
+
+ That's separate from T-W1N working inside **your** mailbox through your
+ [workspace connection](/workspace/email): mail it sends from there goes out
+ as you, from your account. The setup below is for **hired teammates**.
## How your assistant gets an email address
@@ -61,9 +66,10 @@ unlocks calendar, files, contacts, and tasks, depending on what you grant.
## Email in the flow of work
Email is your assistant's channel of choice for anything long-form: reports,
-summaries, documents. It's also how your assistant gently follows up if you've
-gone quiet on something that needs your input — and if you'd rather it didn't,
-just tell it to stop the follow-ups.
+summaries, documents. It's also where your [T-W1N checks
+in](/communication/behavior) if you've been away from the platform for a
+while — those come from your T-W1N rather than a hired teammate, and stop as
+soon as you ask.
You don't have to manage the mailbox. Your assistant watches its inbox and
diff --git a/communication/group-chats.mdx b/communication/group-chats.mdx
new file mode 100644
index 000000000..582dc1c58
--- /dev/null
+++ b/communication/group-chats.mdx
@@ -0,0 +1,72 @@
+---
+title: "Group chats"
+description: "Team rooms, ad-hoc groups, and DMs with colleagues"
+---
+
+[Console chat](/communication/console-chat) is a thread between you and one
+assistant. It isn't the only thread you get. In an organization, the
+assistant list is a full roster — your **teams**, your human **colleagues**,
+and your **assistants** — and any of them opens a conversation.
+
+Rooms work like chat with one difference that changes how they feel: several
+AI teammates can be listening at once, so *who answers* is a real question.
+
+
+ Colleague DMs and groups exist inside an **organization**. On a personal
+ account, the roster is just your own assistants.
+
+
+## Three kinds of room
+
+- **Colleague DMs** — pick a person from **Real** in the roster for a
+ one-to-one thread with them, presence dot and all. No assistant is
+ listening to a human DM; it's just the two of you.
+- **Groups** — an ad-hoc room you create with any mix of colleagues and
+ assistants, optionally named. You can add and remove members later.
+- **Team chats** — one shared thread per [team](/teams/overview), with every
+ member in it, human and AI.
+
+## Who answers
+
+Every message in a team or group room is delivered to **every** AI teammate
+in that room — not just the one you had in mind. They're told to work out
+whose turn it is rather than all pile in:
+
+- **Name someone** and it's theirs. Type `@` for a picker, or just type the
+ name — a hand-typed `@Ada` addresses Ada exactly as much as a picked one.
+- **Name a teammate other than the one you'd expect** and the others stay
+ quiet, even when they could have answered. Talking over a named teammate is
+ worse than saying nothing.
+- **Name nobody** and the best-placed teammate takes it — the one whose work
+ it's plainly about. This is the case where you might get silence, so name
+ someone if it matters.
+
+Your personal T-W1N stays out of team and group rooms. Its job is your own
+thread, not the room.
+
+
+ Rooms have a brake on assistants talking to each other: after **three**
+ consecutive assistant messages with no human turn, the room stops waking
+ assistants until a person says something. If a room goes quiet mid-exchange
+ between two assistants, that's why — say anything and it resumes.
+
+
+## Calls
+
+Any room can become a call, not just your 1:1 with an assistant. The call
+button rings everyone in the room; people answer, decline, or join late, and
+assistants are dispatched into the same call. It's the same machinery as
+[Unify Meet](/communication/unify-meet) — one call surface across colleague
+DMs, groups, teams, and assistant threads.
+
+## The composer
+
+Rooms use the same composer as [Console chat](/communication/console-chat):
+attachments, voice notes transcribed into the box, camera capture, emoji
+reactions, and a search over the room's history.
+
+
+ A group is the quickest way to get two assistants working the same problem
+ in front of you — put both in a room with the colleague who owns the work,
+ and name whichever one you want to pick up each turn.
+
diff --git a/communication/microsoft-teams.mdx b/communication/microsoft-teams.mdx
index 50e378f95..fb6d7837f 100644
--- a/communication/microsoft-teams.mdx
+++ b/communication/microsoft-teams.mdx
@@ -21,13 +21,13 @@ Unify bot, not as a person.
## Setup
A Microsoft admin installs the **Unify Teams app** into your organization's
-Teams. Once it's installed, every assistant in the org — and your coordinator
-— is reachable through it; there's nothing to configure per assistant.
+Teams. Once it's installed, every assistant in the org — and your T-W1N — is
+reachable through it; there's nothing to configure per assistant.
## Messaging
-- **1:1 chat** — message the Unify app in Teams and your coordinator picks up
- the conversation.
+- **1:1 chat** — message the Unify app in Teams and your T-W1N, the
+ coordinator that fields anything unaddressed, picks up the conversation.
- **Group chats** — add the app to a group chat and @mention it to bring it
in; it replies in the same conversation.
- **Channels** — @mention the app in a channel and it replies in the thread,
@@ -39,10 +39,10 @@ Because the app is shared, addressing works like Slack:
- In a **channel or group chat**, @mention the app and include the teammate's
name to reach a specific assistant (for example, `@Unify Alex, can you…`).
- @mention it with no name and the message goes to your **coordinator**, who
- can hand off from there.
-- In a **1:1 chat**, messages go to your coordinator — there's no name to add,
- so naming a teammate isn't used here.
+ @mention it with no name and the message goes to your **T-W1N**, who can
+ hand off from there.
+- In a **1:1 chat**, messages go to your T-W1N — there's no name to add, so
+ naming a teammate isn't used here.
Teams only delivers channel and group-chat messages to the app when it's
diff --git a/communication/overview.mdx b/communication/overview.mdx
index 4ab369fd9..889b45efb 100644
--- a/communication/overview.mdx
+++ b/communication/overview.mdx
@@ -14,6 +14,7 @@ assistant with the same memory of everything you've discussed.
| Channel | You → Assistant | Assistant → You | Setup needed |
|---|---|---|---|
| [Console chat](/communication/console-chat) | Yes | Yes | None — works immediately |
+| [Group chats](/communication/group-chats) (teams, groups, colleagues) | Yes | Yes | None — organization accounts |
| [Unify Meet](/communication/unify-meet) (browser calls) | Yes | Yes — it can ring you | None — works immediately |
| [Phone calls](/communication/phone-calls) | Yes | Yes | Assistant phone number |
| [SMS](/communication/sms) | Yes | Yes | Assistant phone number |
@@ -22,6 +23,7 @@ assistant with the same memory of everything you've discussed.
| [Slack](/communication/slack) | Yes | Yes | Slack app install |
| [Microsoft Teams](/communication/microsoft-teams) | Yes | Yes | Teams app install ([or Microsoft 365 connection](/workspace/teams)) |
| [Discord](/communication/discord) | Yes | Yes | Discord ID on your profile |
+| [API](/communication/api) | Yes — from your own code | Yes — it replies to your call | API key |
| [Google Meet & Teams meetings](/workspace/meetings) | Invite it to a meeting | It can create Teams meetings | Meeting link |
## Two channels work out of the box
@@ -34,8 +36,10 @@ minutes of one-time setup.
## Setting up the other channels
-Setup follows the same pattern for every channel, and is covered in detail in
-[Setting up channels](/communication/setup):
+Setup follows the same pattern for every channel your assistant talks to
+people on, and is covered in detail in
+[Setting up channels](/communication/setup). ([API messages](/communication/api)
+are the exception — no contact details, just your API key.)
@@ -75,8 +79,9 @@ A few things that hold everywhere:
WhatsApp, and preferences.
- **It respects boundaries.** People can be marked as do-not-contact, and your
assistant will never message them.
-- **It can follow up.** If a conversation goes quiet, your assistant may send a
- friendly follow-up email. You can opt out any time by asking it to stop.
+- **Your T-W1N checks in.** If you've been away from the platform for a while,
+ your T-W1N sends a short check-in email — a few at most, and only ever from
+ your T-W1N, never a hired teammate. Ask it to stop and it stops.
## What's in this section
@@ -84,6 +89,9 @@ A few things that hold everywhere:
Text chat with file attachments, reactions, and voice input.
+
+ Team rooms, ad-hoc groups, and DMs with colleagues.
+
Browser voice & video calls with two-way screen sharing.
@@ -108,6 +116,9 @@ A few things that hold everywhere:
DMs and server channels.
+
+ Message it from your own code and poll for the reply.
+
} href="/workspace/meetings">
Your assistant joins Google Meet and Teams meetings.
diff --git a/communication/phone-calls.mdx b/communication/phone-calls.mdx
index 9eb401165..1412a457c 100644
--- a/communication/phone-calls.mdx
+++ b/communication/phone-calls.mdx
@@ -31,9 +31,13 @@ Australia, Canada, Finland, Netherlands, Puerto Rico, Thailand, and Poland**.
Dial its number from your phone. Your assistant picks up and talks with you
naturally — same voice, same memory, same colleague you know from chat.
-Calls to the assistant are for **known contacts**. If someone the assistant
-doesn't know calls the number, they hear a short message directing them to the
-Console instead of reaching your assistant.
+Calls are for people your assistant knows. On the shared numbers T-W1N uses,
+a caller it doesn't recognize never gets through — they hear a short message
+directing them to the Console. On an assistant's own number the call does
+reach the assistant, but an unknown caller isn't treated as a known contact:
+they're recorded as a [contact](/communication/contacts) with responses
+switched off, and your assistant comes to you for guidance rather than acting
+on what a stranger asked for.
## Your assistant calling you (or others)
diff --git a/communication/recordings-and-transcripts.mdx b/communication/recordings-and-transcripts.mdx
index e175e0d64..7cb74c56a 100644
--- a/communication/recordings-and-transcripts.mdx
+++ b/communication/recordings-and-transcripts.mdx
@@ -22,7 +22,10 @@ between you and your assistant, Transcripts is the historian's view of
**Chat**, **Email**, **Call**, **SMS**, **WhatsApp**, **Slack**,
**Discord** — or **All** for the full stream. Calls of every kind
(Unify Meet, phone, WhatsApp calls, Google Meet, Teams meetings) are
- gathered under **Call**.
+ gathered under **Call**. Channels without a rail entry of their own —
+ [Microsoft Teams](/communication/microsoft-teams) messages and
+ [API messages](/communication/api) — are in the record too; find them
+ under **All**.
- **Switch layout.** **Threads** mode groups the record into
conversations — an email thread, a call, an SMS exchange — each showing
its subject, channel, message count, and participants. **Feed** mode is
diff --git a/communication/setup.mdx b/communication/setup.mdx
index 17a3e916d..b2876606a 100644
--- a/communication/setup.mdx
+++ b/communication/setup.mdx
@@ -52,6 +52,20 @@ From there:
Add Discord and your assistant gets a bot identity that can DM you and
join your servers. See [Discord](/communication/discord).
+
+ Choose **Add to Slack** and authorize the Unify app. You connect a
+ workspace **once** for the whole account or organization — every
+ assistant becomes reachable through it, and you address a specific one
+ by naming it in the mention. Only the account owner, or an org owner or
+ admin, can connect it. See [Slack](/communication/slack).
+
+
+ Nothing to create per assistant — a Microsoft admin installs the Unify
+ Teams app once for the organization and every assistant is reachable
+ through it. See [Microsoft Teams](/communication/microsoft-teams). (An
+ assistant can also act through its *own* Microsoft 365 account instead;
+ that's part of the [workspace connection](/workspace/teams).)
+
@@ -72,6 +86,7 @@ senders are registered), which are paid in credits from your wallet:
| WhatsApp | Yes | Yes |
| Discord | Yes | Yes |
| Email | Free | Free |
+| Slack & Microsoft Teams | Free | Free |
| Console chat & Unify Meet | Free | Free |
Exact amounts vary by channel and country, and are always shown in the
diff --git a/communication/slack.mdx b/communication/slack.mdx
index 4b794c4a0..d1fbc9b45 100644
--- a/communication/slack.mdx
+++ b/communication/slack.mdx
@@ -1,30 +1,68 @@
---
title: "Slack"
-description: "Bring your assistant into your Slack workspace"
+description: "Reach your assistants from your Slack workspace"
---
-Add your assistant to Slack and it becomes a member of your workspace you can
-DM, @mention, and collaborate with in channels.
+The **Unify Slack app** brings your assistants into Slack — DMs, channels,
+and threads. It's installed once for your account or organization, and every
+assistant becomes reachable through it. Like the [Teams
+app](/communication/microsoft-teams), your assistants speak as the shared
+Unify app rather than as separate Slack members, so addressing works by
+naming the teammate you want.
## Setup
-Connect Slack from the Console — your assistant can open the setup flow for
-you, or you'll find it under your assistant's **Contact Details → Slack**.
-A workspace admin approves the Unify Slack app, and your assistant appears in
-your workspace.
+Open your assistant's **Contact Details → Slack** and choose **Add to
+Slack**. You connect a workspace once — every assistant on the account (or
+in the organization) becomes reachable through it, with nothing to configure
+per assistant.
+
+
+ Only the account owner, or an organization owner or admin, can connect the
+ workspace. If you're not one of them, the Slack tab tells you who to ask.
+
+
+## Reaching a specific teammate
+
+Mention the app and include the teammate's name:
+
+```
+@Unify Alex, can you pull yesterday's numbers?
+```
+
+From there, the conversation sticks:
+
+- **In a channel**, naming a teammate hands them the thread. Replies in that
+ thread reach the same assistant without naming them again.
+- **In a DM** with the app, the first message goes to your **T-W1N**, the
+ coordinator that fields anything unaddressed. Name a teammate in the DM and
+ the conversation is pinned to them from then on.
+- **If the name doesn't match** anyone — or matches more than one teammate —
+ your T-W1N takes the thread and sorts it out in place rather than guessing.
+
+
+ In a channel, a message that names nobody and isn't part of an established
+ thread reaches **no one**. Name the teammate you want on the first message;
+ after that the thread carries the routing.
+
+
+A thread or DM that goes quiet for two weeks forgets which assistant it
+belonged to. Name the teammate again and it picks straight back up.
## What you can do
-- **Direct messages** — DM your assistant for the same one-on-one
- conversation you'd have anywhere else.
-- **Channel mentions** — @mention your assistant in a channel and it joins
- the discussion. It replies in-thread, keeping channels tidy.
+- **Direct messages** — the same one-on-one conversation you'd have anywhere
+ else, with your T-W1N or with any teammate you've named.
+- **Channel threads** — mention the app in a channel and it replies in
+ thread, keeping the channel tidy. Invite the app to the channel first.
- **File attachments** — share files in Slack and your assistant picks them
up and works with them.
## Good to know
-- Your assistant only speaks in a channel when it's mentioned or directly
- relevant — it won't spam your team's conversations.
+- Your assistant only speaks when it's addressed — it won't spam your team's
+ conversations.
+- Coordinators are personal. In an organization, each member's unaddressed
+ messages go to *their own* T-W1N, not to a shared one.
- It's the same assistant across every surface: a task you discussed in Slack
can be delivered over email, and vice versa.
diff --git a/communication/sms.mdx b/communication/sms.mdx
index fc06580bd..b7a15b950 100644
--- a/communication/sms.mdx
+++ b/communication/sms.mdx
@@ -28,6 +28,9 @@ text it. If not, see [Setting up channels](/communication/setup).
- SMS is **text only** — for photos, documents, and voice notes, use
[WhatsApp](/communication/whatsapp) or [email](/communication/email)
instead.
-- Like calls, SMS works between your assistant and its **known contacts**.
- Strangers texting the number get a polite pointer to the Console rather
- than a conversation.
+- Like calls, SMS is for people your assistant **knows**. A text to one of
+ T-W1N's shared numbers from an unrecognized number gets an automated reply
+ rather than a conversation. On an assistant's own number the text reaches
+ it, but the sender lands as a [contact](/communication/contacts) with
+ responses switched off — your assistant tells you about them and asks how
+ to handle it instead of replying.
diff --git a/communication/unify-meet.mdx b/communication/unify-meet.mdx
index f4e360f2e..90e04e568 100644
--- a/communication/unify-meet.mdx
+++ b/communication/unify-meet.mdx
@@ -70,3 +70,6 @@ This is where Unify Meet really shines:
conversation uninvited.
- **One call at a time.** Your assistant holds one live voice conversation at
a time — if you're on a Meet call, it won't simultaneously be on the phone.
+- **Not only one-to-one.** The same call surface runs across
+ [rooms](/communication/group-chats): ring a colleague, a group, or a whole
+ team, and the room's assistants join the call with everyone else.
diff --git a/mint.json b/mint.json
index 1668e868e..87400cb38 100644
--- a/mint.json
+++ b/mint.json
@@ -48,6 +48,7 @@
"pages": [
"communication/overview",
"communication/console-chat",
+ "communication/group-chats",
"communication/unify-meet",
"communication/phone-calls",
"communication/sms",
@@ -56,6 +57,7 @@
"communication/slack",
"communication/microsoft-teams",
"communication/discord",
+ "communication/api",
"communication/setup",
"communication/voice",
"communication/behavior",