diff --git a/docs/channels/msteams.md b/docs/channels/msteams.md
index 1efbafbd5e4..f5123d6f255 100644
--- a/docs/channels/msteams.md
+++ b/docs/channels/msteams.md
@@ -136,63 +136,56 @@ Example:
}
```
-## How it works
+## Azure Bot setup
-1. Ensure the Microsoft Teams plugin is available.
- - Current packaged OpenClaw releases already bundle it.
- - Older/custom installs can add it manually with the commands above.
-2. Create an **Azure Bot** (App ID + secret + tenant ID).
-3. Build a **Teams app package** that references the bot and includes the RSC permissions below.
-4. Upload/install the Teams app into a team (or personal scope for DMs).
-5. Configure `msteams` in `~/.openclaw/openclaw.json` (or env vars) and start the gateway.
-6. The gateway listens for Bot Framework webhook traffic on `/api/messages` by default.
+Before configuring OpenClaw, create an Azure Bot resource and capture its credentials.
-## Azure Bot Setup (Prerequisites)
+
+
+ Go to [Create Azure Bot](https://portal.azure.com/#create/Microsoft.AzureBot) and fill in the **Basics** tab:
-Before configuring OpenClaw, you need to create an Azure Bot resource.
+ | Field | Value |
+ | ------------------ | -------------------------------------------------------- |
+ | **Bot handle** | Your bot name, e.g. `openclaw-msteams` (must be unique) |
+ | **Subscription** | Your Azure subscription |
+ | **Resource group** | Create new or use existing |
+ | **Pricing tier** | **Free** for dev/testing |
+ | **Type of App** | **Single Tenant** (recommended) |
+ | **Creation type** | **Create new Microsoft App ID** |
-### Step 1: Create Azure Bot
+
+ New multi-tenant bots were deprecated after 2025-07-31. Use **Single Tenant** for new bots.
+
-1. Go to [Create Azure Bot](https://portal.azure.com/#create/Microsoft.AzureBot)
-2. Fill in the **Basics** tab:
+ Click **Review + create** → **Create** (wait ~1-2 minutes).
- | Field | Value |
- | ------------------ | -------------------------------------------------------- |
- | **Bot handle** | Your bot name, e.g., `openclaw-msteams` (must be unique) |
- | **Subscription** | Select your Azure subscription |
- | **Resource group** | Create new or use existing |
- | **Pricing tier** | **Free** for dev/testing |
- | **Type of App** | **Single Tenant** (recommended - see note below) |
- | **Creation type** | **Create new Microsoft App ID** |
+
-> **Deprecation notice:** Creation of new multi-tenant bots was deprecated after 2025-07-31. Use **Single Tenant** for new bots.
+
+ From the Azure Bot resource → **Configuration**:
-3. Click **Review + create** → **Create** (wait ~1-2 minutes)
+ - copy **Microsoft App ID** → `appId`
+ - **Manage Password** → **Certificates & secrets** → **New client secret** → copy the value → `appPassword`
+ - **Overview** → **Directory (tenant) ID** → `tenantId`
-### Step 2: Get Credentials
+
-1. Go to your Azure Bot resource → **Configuration**
-2. Copy **Microsoft App ID** → this is your `appId`
-3. Click **Manage Password** → go to the App Registration
-4. Under **Certificates & secrets** → **New client secret** → copy the **Value** → this is your `appPassword`
-5. Go to **Overview** → copy **Directory (tenant) ID** → this is your `tenantId`
+
+ Azure Bot → **Configuration** → set **Messaging endpoint**:
-### Step 3: Configure Messaging Endpoint
+ - Production: `https://your-domain.com/api/messages`
+ - Local dev: use a tunnel (see [Local development](#local-development-tunneling))
-1. In Azure Bot → **Configuration**
-2. Set **Messaging endpoint** to your webhook URL:
- - Production: `https://your-domain.com/api/messages`
- - Local dev: Use a tunnel (see [Local Development](#local-development-tunneling) below)
+
-### Step 4: Enable Teams Channel
-
-1. In Azure Bot → **Channels**
-2. Click **Microsoft Teams** → Configure → Save
-3. Accept the Terms of Service
+
+ Azure Bot → **Channels** → click **Microsoft Teams** → Configure → Save. Accept the Terms of Service.
+
+
-## Federated Authentication (Certificate + Managed Identity)
+## Federated authentication
> Added in 2026.3.24
@@ -287,7 +280,7 @@ Use Azure Managed Identity for passwordless authentication. This is ideal for de
- `MSTEAMS_USE_MANAGED_IDENTITY=true`
- `MSTEAMS_MANAGED_IDENTITY_CLIENT_ID=` (only for user-assigned)
-### AKS Workload Identity Setup
+### AKS workload identity setup
For AKS deployments using workload identity:
@@ -334,7 +327,7 @@ For AKS deployments using workload identity:
**Default behavior:** When `authType` is not set, OpenClaw defaults to client secret authentication. Existing configurations continue to work without changes.
-## Local Development (Tunneling)
+## Local development (tunneling)
Teams can't reach `localhost`. Use a tunnel for local development:
@@ -353,7 +346,7 @@ tailscale funnel 3978
# Use your Tailscale funnel URL as the messaging endpoint
```
-## Teams Developer Portal (Alternative)
+## Teams Developer Portal (alternative)
Instead of manually creating a manifest ZIP, you can use the [Teams Developer Portal](https://dev.teams.microsoft.com/apps):
@@ -367,7 +360,7 @@ Instead of manually creating a manifest ZIP, you can use the [Teams Developer Po
This is often easier than hand-editing JSON manifests.
-## Testing the Bot
+## Testing the bot
**Option A: Azure Web Chat (verify webhook first)**
@@ -456,7 +449,7 @@ The action is gated by `channels.msteams.actions.memberInfo` (default: enabled w
- In other words, allowlists gate who can trigger the agent; only specific supplemental context paths are filtered today.
- DM history can be limited with `channels.msteams.dmHistoryLimit` (user turns). Per-user overrides: `channels.msteams.dms[""].historyLimit`.
-## Current Teams RSC Permissions (Manifest)
+## Current Teams RSC permissions
These are the **existing resourceSpecific permissions** in our Teams app manifest. They only apply inside the team/chat where the app is installed.
@@ -474,7 +467,7 @@ These are the **existing resourceSpecific permissions** in our Teams app manifes
- `ChatMessage.Read.Chat` (Application) - receive all group chat messages without @mention
-## Example Teams Manifest (redacted)
+## Example Teams manifest
Minimal, valid example with the required fields. Replace IDs and URLs.
@@ -547,7 +540,7 @@ To update an already-installed Teams app (e.g., to add RSC permissions):
## Capabilities: RSC only vs Graph
-### With **Teams RSC only** (app installed, no Graph API permissions)
+### Teams RSC only (no Graph API permissions)
Works:
@@ -561,7 +554,7 @@ Does NOT work:
- Downloading attachments stored in SharePoint/OneDrive.
- Reading message history (beyond the live webhook event).
-### With **Teams RSC + Microsoft Graph Application permissions**
+### Teams RSC plus Microsoft Graph application permissions
Adds:
@@ -593,7 +586,7 @@ If you need images/files in **channels** or want to fetch **message history**, y
**Additional permission for user mentions:** User @mentions work out of the box for users in the conversation. However, if you want to dynamically search and mention users who are **not in the current conversation**, add `User.Read.All` (Application) permission and grant admin consent.
-## Known Limitations
+## Known limitations
### Webhook timeouts
@@ -615,40 +608,53 @@ Teams markdown is more limited than Slack or Discord:
## Configuration
-Key settings (see `/gateway/configuration` for shared channel patterns):
+Grouped settings (see `/gateway/configuration` for shared channel patterns).
-- `channels.msteams.enabled`: enable/disable the channel.
-- `channels.msteams.appId`, `channels.msteams.appPassword`, `channels.msteams.tenantId`: bot credentials.
-- `channels.msteams.webhook.port` (default `3978`)
-- `channels.msteams.webhook.path` (default `/api/messages`)
-- `channels.msteams.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing)
-- `channels.msteams.allowFrom`: DM allowlist (AAD object IDs recommended). The wizard resolves names to IDs during setup when Graph access is available.
-- `channels.msteams.dangerouslyAllowNameMatching`: break-glass toggle to re-enable mutable UPN/display-name matching and direct team/channel name routing.
-- `channels.msteams.textChunkLimit`: outbound text chunk size.
-- `channels.msteams.chunkMode`: `length` (default) or `newline` to split on blank lines (paragraph boundaries) before length chunking.
-- `channels.msteams.mediaAllowHosts`: allowlist for inbound attachment hosts (defaults to Microsoft/Teams domains).
-- `channels.msteams.mediaAuthAllowHosts`: allowlist for attaching Authorization headers on media retries (defaults to Graph + Bot Framework hosts).
-- `channels.msteams.requireMention`: require @mention in channels/groups (default true).
-- `channels.msteams.replyStyle`: `thread | top-level` (see [Reply Style](#reply-style-threads-vs-posts)).
-- `channels.msteams.teams..replyStyle`: per-team override.
-- `channels.msteams.teams..requireMention`: per-team override.
-- `channels.msteams.teams..tools`: default per-team tool policy overrides (`allow`/`deny`/`alsoAllow`) used when a channel override is missing.
-- `channels.msteams.teams..toolsBySender`: default per-team per-sender tool policy overrides (`"*"` wildcard supported).
-- `channels.msteams.teams..channels..replyStyle`: per-channel override.
-- `channels.msteams.teams..channels..requireMention`: per-channel override.
-- `channels.msteams.teams..channels..tools`: per-channel tool policy overrides (`allow`/`deny`/`alsoAllow`).
-- `channels.msteams.teams..channels..toolsBySender`: per-channel per-sender tool policy overrides (`"*"` wildcard supported).
-- `toolsBySender` keys should use explicit prefixes:
- `id:`, `e164:`, `username:`, `name:` (legacy unprefixed keys still map to `id:` only).
-- `channels.msteams.actions.memberInfo`: enable or disable the Graph-backed member info action (default: enabled when Graph credentials are available).
-- `channels.msteams.authType`: authentication type — `"secret"` (default) or `"federated"`.
-- `channels.msteams.certificatePath`: path to PEM certificate file (federated + certificate auth).
-- `channels.msteams.certificateThumbprint`: certificate thumbprint (optional, not required for auth).
-- `channels.msteams.useManagedIdentity`: enable managed identity auth (federated mode).
-- `channels.msteams.managedIdentityClientId`: client ID for user-assigned managed identity.
-- `channels.msteams.sharePointSiteId`: SharePoint site ID for file uploads in group chats/channels (see [Sending files in group chats](#sending-files-in-group-chats)).
+
+
+ - `channels.msteams.enabled`
+ - `channels.msteams.appId`, `appPassword`, `tenantId`: bot credentials
+ - `channels.msteams.webhook.port` (default `3978`)
+ - `channels.msteams.webhook.path` (default `/api/messages`)
+
-## Routing & Sessions
+
+ - `authType`: `"secret"` (default) or `"federated"`
+ - `certificatePath`, `certificateThumbprint`: federated + certificate auth (thumbprint optional)
+ - `useManagedIdentity`, `managedIdentityClientId`: federated + managed identity auth
+
+
+
+ - `dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing)
+ - `allowFrom`: DM allowlist, prefer AAD object IDs; the wizard resolves names when Graph access is available
+ - `dangerouslyAllowNameMatching`: break-glass for mutable UPN/display-name and team/channel name routing
+ - `requireMention`: require @mention in channels/groups (default `true`)
+
+
+
+ All of these override the top-level defaults:
+
+ - `teams..replyStyle`, `.requireMention`
+ - `teams..tools`, `.toolsBySender`: per-team tool policy defaults
+ - `teams..channels..replyStyle`, `.requireMention`
+ - `teams..channels..tools`, `.toolsBySender`
+
+ `toolsBySender` keys accept `id:`, `e164:`, `username:`, `name:` prefixes (unprefixed keys map to `id:`). `"*"` is a wildcard.
+
+
+
+
+ - `textChunkLimit`: outbound text chunk size
+ - `chunkMode`: `length` (default) or `newline` (split on paragraph boundaries before length)
+ - `mediaAllowHosts`: inbound attachment host allowlist (defaults to Microsoft/Teams domains)
+ - `mediaAuthAllowHosts`: hosts that may receive Authorization headers on retries (defaults to Graph + Bot Framework)
+ - `replyStyle`: `thread | top-level` (see [Reply style](#reply-style-threads-vs-posts))
+ - `actions.memberInfo`: toggle the Graph-backed member info action (default on when Graph is available)
+ - `sharePointSiteId`: required for file uploads in group chats/channels (see [Sending files in group chats](#sending-files-in-group-chats))
+
+
+
+## Routing and sessions
- Session keys follow the standard agent format (see [/concepts/session](/concepts/session)):
- Direct messages share the main session (`agent::`).
@@ -656,7 +662,7 @@ Key settings (see `/gateway/configuration` for shared channel patterns):
- `agent::msteams:channel:`
- `agent::msteams:group:`
-## Reply Style: Threads vs Posts
+## Reply style: threads vs posts
Teams recently introduced two channel UI styles over the same underlying data model:
@@ -691,7 +697,7 @@ Teams recently introduced two channel UI styles over the same underlying data mo
}
```
-## Attachments & Images
+## Attachments and images
**Current limitations:**
@@ -774,7 +780,7 @@ Per-user sharing is more secure as only the chat participants can access the fil
Uploaded files are stored in a `/OpenClawShared/` folder in the configured SharePoint site's default document library.
-## Polls (Adaptive Cards)
+## Polls (adaptive cards)
OpenClaw sends Teams polls as Adaptive Cards (there is no native Teams poll API).
@@ -783,7 +789,7 @@ OpenClaw sends Teams polls as Adaptive Cards (there is no native Teams poll API)
- The gateway must stay online to record votes.
- Polls do not auto-post result summaries yet (inspect the store file if needed).
-## Presentation Cards
+## Presentation cards
Send semantic presentation payloads to Teams users or conversations using the `message` tool or CLI. OpenClaw renders them as Teams Adaptive Cards from the generic presentation contract.
@@ -871,7 +877,7 @@ Note: Without the `user:` prefix, names default to group/team resolution. Always
- Proactive messages are only possible **after** a user has interacted, because we store conversation references at that point.
- See `/gateway/configuration` for `dmPolicy` and allowlist gating.
-## Team and Channel IDs (Common Gotcha)
+## Team and channel IDs
The `groupId` query parameter in Teams URLs is **NOT** the team ID used for configuration. Extract IDs from the URL path instead:
@@ -897,7 +903,7 @@ https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?gr
- Channel ID = path segment after `/channel/` (URL-decoded)
- **Ignore** the `groupId` query parameter
-## Private Channels
+## Private channels
Bots have limited support in private channels: