Skip to content

Plugins

SecondBrain plugins are declarative capability bundles. A plugin manifest tells operators which connector, kernel tool, MCP server, skill, or resource a bundle adds, which environment variables it needs, and what side effects each capability can have.

Plugins do not bypass the runtime. Tool execution still flows through the existing connector, MCP, skill, kernel policy, approval, tracing, and event-log layers.

Commands

sb plugins list
sb plugins show teams
sb plugins tools teams
sb plugins status teams
sb plugins validate teams
sb plugins disable teams
sb plugins enable teams

Use --json on each command for automation.

enable and disable write local plugin state under the configured SecondBrain state directory. The kernel tool bridge respects that state during runtime registration, while direct diagnostic commands such as sb teams status remain available for setup and repair.

The serve daemon exposes the same manifest and connector state at GET /plugins/status; the web UI renders it on the Settings page.

Microsoft Teams

The first built-in plugin is teams. It contributes Microsoft Graph-backed kernel tools for:

  • reading the signed-in profile
  • listing joined teams
  • listing channels for one team
  • listing recent Teams chats
  • reading messages from one chat
  • fetching one chat message by ID
  • reading messages from one channel
  • fetching one channel message by ID
  • reading replies under one channel message
  • resolving users, joined teams, channels, and chats by visible names
  • sending text or HTML chat/channel messages, including mentions and attachment payloads
  • listing Planner plans, buckets, and tasks
  • fetching, creating, updating, and deleting Planner tasks
  • fetching and updating Planner task details, descriptions, checklists, and references
  • receiving Bot Framework message activities through the conversational adapter
  • storing Bot Framework conversation references for later proactive messaging

Read operations are classified as network_read. Sending a chat/channel message or creating/updating/deleting a Planner task is classified as external_write and maps to the existing kernel destructive safety class so the ToolExecutor requires approval before an agent can post externally or change work in Planner.

Azure CLI can be used for a basic local token check:

az login
sb teams login
sb teams status
sb teams auth-doctor

Teams chat and message APIs usually require delegated Microsoft Graph scopes that Azure CLI's first-party app cannot request directly. For durable chat, channel, and Planner access, use device-code login with a Microsoft Entra public-client application ID:

export TEAMS_GRAPH_CLIENT_ID=<app-client-id>
sb teams device-login
sb teams auth-doctor
sb teams joined-teams --json
sb teams channels <team_id> --json
sb teams channel-messages <team_id> <channel_id> --json
sb teams channel-message <team_id> <channel_id> <message_id> --json
sb teams channel-replies <team_id> <channel_id> <message_id> --json
sb teams chats --json
sb teams chat-message <chat_id> <message_id> --json
sb teams resolve-users "Ada" --json
sb teams resolve-team "Launch" --json
sb teams resolve-channel <team_id> "General" --json
sb teams resolve-chat "Launch planning" --json
sb teams planner-plans <team_id> --json
sb teams planner-buckets <plan_id> --json
sb teams planner-tasks <plan_id> --all-pages --json
sb teams planner-task <task_id> --json
sb teams planner-task-details <task_id> --json

sb teams login does not copy or store a token. It verifies that the signed-in Azure CLI account can mint a Microsoft Graph token. If sb teams chats returns 403, do not keep switching Azure subscriptions; use sb teams device-login with an Entra public-client app that has the required delegated Graph scopes.

The device-code path stores the access token and refresh token in the SecondBrain keychain. auth_provider=auto can refresh cached device-code tokens before falling back to Azure CLI. Configure connectors.teams.oauth_* fields to pin the tenant, client ID source, or scopes.

Conversational Teams Gateway Adapter

Graph is still the right path for background reads and writes. Interactive Teams conversations should use the existing SecondBrain gateway channel runtime. The Teams adapter normalizes Bot Framework Activity payloads into MessageEnvelope objects, then hands them to GatewayRuntime.handle_message() so identity routing, sessions, approval gates, lanes, and outbound delivery remain shared with HTTP and Telegram channels.

Configure the gateway channel in ~/.secondbrain/gateway.yaml:

channels:
  teams:
    enabled: true
    host: 127.0.0.1
    port: 3978
    path: /api/messages
    auth_mode: token
    auth_token: local-dev-token

Point Azure Bot Service or a local tunnel at:

https://<public-tunnel>/api/messages

For local tunnel tests, send the gateway token as Authorization: Bearer local-dev-token or X-Teams-Channel-Token: local-dev-token. In production, put Bot Connector JWT validation at the edge or use a trusted proxy that forwards verified requests to the local gateway adapter.

sb teams bot-manifest --app-id <bot-app-id> --json

The adapter stores the Bot Framework conversation reference under local state so gateway outbound delivery can do proactive messaging when TEAMS_BOT_APP_ID and TEAMS_BOT_APP_PASSWORD are configured. It also splits text replies and attachments into separate activities, because Teams can split combined payloads internally and that makes message IDs harder to track.

Manual token setup is still available. The auth command stores a Microsoft Graph access token in the same SecondBrain keychain path used by sb keys:

sb teams auth
sb teams status
sb teams chats --json

The token variable defaults to TEAMS_GRAPH_TOKEN and can be changed with connectors.teams.token_env in the SecondBrain config. The auth provider defaults to auto, which tries environment/keychain auth first and falls back to Azure CLI.

Direct CLI sends require --force:

sb teams send-chat <chat_id> "Status update" --force
sb teams send-chat <chat_id> "<b>Status update</b>" --html --force
sb teams send-chat <chat_id> "Ada please review" --mention <user_id>=Ada --force
sb teams send-channel <team_id> <channel_id> "Status update" --force
sb teams send-channel-reply <team_id> <channel_id> <message_id> "Reply" --force
sb teams create-planner-task <plan_id> <bucket_id> "Follow up" --force
sb teams update-planner-task <task_id> --title "Renamed" --force
sb teams update-planner-task-details <task_id> --description "New details" --checklist-item "Call Ada" --force
sb teams delete-planner-task <task_id> --force

Use --dry-run --json on any write command to preview the Microsoft Graph request body without posting, creating, updating, or deleting anything. Planner updates, deletes, and details updates use ETag-safe writes. If --etag is omitted, the connector fetches the task or details object first and uses the returned ETag for the write. List commands that can return Graph nextLink support --all-pages --max-pages N.

Agent-driven sends should use the governed tool path, where approval is handled by the kernel policy layer.

Planner reads require Microsoft Graph Tasks.Read delegated permission. Task creation, update, delete, and details updates require Tasks.ReadWrite. User resolution uses basic Microsoft Entra user read permissions such as User.ReadBasic.All depending on tenant policy.

Live Graph smoke coverage is opt-in and skipped by default:

SECOND_BRAIN_TEAMS_LIVE=1 .venv/bin/python -m pytest -q tests/connectors/test_teams_live_smoke.py