add-teams
Add Microsoft Teams channel integration via Chat SDK.
Install / Use
npx skills add nanocoai/nanoclaw --skill add-teamsInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
Content & MediaSupported Platforms
Tags
Our assessment of add-teams
add-teams scores 92/100 on our quality scale, 83rd of 398 Content & Media skills we index (top 21%).
Its SKILL.md is 28 KB long, well organised into 38 sections with 36 code examples: a thorough specification that gives an agent plenty to work with.
With 30,846 GitHub stars, it is one of the more widely adopted skills in the catalogue.
Maintenance, license and trust
- The repository was last updated yesterday, so add-teams is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
add-teams compared with similar skills
All 4 of these similar skills score higher than add-teams; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| add-teams (this skill)by nanocoai | 92 | 30.8k | 1d ago | SKILL.md |
| siyuanby siyuan-note | 100 | 46.5k | today | MCP Server |
| algorithmic-artby anthropics | 100 | 177.9k | 3d ago | SKILL.md |
| pptxby anthropics | 100 | 177.9k | 3d ago | SKILL.md |
| designby nextlevelbuilder | 100 | 130.2k | 5d ago | SKILL.md |
Frequently asked questions
- How do I install add-teams?
- Run
npx skills add nanocoai/nanoclaw --skill add-teams. The install tabs above show the steps for each supported agent. - Which AI agents does add-teams work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is add-teams safe to use?
- It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is add-teams still maintained?
- The repository was last updated yesterday, so add-teams is actively maintained.
Skill content
View source on GitHubname: add-teams description: Add Microsoft Teams channel integration via Chat SDK.
Add Microsoft Teams Channel
Adds Microsoft Teams support via the Chat SDK bridge — interactive chat in team
channels, group chats, and direct messages. NanoClaw doesn't ship channels in
trunk — this skill copies the Teams adapter in from the channels branch.
The mechanical steps under Apply carry nc: directive fences: an agent
reads the prose and applies them, and a parser can apply them deterministically
from the same document. Every directive is idempotent, so the whole skill is
safe to re-run; anything a parser can't apply falls back to the prose beside it.
Teams has no "paste a token" shortcut — a bot has to exist in Microsoft's cloud before it can receive a message. The Microsoft Teams CLI collapses that into one sign-in and one create command: it registers the Entra app, generates the client secret, registers a Teams-managed bot (through the Teams Developer Portal — no Azure subscription needed), uploads the app package, and hands back an install link. The old ~7-step Azure portal walk survives only as a fallback in Alternatives for tenants where the Developer Portal is blocked.
Apply
1. Copy the adapter and its registration test
Fetch the channels branch and copy the Teams adapter and its registration test
into src/channels/ (overwrite — the branch is canonical):
src/channels/teams.ts
src/channels/teams-registration.test.ts
2. Register the adapter
Append the self-registration import to the channel barrel (skipped if the line is already present). This one line is the skill's only reach-in into core:
import './teams.js';
3. Install the adapter package
Pinned to an exact version — the supply-chain policy rejects ranges and latest:
@chat-adapter/teams@4.29.0
4. Build and validate
Build first: it guards the typed createChatSdkBridge(...) core call and proves
the dependency is installed. Then run the one integration test.
pnpm run build
pnpm exec vitest run src/channels/teams-registration.test.ts
teams-registration.test.ts imports the real channel barrel and asserts the
registry contains teams. It goes red if the import line is deleted or drifts,
if the barrel fails to evaluate, or if @chat-adapter/teams isn't installed (the
import throws) — so it also covers the dependency from step 3. End-to-end
delivery against a real Teams workspace is verified manually once the service
runs.
Credentials
The adapter is installed and registered, but it can't receive a message until a bot exists, points at this machine, and is installed into Teams. The Teams CLI does all of that below.
Check for existing credentials
Re-running teams app create provisions a brand-new app registration and bot
each time — it never reuses the first one. So the flow starts with a probe:
when .env already carries a Teams credential — either key; a partial pair
means a half-finished setup that creating ANOTHER app would only corrupt —
every step below (prompts included) is skipped and the flow drops straight
through to Restart. To rotate credentials or finish a partial
configuration, see Troubleshooting; if your tunnel URL
changed, the fix is teams app update, not a re-run (also in Troubleshooting).
( grep -q '^TEAMS_APP_ID=.' .env 2>/dev/null || grep -q '^TEAMS_APP_PASSWORD=.' .env 2>/dev/null ) && echo yes || echo no
Before creating anything, tell the user:
Confirm you have everything Teams setup needs:
1. A Microsoft 365 account that can create Entra app registrations and upload custom apps (sideloading) — free personal Teams does NOT qualify; you need a Microsoft 365 Business / EDU / developer tenant.
2. A way to expose an HTTPS endpoint that forwards to this machine's webhook port 3000 (e.g. a Cloudflare Tunnel, or a reverse-proxied VPS). Start it now if it isn't running — e.g. `cloudflared tunnel --url http://localhost:3000` — the create step needs the URL up front. The next prompt asks for its public base URL: just the https:// origin, no trailing path.
Note: the bot is created single-tenant (only your own Microsoft 365 tenant can install it) — the right default for a self-hosted assistant. If you need a bot other tenants can install, set it up manually via the Alternatives section of this skill instead.
Public URL
Microsoft delivers bot messages to an HTTPS endpoint you control; it has to
reach this machine's webhook server (port 3000, configurable via
WEBHOOK_PORT) at /webhook/teams.
Paste your tunnel's public https:// URL — e.g. https://your-tunnel.trycloudflare.com
App name
One more choice belongs to the human before anything is created. The name is
used everywhere at once: the Entra app registration, the bot, and the Teams
app are all created under it. There is no client-secret name to pick on this
path — the CLI generates the secret itself (Entra displayName default,
2-year expiry); rotating it later is in Troubleshooting.
What should the bot be called? One name covers the Entra app registration, the bot, and the Teams app (letters, digits, spaces, . _ -; max 30 characters) — e.g. NanoClaw.
Install the Teams CLI
Installed globally with npm — not as a workspace dependency — deliberately:
the CLI's credential store (keytar) is a native module whose install script
must run to fetch its prebuilt binary, and pnpm's supply-chain policy blocks
dependency build scripts — a workspace install leaves the sign-in unable to
persist. The global install matches Microsoft's own instruction and keeps the
workspace policy intact. Pinned; re-running is a no-op. (If npm reports
EACCES here, your global prefix needs root — prefer a user-level Node like
nvm, or npm config set prefix ~/.npm-global.) --loglevel=error because
npm runs inside a pnpm script here and warns about every pnpm config var it
inherits — pure noise; real errors still print.
npm install -g @microsoft/teams.cli@3.0.2 --loglevel=error
npm's global bin directory is not reliably on PATH (custom prefixes rarely
are), so every step below calls the CLI by its absolute path,
$(npm prefix -g)/bin/teams (stderr of the prefix lookup silenced — same
pnpm-config noise as above). Where this document says to run teams … by
hand, use that path too if plain teams isn't found.
Sign in to Microsoft 365
Every teams command is a separate process, so the sign-in must survive into
the next one via the CLI's on-disk token cache. A "libsecret not found —
token cache will be stored unencrypted" warning here is safe to ignore: the
CLI falls back to a plaintext cache file that persists fine, and setup signs
the session out at the end anyway. The login output may
also report "Azure CLI: not installed" — informational only; this flow
creates a Teams-managed bot precisely so the Azure CLI is never needed (it
only matters for --azure bots and the manual portal path). The
step below verifies persistence by re-reading the session from a fresh
process after login. In an interactive terminal the login opens a browser;
on a headless box (SSH) it prints a device code — open
microsoft.com/devicelogin on any machine and enter it. If this step fails,
run teams login then teams status by hand: status must say logged in, or
the cache is not persisting (see Troubleshooting).
"$(npm prefix -g 2>/dev/null)/bin/teams" login && "$(npm prefix -g 2>/dev/null)/bin/teams" status --json 2>/dev/null | grep -q '"loggedIn": true' && printf '=== NANOCLAW SETUP: TEAMS-LOGIN ===\nSTATUS: success\n=== END ===\n'
Create the bot
One command registers the Entra app, generates a client secret (Graph can take
~30s to see the new app — the CLI retries), registers a Teams-managed bot, and
uploads the app package to the Teams Developer Portal. It needs the sign-in
from the previous step (AUTH_REQUIRED means run that first). The bot is
always created single-tenant (--sign-in-audience myOrg) — the right default
for a self-hosted assistant, applied without asking; for a bot other
Microsoft 365 tenants can install, set it up manually per
Alternatives.
"$(npm prefix -g 2>/dev/null)/bin/teams" app create --name "{{app_name}}" --endpoint "{{public_url}}/webhook/teams" --sign-in-audience myOrg --json
Store the credentials
The adapter reads these from .env (set-if-absent — a value you've already
filled in is never overwritten). The pairing matters: SingleTenant requires
TEAMS_APP_TENANT_ID, and a multi-tenant app must instead set
TEAMS_APP_TYPE=MultiTenant with no tenant ID — a mismatch makes the
adapter authenticate against the wrong authority and every message fails with
a 401 from Bot Framework.
TEAMS_APP_ID={{app_id}}
TEAMS_APP_PASSWORD={{app_password}}
TEAMS_APP_TENANT_ID={{app_tenant_id}}
TEAMS_APP_TYPE=SingleTenant
Set the app icons
The CLI-created app ships with placeholder icons; this swaps in the NanoClaw mascot (the same PNGs the manual-path package bakes into its zip), so the install dialog below already shows it. Cosmetic — a failure is logged and skipped, never blocking setup. Re-runnable any time while signed in to the Teams CLI:
"$(npm prefix -g 2>/dev/null)/bin/teams" app update {{teams_app_id}} --color-icon setup/assets/teams/color.png --outline-icon setup/assets/teams/outline.png --json || echo "Icon update failed — cosmetic only, continuing."
Who owns this bot
The account signed into the Teams CLI is the account that just created the bot — that human is the wiring target this flow suggests. Its identity comes from the CLI session, so this runs before the sign-out step below:
"$(npm prefix -g 2>/dev/null)/bin/teams" status --json 2>/dev/null
Confirm the wiring target
Nothing is wired without a confirmed target, and someone is always wired — there is no skip. The account signed into the Teams CLI is often NOT the person setting up NanoClaw, so a no leads to a clarifying choice: wire the logged-in Teams user after all, or a different Teams user by Microsoft Entra object ID. Identities are shown by sign-in name, never a raw ID:
Detected the account that created the bot: {{owner_upn}}. Wiring the assistant to it means its first message arrives in that account's Teams DMs.
Wire the assistant to this account?
You're currently logged in to Teams as {{owner_upn}}.
- To wire the assistant to this logged-in Teams user, choose "logged-in-account".
- To wire a different Teams user, get their Microsoft Entra object ID — found at entra.microsoft.com > Users > (person) > Overview > Object ID, or Teams admin center > Manage users — and choose "other-account". Once wired, the assistant messages them first.
Which Teams user should the assistant be wired to?
Truncated for display — read the full file on GitHub.
Related Skills
siyuan
46.5kAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间,让人与智能体在此协作
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
pptx
177.9kUse this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an em…
design
130.2kComprehensive design skill: brand identity, design tokens, UI styling, logo generation (55 styles, Gemini, Atlas Cloud, or MuAPI AI), corporate identity program (50 deliverables, CIP mockups), HTML presentations (Chart.js), banner design (22 styles, social/ads/web/print), icon design (15 styles, SVG…
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
