This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Microsoft Agent 365 SDK for Python - Enterprise-grade extensions for building production-ready AI agents for M365, Teams, Copilot Studio, and Webchat. This is a multi-package monorepo organized as a uv workspace with 13 interdependent packages.
Python Version: 3.11+ (3.11 and 3.12 tested in CI)
For detailed architecture and design documentation, see docs/design.md, which includes:
- Complete package descriptions and usage examples
- Design patterns (Singleton, Context Manager, Builder, Result, Strategy)
- Data flow diagrams for agent invocation tracing and MCP tool discovery
- Configuration options and environment variables
- Per-package design documents in
libraries/<package-name>/docs/design.md
# Create and activate virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install dependencies (locks and syncs all workspace packages)
uv lock && uv sync --locked --all-extras --dev# Build all packages (requires version environment variable)
export AGENT365_PYTHON_SDK_PACKAGE_VERSION="0.1.0" # Windows: $env:AGENT365_PYTHON_SDK_PACKAGE_VERSION = "0.1.0"
uv build --all-packages --wheel
# Built wheels are output to dist/# Run all unit tests (excludes integration tests)
uv run --frozen pytest tests/ -v --tb=short -m "not integration"
# Run specific test file
uv run --frozen pytest tests/runtime/test_environment_utils.py -v
# Run tests matching pattern
uv run --frozen pytest tests/ -k "environment" -v
# Run integration tests (requires secrets/environment variables)
uv run --frozen pytest -m integration -v --tb=short
# Run with coverage report
pytest tests/ --cov=libraries --cov-report=html -vTest markers:
unit: Fast, mocked tests (default)integration: Slow tests requiring real services/API keys
# Check linting (does not auto-fix)
uv run --frozen ruff check .
# Auto-fix linting issues
uv run --frozen ruff check . --fix
# Check formatting
uv run --frozen ruff format --check .
# Auto-format code
uv run --frozen ruff format .Linting rules:
- Line length: 100 characters
- Enabled: pycodestyle (E/W), Pyflakes (F), isort (I), flake8-bugbear (B), comprehensions (C4), pyupgrade (UP), copyright headers (CPY)
- Copyright header required in all Python files (see Code Standards)
The repository follows a monorepo workspace pattern with 13 packages organized into 4 core areas:
libraries/
├── Core Packages (foundation)
│ ├── microsoft-agents-a365-runtime # Core utilities and extensions
│ ├── microsoft-agents-a365-notifications # Notification services and models
│ ├── microsoft-agents-a365-observability-core # OpenTelemetry-based tracing
│ └── microsoft-agents-a365-tooling # Tool definitions and MCP integration
│
└── Framework Extensions (integrate with specific AI frameworks)
├── Observability Extensions
│ ├── *-observability-extensions-openai
│ ├── *-observability-extensions-langchain
│ ├── *-observability-extensions-semantickernel
│ └── *-observability-extensions-agentframework
│
└── Tooling Extensions
├── *-tooling-extensions-openai
├── *-tooling-extensions-semantickernel
├── *-tooling-extensions-agentframework
└── *-tooling-extensions-azureaifoundry
-
Namespace Packages: All packages share the
microsoft_agents_a365namespace- Directory names:
microsoft-agents-a365-*(dashes) - Python imports:
microsoft_agents_a365.*(underscores)
- Directory names:
-
Core + Extensions Pattern:
- Core packages (runtime, observability-core, tooling) provide framework-agnostic base functionality
- Extension packages add framework-specific integrations (OpenAI, LangChain, Semantic Kernel, Agent Framework)
- Extensions depend on core packages but cores are independent
-
Workspace Dependencies:
- Inter-package dependencies managed via
[tool.uv.workspace]in root pyproject.toml - Packages reference each other using
{ workspace = true } - All packages built and versioned together
- Inter-package dependencies managed via
-
Observability:
- Built on OpenTelemetry (traces, spans, metrics)
- Core provides base functionality; extensions add framework-specific instrumentation
- Azure Monitor and Jaeger export options available
-
Tooling:
- Tool definitions for agent capabilities
- MCP (Model Context Protocol) integration
- Framework-specific adapters for tool execution
This monorepo uses uv's constraint-dependencies feature to centralize version constraints:
How it works:
- Root pyproject.toml defines version constraints for all external packages
- Package pyproject.toml files declare dependencies by name only (no version)
- uv applies root constraints during dependency resolution
Adding a new dependency:
- Add the package name to your package's
dependenciesarray - Add the version constraint to root
pyproject.tomlconstraint-dependencies - Run
uv lock && uv sync
Updating a dependency version:
- Edit the constraint in root
pyproject.tomlonly - Run
uv lock && uv sync - All packages automatically use the new version
Internal workspace dependencies:
- Package pyproject.toml files list internal deps by name only (e.g.,
microsoft-agents-a365-runtime) - Root pyproject.toml
[tool.uv.sources]maps them to{ workspace = true }for local development - At build time,
setup.pyinjects exact version matches (e.g.,== 1.2.3) for published packages - This ensures all SDK packages require the exact same version of each other
CI Enforcement: The scripts/verify_constraints.py script runs in CI to prevent
accidental reintroduction of version constraints in package files.
Tests mirror the library structure:
tests/
├── runtime/ # Runtime package tests
├── observability/ # Observability core and extension tests
├── tooling/ # Tooling core and extension tests
└── notifications/ # Notifications package tests
Every Python file MUST include this header at the top:
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.Place it before imports with one blank line after.
- Never use the keyword "Kairo" in code - it's a legacy reference that must be removed/replaced
- If found during code review, flag for removal
- Type hints required on all function parameters and return types
- Async/await patterns for I/O operations
- Use explicit
Nonechecks:if x is not None:notif x: - Local imports should be moved to top of file
- Return defensive copies of mutable data to protect singletons
- Async method naming: Do NOT use
_asyncsuffix on async methods. The_asyncsuffix is only appropriate when providing both sync and async versions of the same method. Since this SDK is async-only, use plain method names (e.g.,send_chat_history_messagesnotsend_chat_history_messages_async)
CRITICAL: Never use typing.Any in this codebase. Using Any defeats the purpose of type checking and can hide bugs. Instead:
-
Use actual types from external SDKs - When integrating with external libraries (OpenAI, LangChain, etc.), import and use their actual types:
from agents.memory import Session from agents.items import TResponseInputItem async def send_chat_history(self, session: Session) -> OperationResult: ...
-
Use
Unionfor known possible types:from typing import Union MessageType = Union[UserMessage, AssistantMessage, SystemMessage, Dict[str, object]]
-
Use
objectfor truly unknown types that you only pass through:def log_item(item: object) -> None: ...
-
Use
Protocolonly as a last resort - If external types cannot be found or imported, define a Protocol. However, confirm with the developer first before proceeding with this approach, as it may indicate a missing dependency or incorrect understanding of the external API.
Why this matters:
Anydisables all type checking for that variable- Bugs that type checkers would catch go unnoticed
- Code readability suffers - developers don't know what types to expect
- Using actual SDK types provides better IDE support and ensures compatibility
- This applies to both production code AND test files
The .github/workflows/ci.yml pipeline:
- Runs on pushes to
mainandrelease/*branches - Tests both Python 3.11 and 3.12
- Executes: lint check → format check → build → unit tests → integration tests (if secrets available)
- Only publishes packages on
release/*branches when SDK changes detected - Uses git-based versioning (tags on release branches = official versions, others = dev versions)
- When installing packages for development, use
-e(editable) installs:uv pip install -e libraries/microsoft-agents-a365-runtime - The
AGENT365_PYTHON_SDK_PACKAGE_VERSIONenvironment variable must be set before building - Integration tests require Azure OpenAI credentials (secrets not available in PRs from forks)
- All packages are published to PyPI with prefix
microsoft-agents-a365-*