feat(skills): add setup-teams-channel skill - #11
Conversation
A repository-owned, browser-first skill for the provider half of getting a locally running Channels agent to answer in Microsoft Teams: the Azure Bot and its Entra app, the tenant-wide Graph consent, the Teams app package, and the install. Grounded in the Teams setup wizard shipped on CopilotKit/Intelligence main as of 2026-08-03 — the seven-step sequence, the three write-only credentials, the /api/channels/adapters/teams/messages endpoint path, the Files.ReadWrite.All consent requirement, the ChannelMessage.Read.Group behaviour split, and the reaction preview dependency were all read from that wizard rather than assumed. Deliberately makes no reference to the `copilotkit channels` commands: per Ben Taylor on 2026-08-03, those defer to the web app until they have more real-world usage. The skill routes to the Intelligence dashboard throughout, matching setup-slack-channel. Two things this skill does that the wizard does not: - Phase 0 checks access before building anything. Two of the seven steps need privileges most developers lack — an Azure subscription for the Azure Bot, and an admin role to grant tenant-wide consent — and both fail late, after an Entra app already exists. Verified against a real tenant that had neither. - Names the ChannelMessage.Read.Group symptom explicitly. A bot that answers mentions and ignores ordinary channel messages is a correctly installed bot without resource-specific consent, not a delivery failure. The guardrail section is marked unverified: unlike setup-slack-channel, whose prohibitions came from observed agent failures against a live setup, this has not been exercised against a completed Teams install. The Azure subscription gate blocked validation. .claude/skills/setup-teams-channel is a symlink to the canonical copy, matching the existing setup-slack-channel pattern.
Drove the whole provider-side flow in a live tenant on 2026-08-03. Two of the
skill's claims were wrong, one was right, and several new facts surfaced. All of
it is now grounded in observation rather than in the dashboard's happy path.
Wrong, and removed:
- Phase 0 no longer stops on "no Azure subscription". The Teams Developer Portal
(Tools > Bot management > New bot) creates the bot, its Entra app registration,
the client secret, and the messaging endpoint from a single form field with no
subscription at all. Proven in a tenant holding zero Azure subscriptions. The
previous gate would have halted a run that can actually succeed, which is the
worst possible defect in a skill an agent is told to trust.
- Step 1 now routes to the Developer Portal and explicitly says to ignore the
dashboard's "Open Azure portal" button.
Right, and kept as gate 1:
- Tenant-wide admin consent for Files.ReadWrite.All. This is what actually
blocked the run, and it blocks late: bot, endpoint, credentials and Channel all
succeed, then the adapter attach fails.
New, from the run:
- A "When the adapter reports teams_setup_failed" section. Its own remediation
text ("Reconnect the Teams app") points away from the cause; the real
diagnostic order is client ID, Teams channel, endpoint, then API permissions.
In the observed case the first three passed and API permissions was empty.
- The bot's ID is the Entra app's Application (client) ID. Confirmed, which
removes a guess the earlier draft flagged as unverified.
- Microsoft Teams is enabled by default on a Developer-Portal-created bot.
- A Developer-Portal app starts with no API permissions, so step 4 is an
addition, not a confirmation.
- Phase 0 gate 2: the org-wide Channel cap. It is org-wide rather than
per-project, so a new project does not help, and a capped Create channel button
is indistinguishable from a disabled one — no disabled attribute, silently
no-ops. Read the "N of M used" counter. Worded to survive the cap changing.
- Deleting another provider's Channel to free a slot trades one working setup for
another, and the credentials on the deleted side are write-only.
Provenance now separates what was observed from what is still read from source:
the ready()/setup_required trap, the ChannelMessage.Read.Group split and the
reaction preview dependency remain unverified, because the consent gate stopped
the run before a real mention could be answered.
references/azure-bot-and-entra.md renamed to
references/bot-registration-and-permissions.md to match.
|
Drove the whole provider-side flow in a live tenant today ( The Azure requirement does not existThe skill — and the dashboard's Teams step it was derived from — routed step 1 through That was wrong. Developer Portal → Tools → Bot management → New bot asks for a name and nothing else — no subscription, no resource group, no region, no pricing tier — and produces the bot, its Entra app registration, the client secret, and the messaging endpoint. Done in a tenant holding zero Azure subscriptions. So the original gate would have halted a run that can actually succeed. That is the worst kind of defect here: it was also the section I'd argued hardest for, so it was the one most likely to be trusted. Removed, and step 1 now says explicitly to ignore the dashboard's Open Azure portal button. This is a product finding as much as a skill fix. If Developer Portal is the shorter path, the dashboard is sending everyone through billing they may not control. The consent gate is real, and it is what actually blocked the run
Better than either gate being right: both are now evidence-backed rather than inferred. New section: when the adapter reports
|
Companion to #7. A repository-owned, browser-first skill for the provider half of getting a locally running Channels agent to answer in Microsoft Teams: the Azure Bot and its Entra app, the tenant-wide Graph consent, the Teams app package, and the install.
Draft, deliberately. The guardrails have not been validated against a completed Teams install — see What is unverified at the bottom. I would rather this sit in draft than borrow the credibility #7 earned by actually being tested.
Where the content comes from
Every claim was read from the Teams setup wizard shipped on
CopilotKit/Intelligencemainas of 2026-08-03 (apps/app-frontend/react-shell/src/channels/teams-guided-adapter-setup.tsxandteams-credential-fields.tsx), not derived from memory of how Teams bots usually work:/api/channels/adapters/teams/messagesFiles.ReadWrite.Allapplication permission and its Grant admin consent requirementChannelMessage.Read.Groupresource-specific consent and exactly what changes without itTwo things the skill does that the wizard does not
1. Phase 0 checks access before building anything.
Two of the seven steps need privileges most developers in most tenants do not have, and both fail late — after an Entra app already exists and credentials have been pasted:
Files.ReadWrite.All, an application-wide Graph permissionThis was verified against a real tenant, not theorised:
Subscriptions: 0 of 0and a blankYour Role:inRoles & admins. Notably, directory ownership does not clear the first one — Azure subscriptions are a billing artifact separate from Entra roles, so a Global Administrator with no subscription is still stuck at step 1. The skill says so explicitly, because it is a natural thing to assume.Phase 0 also records the inverse, so agents stop treating non-blockers as blockers: registering an Entra app is usually permitted for all members via the tenant's Users can register applications setting, and sideloading needs only Upload a custom app under Teams → Apps → Manage your apps, which is independent of any admin role.
And one operational note that cost real time to discover: Entra role assignments do not appear until the session holds a fresh token, so a freshly granted role reads as blank until sign-out and back in.
2. It names the
ChannelMessage.Read.Groupsymptom.That permission is resource-specific consent, granted at install, not in Entra. Granted, the Channel receives ambient unmentioned channel messages. Not granted, the bot receives only what Teams routes directly to it — mentions and personal chats.
So "the bot replies when I @-mention it but ignores everything else" is the expected shape of a correctly installed bot missing that consent. Without this written down it reads as a delivery bug, and the debugging goes to entirely the wrong place.
Consistent with the CLI deferral
The skill makes no reference to the
copilotkit channelscommands and routes to the Intelligence dashboard throughout, matchingsetup-slack-channel. Per Ben Taylor on 2026-08-03, those commands defer to the web app until they have more real-world usage.channels-flow.tswas used only as a source for what the app package and client id must contain — never as developer-facing instructions.Layout
.claude/skills/setup-teams-channelis a symlink (git mode120000) to the canonical copy, matching the existingsetup-slack-channelpattern.AGENTS.mdgains a table row and the symlink note now covers both skills.Trigger boundaries
Three skills now touch this area, so the description is scoped to avoid the collision tracked in #10:
setup-slack-channel— the same, for Slackcopilotkit-channels(inCopilotKit/CopilotKit/skills) — the code half; assumes the provider app existsThe description names the other two and hands off. Note the third lives in another repo, so the full three-way split completes alongside CopilotKit/CopilotKit#6340.
What is unverified
The ordering and guardrails have not been exercised against a completed Teams install. #7's authority came from three scenarios run with fresh agents without the skill to establish a baseline, then re-run with it. This skill has had none of that, because the Azure subscription gate blocked validation. The skill states this in its own closing section rather than leaving a reader to assume parity with #7.
Reviewers should treat the sequence as sound but provisional, and the prohibitions as predictions.
The prediction I would most like tested. #7's hardest prohibition exists because two of three baseline agents independently invented the direct-adapter escape hatch under pressure. Teams has a worse version of that trap, and it is one we ship:
examples/teamsin the CopilotKit monorepo is a working Teams demo built on the self-hosted@copilotkit/channels/teamsadapter, explicitly "testable in the Microsoft 365 Agents Playground with no Microsoft credentials." An agent stuck at the Azure subscription gate is one search away from it. That pivot is not something it has to invent — it is a committed, working repo that appears to solve the exact problem. The prohibition is already written; whether it holds is the first thing a baseline run should try to break.Follow-ups, not blockers