It builds a single Rust binary named teams. The CLI wraps Microsoft Graph APIs for Teams automation and emits structured output that AI agents and scripts can consume.
No. The current CLI is a Microsoft Graph command line tool. It can be used by agents as a subprocess, but it is not a Bot Framework app running inside Teams.
Yes, using delegated auth. A user signs in and the CLI posts as that user, subject to that user's Teams permissions and the tenant's Graph consent policy.
Not for normal live Teams chat/channel messages. Microsoft Graph's ordinary send APIs are delegated-user APIs for normal use; the application permission surfaced for sending is a migration/import path. For unattended service-identity posting, the product should add a Teams app/bot proactive messaging mode.
Not in the default commercial model. The CLI defaults to OSO's multi-tenant public client app. Customers can grant admin consent to that app.
Customers can still use BYO mode when their enterprise policy requires their own app registration.
fba1b5d0-fdd0-4fe2-9729-9ccdc38f9595
Do not treat the client ID as a secret. Client secrets, refresh tokens, and access tokens are secrets.
Not fully. The app is built into the CLI as the default delegated public client, but it must be publisher verified before broad public release so Microsoft consent prompts show a verified publisher badge.
Current delegated permissions:
User.Read
offline_access
Team.ReadBasic.All
Channel.ReadBasic.All
ChannelMessage.Send
Chat.ReadWrite
ChatMessage.Send
ChatMessage.Read
User.ReadBasic.All
Presence.Read.All
The default avoids ChannelMessage.Read.All because Microsoft marks that delegated Graph scope as admin-consent required. Customers that need channel message reads should grant it explicitly with --scopes or through a customer-owned app. Future features may require additional permissions.
team list uses /me/joinedTeams, which returns teams where the signed-in user is a direct member. If the user is not a direct member of any team, it can return an empty list even if they have chats or meetings.
Teams/Graph can list chats that later fail message reads because the user is no longer in the meeting roster or lacks access to that thread. Treat this as a per-chat 403 and skip it.
The CLI automatically refreshes an expired access token using the stored refresh token (login requests offline_access), so this should be rare. You will still see AUTH_TOKEN_EXPIRED when no refresh token is stored or the refresh is rejected — for example the refresh token itself expired or was revoked. In that case, re-authenticate:
teams auth login --device-codeThen retry the command.
In the operating system keyring:
- macOS Keychain
- Windows Credential Manager
- Linux Secret Service-compatible keyring
Tokens are not stored in config.toml.
Linux: ~/.config/teams-cli/config.toml
macOS: ~/Library/Application Support/teams-cli/config.toml
Windows: %APPDATA%\teams-cli\config.toml
Check with:
teams config pathThe code is designed to work on Windows and CI runs on windows-latest. Windows release readiness still requires full CI matrix validation and a live smoke test on Windows Credential Manager.
Use --output json. The CLI also auto-detects non-TTY stdout and defaults to JSON when piped.
teams chat list --output jsonAgents should branch on exit code first, then parse the JSON envelope.
No. Teams should not be used as a log sink. Send concise human-readable messages that people are expected to read.
No, not with delegated auth. Delegated mode is scoped by the signed-in user's access and the app's granted permissions. Tenant-wide read scenarios need carefully reviewed application permissions or resource-specific consent depending on the Graph API.
Use a dedicated test team/channel, a test profile, and non-sensitive messages. Validate:
teams auth doctor --output json
teams user me --output json
teams team list --output json
teams chat list --output json
teams message send --team "$TEAM_ID" --channel "$CHANNEL_ID" --body "teams-cli smoke test" --output json