This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is the Microsoft 365 Agents SDK for Python, a framework for building enterprise-grade conversational agents for M365, Teams, Copilot Studio, and other platforms. The SDK replaces the legacy Bot Framework SDK (botbuilder packages) with a modern, modular architecture.
Important: Python imports use underscores (microsoft_agents), not dots (microsoft.agents).
Quick setup (Linux/macOS):
. ./scripts/dev_setup.shQuick setup (Windows):
. ./scripts/dev_setup.ps1Manual setup (from repository root):
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install all libraries in editable mode
pip install -e ./libraries/microsoft-agents-activity/ --config-settings editable_mode=compat
pip install -e ./libraries/microsoft-agents-hosting-core/ --config-settings editable_mode=compat
pip install -e ./libraries/microsoft-agents-authentication-msal/ --config-settings editable_mode=compat
pip install -e ./libraries/microsoft-agents-copilotstudio-client/ --config-settings editable_mode=compat
pip install -e ./libraries/microsoft-agents-hosting-aiohttp/ --config-settings editable_mode=compat
pip install -e ./libraries/microsoft-agents-hosting-teams/ --config-settings editable_mode=compat
pip install -e ./libraries/microsoft-agents-storage-blob/ --config-settings editable_mode=compat
pip install -e ./libraries/microsoft-agents-storage-cosmos/ --config-settings editable_mode=compat
pip install -e ./libraries/microsoft-agents-hosting-fastapi/ --config-settings editable_mode=compat
# Install development dependencies
pip install -r dev_dependencies.txt
# Setup pre-commit hooks
pre-commit installPython version: Requires Python 3.10+, supports 3.10-3.14. Recommended: Python 3.11+
# Run all tests
pytest
# Run tests in a specific directory
pytest tests/microsoft-agents-activity/
# Run a single test file
pytest tests/microsoft-agents-activity/test_activity.py
# Run a single test
pytest tests/microsoft-agents-activity/test_activity.py::test_activity_creation
# Run with verbose output
pytest -v
# Run with test markers
pytest -m unit
pytest -m integration
pytest -m slow# Format code with black (line length: 88)
black libraries/
# Check formatting without making changes
black libraries/ --check
# Lint with flake8 (max line length: 127, max complexity: 10)
flake8 .
# Run pre-commit checks manually
pre-commit run --all-files# Set package version (from versioning directory)
cd ./versioning
setuptools-git-versioning
# Build all packages (run from repository root)
mkdir -p dist
for dir in libraries/*; do
if [ -f "$dir/pyproject.toml" ]; then
(cd "$dir" && python -m build --outdir ../../dist)
fi
done
# Build a specific package
cd libraries/microsoft-agents-activity
python -m buildThe SDK follows a layered, modular architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────────────────┐
│ Layer 5: Web Framework Adapters │
│ hosting-aiohttp, hosting-fastapi │
├─────────────────────────────────────────────────────────────────┤
│ Layer 4: Platform Extensions & Storage │
│ hosting-teams, storage-blob, storage-cosmos │
├─────────────────────────────────────────────────────────────────┤
│ Layer 3: Authentication │
│ authentication-msal │
├─────────────────────────────────────────────────────────────────┤
│ Layer 2: Core Hosting Engine │
│ hosting-core (Agent, TurnContext, State, Routing) │
├─────────────────────────────────────────────────────────────────┤
│ Layer 1: Protocol/Schema │
│ activity (Activity protocol, Pydantic models) │
└─────────────────────────────────────────────────────────────────┘
Each library in libraries/ is independently published to PyPI:
| Package | Purpose | Key Abstractions |
|---|---|---|
microsoft-agents-activity |
Activity protocol types using Pydantic | Activity, ConversationReference, protocols |
microsoft-agents-hosting-core |
Core agent runtime and lifecycle | Agent, TurnContext, ActivityHandler, AgentApplication |
microsoft-agents-authentication-msal |
MSAL-based OAuth authentication | MsalAuth, MsalConnectionManager |
microsoft-agents-hosting-aiohttp |
aiohttp web framework adapter | CloudAdapter, start_agent_process() |
microsoft-agents-hosting-fastapi |
FastAPI web framework adapter | CloudAdapter, start_agent_process() |
microsoft-agents-hosting-teams |
Teams-specific extensions | TeamsActivityHandler, TeamsInfo |
microsoft-agents-storage-blob |
Azure Blob Storage persistence | BlobStorage |
microsoft-agents-storage-cosmos |
CosmosDB persistence | CosmosDbStorage |
1. ActivityHandler (inheritance-based):
class MyAgent(ActivityHandler):
async def on_message_activity(self, context: TurnContext):
await context.send_activity(f"You said: {context.activity.text}")2. AgentApplication (modern, decorator-based):
app = AgentApplication[TurnState]()
@app.message()
async def on_message(context: TurnContext[TurnState]):
await context.send_activity(f"You said: {context.activity.text}")HTTP POST /api/messages
↓
Web Framework (aiohttp/FastAPI)
↓
CloudAdapter.process()
↓
Parse Activity JSON → Create ClaimsIdentity
↓
ChannelServiceAdapter.process_activity()
↓
Create TurnContext(adapter, activity, identity)
↓
Middleware Pipeline (auth, logging, etc.)
↓
Agent.on_turn(context)
↓
Route to handler (ActivityHandler methods OR AgentApplication selectors)
↓
Handler executes, may call context.send_activity()
↓
Middleware unwind → Return response
Three state scopes managed via TurnContext.state:
- ConversationState: Persisted per conversation (
conversation[conversation_id]) - UserState: Persisted per user across conversations (
user[user_id]) - TempState: Ephemeral, exists only for the current turn
State is automatically loaded at turn start and saved at turn end using the configured Storage implementation.
The AgentApplication routing system prioritizes activities in this order:
- Invoke activities (Adaptive Cards, task modules)
- Agentic requests (agent-to-agent communication)
- Regular messages (user messages)
Routes are matched using selectors:
- Activity type matching (
activity_types=["message"]) - Regex patterns (
message(r"^hello")) - Custom selector functions
MSAL-based authentication supports three flows:
- User auth: OAuth for user-to-agent
- Agentic user auth: OAuth for agent-to-agent with user context
- Connector auth: Service-to-service authentication
OAuth state machine:
User requests auth → Save _SignInState → Send OAuthCard
→ User completes OAuth → Token callback → Retrieve token
→ Resume conversation with auth
The SDK dynamically selects the appropriate client based on channel context:
- Teams:
TeamsConnectorClientwith Teams-specific APIs - Copilot Studio (MCS):
McsConnectorClientwith Direct-to-Engine - Generic:
BotFrameworkConnectorClientfor standard channels
Factory pattern in RestChannelServiceClientFactory handles this selection.
All major abstractions use Python Protocols (structural typing) for loose coupling:
Agent,TurnContextProtocol,ChannelAdapterProtocol,Storage
- Framework adapters translate framework-specific types to SDK protocols
HttpRequestProtocolabstracts HTTP request detailsChannelServiceAdapteradapts between SDK and channel services
Cross-cutting concerns (auth, logging, state management) implemented as middleware:
MiddlewareSet → Middleware 1 → ... → Agent Handler → UnwindChannelServiceClientFactory: Creates appropriate clientsMessageFactory,CardFactory: Builders for creating messages
- Formatting:
blackwith 88-character line length (not 127 for flake8) - Linting:
flake8with max line length 127, max complexity 10 - Type hints: Heavy use of generics and protocols
- Async-first: All I/O operations are async
- Pydantic models: Activity protocol uses Pydantic for validation
- Error resources: Standardized error codes with help URLs in
errors/subdirectories
-
Install Microsoft Dev Tunnels:
winget install Microsoft.devtunnel
-
Create and run tunnel:
devtunnel user login devtunnel create my-tunnel -a devtunnel port create -p 3978 my-tunnel devtunnel host -a my-tunnel
Record the tunnel URL for configuration.
-
Install M365 Agents Playground:
winget install --id=Microsoft.M365AgentsPlayground -e
Samples are in test_samples/:
app_style/: Examples usingAgentApplicationteams_agent/: Teams-specific agentfastapi/: FastAPI integration exampleagent_to_agent/: Agent-to-agent communication
Run samples from VS Code or directly:
cd test_samples/app_style
python empty_agent.pylibraries/
microsoft-agents-activity/
microsoft-agents-hosting-core/
microsoft-agents-authentication-msal/
microsoft-agents-hosting-{aiohttp,fastapi,teams}/
microsoft-agents-storage-{blob,cosmos}/
microsoft-agents-copilotstudio-client/
tests/
{package-name}/ # Tests organized by package
test_samples/
app_style/ # AgentApplication examples
teams_agent/ # Teams examples
fastapi/ # FastAPI examples
agent_to_agent/ # Agent-to-agent examples
scripts/
dev_setup.sh # Linux/macOS dev setup
dev_setup.ps1 # Windows dev setup
versioning/
pyproject.toml # Centralized version management
- Import structure: Use
microsoft_agents(underscores), notmicrosoft.agents(dots) - Editable installs: Always use
--config-settings editable_mode=compatfor editable installs - Async everywhere: All I/O operations are async, don't forget
await - State persistence: State is auto-saved only if
Storageis configured - Activity responses: Not all activities require a response (200), some return 202 Accepted
- Turn lifetime:
TurnContextis scoped to a single turn, don't cache it - Middleware order: Middleware runs in registration order, reverse on unwind
The SDK includes source code for debugging. Key areas for breakpoints:
- Request entry:
CloudAdapter.process()in hosting adapters - Activity parsing:
ChannelServiceAdapter.process_activity() - Turn context creation:
TurnContext.__init__() - Routing:
AgentApplication._on_turn()orActivityHandler.on_turn() - State management:
TurnState.load()andsave() - Activity sending:
TurnContext.send_activity() - Connector calls:
ConnectorClientmethods in hosting-core
Versioning is centralized in versioning/pyproject.toml using setuptools-git-versioning. All packages share the same version number for consistency.