[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69B8ENJGC9NPQBZAYAN4706":3,"skill-same:01M69B8ENJGC9NPQBZAYAN4706":304},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":41,"linkOnly":42,"markdownContent":43,"markdownBody":44,"frontMatter":45,"refName":46,"commitSha":47,"skillDirectory":48,"forksCount":49,"repositoryHtmlUrl":50,"repositoryHomepageUrl":51,"ownerHtmlUrl":52,"ownerBlogUrl":53,"ownerDescription":54,"updatedAt":55,"install":56,"resources":69},"01M69B8ENJGC9NPQBZAYAN4706","agents-sdk-python-otel",null,"Use when adding, configuring, validating, or troubleshooting OpenTelemetry observability for a Microsoft 365 Agents SDK application in Python. Trigger when the user mentions OpenTelemetry, OTel, telemetry, traces, metrics, logs, OTLP, Aspire Dashboard, Application Insights, Azure Monitor, distributed tracing, custom tracers or meters, span sampling, or observing microsoft_agents SDK signals.","microsoft\u002FAgents","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M69B7CR81D1HSNV69XDT8KAR",1109,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-python\u002Fskills\u002Fagents-sdk-python-otel\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[29,30,31,32,33,34,9,35,36,37,38,39,40],"python","agents sdk","sdk","otel","agents sdk python otel","dashboard","telemetry","aspire","distributed","azure","monitor","aspire dashboard","2026-11-10 10:12:30",false,"---\nname: agents-sdk-python-otel\ndescription: >\n  Use when adding, configuring, validating, or troubleshooting OpenTelemetry\n  observability for a Microsoft 365 Agents SDK application in Python. Trigger\n  when the user mentions OpenTelemetry, OTel, telemetry, traces, metrics,\n  logs, OTLP, Aspire Dashboard, Application Insights, Azure Monitor,\n  distributed tracing, custom tracers or meters, span sampling, or observing\n  microsoft_agents SDK signals.\n---\n\n# OpenTelemetry for Agents SDK (Python)\n\n## Goal\n\nConfigure traces, metrics, and logs for a Python Agents SDK application,\nincluding the SDK's built-in telemetry and a local Aspire Dashboard. Preserve\nthe project's dependency manager, web host, logging design, and startup\nlifecycle.\n\n## Non-negotiable rules\n\n- Configure global OpenTelemetry providers before importing most\n  `microsoft_agents` SDK modules. The Python SDK resolves tracers and meters at\n  import time. `microsoft_agents.activity` contains no telemetry and is safe\n  to import before provider setup.\n- Extend existing providers instead of attempting to replace already-set\n  global providers. OpenTelemetry Python does not permit provider replacement\n  after initialization.\n- Instrument aiohttp, requests, or other libraries after providers are\n  configured and before the application starts handling traffic.\n- Use one stable application-specific `service.name`.\n- Let exporters read standard OTEL environment variables. Never hardcode\n  collector credentials, API keys, or connection strings.\n- Never add prompts, responses, message text, tokens, authorization headers,\n  cookies, secrets, attachment contents, user names, user IDs, conversation\n  IDs, activity IDs, or arbitrary HTTP headers to custom telemetry by default.\n- Keep custom metric attributes low-cardinality. Good dimensions include\n  route type, activity type, channel ID, operation, status, and error type.\n- Use batch processors for normal applications. Simple processors are only\n  appropriate for narrow debugging or tests.\n- Do not set always-on sampling as a production default. Honor the deployment\n  sampling policy or configure a deliberate parent-based ratio.\n- Flush tracer, meter, and logger providers during graceful shutdown. Do not\n  silently ignore exporter or shutdown failures.\n- Avoid duplicate `LoggingHandler` instances on the root logger.\n- Aspire Dashboard anonymous mode is local-development only. Bind it to\n  loopback and never deploy that configuration.\n- Telemetry must record and re-raise application exceptions.\n\n## Workflow\n\nComplete these steps in order.\n\n### 1. Inspect the application\n\nFind:\n\n- `pyproject.toml`, `requirements*.txt`, lockfiles, Python version, virtual\n  environment convention, and dependency manager.\n- The actual startup module and import order.\n- Whether the app uses aiohttp, FastAPI, Flask, requests, httpx, or another\n  server\u002Fclient stack.\n- Existing global tracer, meter, or logger providers.\n- Existing OTLP, Azure Monitor, Application Insights, or vendor-specific\n  exporters.\n- Existing logging handlers and shutdown hooks.\n- Existing custom tracers, meters, instruments, and instrumentation calls.\n- OTEL settings in `.env` templates, deployment manifests, containers, and\n  CI\u002FCD configuration.\n\nIf any provider is already configured, merge the missing exporter,\ninstrumentation, processor, or logging behavior into that setup. Do not call\n`trace.set_tracer_provider`, `metrics.set_meter_provider`, or\n`set_logger_provider` a second time.\n\nChoose one provider setup:\n\n- Use zero-code instrumentation when the user requests no OTel setup code and\n  the application's process can be started through `opentelemetry-instrument`.\n- Use programmatic configuration when the application must own providers,\n  processors, custom exporters, shutdown behavior, or unsupported\n  instrumentation.\n- Preserve an existing provider setup instead of introducing either approach\n  alongside it.\n\n### 2. Add only the required packages\n\nUse the project's dependency manager and preserve its lockfile.\n\nFor zero-code instrumentation of a pip-based aiohttp application:\n\n```powershell\npython -m pip install `\n  \"python-dotenv[cli]\" `\n  opentelemetry-distro `\n  opentelemetry-exporter-otlp `\n  opentelemetry-instrumentation-aiohttp-server `\n  opentelemetry-instrumentation-aiohttp-client `\n  opentelemetry-instrumentation-requests `\n  opentelemetry-instrumentation-logging\n```\n\nFor programmatic instrumentation of a pip-based aiohttp application:\n\n```powershell\npython -m pip install `\n  opentelemetry-api `\n  opentelemetry-sdk `\n  opentelemetry-exporter-otlp `\n  opentelemetry-instrumentation-aiohttp-server `\n  opentelemetry-instrumentation-aiohttp-client `\n  opentelemetry-instrumentation-requests\n```\n\nInstall only instrumentations for libraries the application actually uses.\nExamples:\n\n- `opentelemetry-instrumentation-fastapi`\n- `opentelemetry-instrumentation-flask`\n- `opentelemetry-instrumentation-httpx`\n- `opentelemetry-instrumentation-logging`\n\nKeep OpenTelemetry API, SDK, exporter, and instrumentation versions compatible.\nDo not add a second dependency manifest or switch package managers.\n\n### 3. Configure providers\n\n#### Zero-code setup\n\nDo not add an `instrumentation.py` module, OTel imports, provider setup, or\nmanual instrumentation calls to application code. Configure the distro with\nstandard environment variables:\n\n```dotenv\nOTEL_SERVICE_NAME=contoso-support-agent\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317\nOTEL_EXPORTER_OTLP_PROTOCOL=grpc\nOTEL_TRACES_EXPORTER=otlp\nOTEL_METRICS_EXPORTER=otlp\nOTEL_LOGS_EXPORTER=otlp\nOTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true\n```\n\nThe process that launches `opentelemetry-instrument` must already contain\nthese variables. Calling `load_dotenv()` in the application startup module is\ntoo late: the zero-code launcher configures providers before it imports the\napplication. For a local `.env`, load it in the parent process:\n\n```powershell\npython -m dotenv run -- opentelemetry-instrument python -m src.main\n```\n\nThis command requires `python-dotenv[cli]`. In deployments, configure the same\nvariables in the process environment and use:\n\n```powershell\nopentelemetry-instrument python -m src.main\n```\n\nThe launcher is part of the required startup lifecycle. Running\n`python -m src.main` directly does not enable zero-code export. Installed\ninstrumentation packages are discovered by the distro and initialized before\nthe application starts.\n\n#### Programmatic setup\n\nCreate `instrumentation.py` without importing any Agents SDK telemetry module:\n\n```python\nfrom __future__ import annotations\n\nimport logging\nimport os\nimport socket\nfrom dataclasses import dataclass\n\nfrom opentelemetry import metrics, trace\nfrom opentelemetry._logs import set_logger_provider\nfrom opentelemetry.exporter.otlp.proto.grpc._log_exporter import (\n    OTLPLogExporter,\n)\nfrom opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (\n    OTLPMetricExporter,\n)\nfrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (\n    OTLPSpanExporter,\n)\nfrom opentelemetry.sdk._logs import LoggerProvider, LoggingHandler\nfrom opentelemetry.sdk._logs.export import BatchLogRecordProcessor\nfrom opentelemetry.sdk.metrics import MeterProvider\nfrom opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\n\n\n@dataclass(frozen=True)\nclass TelemetryProviders:\n    tracer_provider: TracerProvider\n    meter_provider: MeterProvider\n    logger_provider: LoggerProvider\n\n    def shutdown(self) -> None:\n        failures: list[tuple[str, Exception]] = []\n\n        for name, provider in (\n            (\"logger\", self.logger_provider),\n            (\"meter\", self.meter_provider),\n            (\"tracer\", self.tracer_provider),\n        ):\n            try:\n                provider.shutdown()\n            except Exception as exception:\n                failures.append((name, exception))\n\n        if failures:\n            details = \"; \".join(\n                f\"{name}: {exception!r}\" for name, exception in failures\n            )\n            raise RuntimeError(\n                f\"Telemetry provider shutdown failed: {details}\"\n            ) from failures[0][1]\n\n\ndef configure_otel_providers(\n    service_name: str,\n    service_version: str | None = None,\n) -> TelemetryProviders:\n    resolved_service_name = os.getenv(\"OTEL_SERVICE_NAME\", service_name)\n    resource_attributes: dict[str, str] = {\n        \"service.name\": resolved_service_name,\n        \"service.instance.id\": socket.gethostname(),\n        \"telemetry.sdk.language\": \"python\",\n    }\n\n    if service_version:\n        resource_attributes[\"service.version\"] = service_version\n\n    resource = Resource.create(resource_attributes)\n\n    tracer_provider = TracerProvider(resource=resource)\n    tracer_provider.add_span_processor(\n        BatchSpanProcessor(OTLPSpanExporter())\n    )\n    trace.set_tracer_provider(tracer_provider)\n\n    meter_provider = MeterProvider(\n        resource=resource,\n        metric_readers=[\n            PeriodicExportingMetricReader(OTLPMetricExporter())\n        ],\n    )\n    metrics.set_meter_provider(meter_provider)\n\n    logger_provider = LoggerProvider(resource=resource)\n    logger_provider.add_log_record_processor(\n        BatchLogRecordProcessor(OTLPLogExporter())\n    )\n    set_logger_provider(logger_provider)\n\n    root_logger = logging.getLogger()\n    if not any(\n        isinstance(handler, LoggingHandler)\n        for handler in root_logger.handlers\n    ):\n        root_logger.addHandler(\n            LoggingHandler(\n                level=logging.NOTSET,\n                logger_provider=logger_provider,\n            )\n        )\n\n    return TelemetryProviders(\n        tracer_provider=tracer_provider,\n        meter_provider=meter_provider,\n        logger_provider=logger_provider,\n    )\n```\n\nExporter constructors intentionally omit endpoints and headers so they honor\nthe standard OTEL environment variables.\n\nIf the application already configured a provider, do not use this complete\ntemplate. Modify the existing provider setup instead.\n\n### 4. Enforce provider-before-SDK import order\n\nFor zero-code instrumentation, `opentelemetry-instrument` establishes the\nproviders before loading the startup module; do not duplicate provider setup\nin that module.\n\nFor programmatic instrumentation, the startup module must load environment\nvariables, configure providers, and only then import the agent:\n\n```python\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nfrom .instrumentation import configure_otel_providers\n\nTELEMETRY = configure_otel_providers(\n    service_name=\"contoso-support-agent\",\n    service_version=\"1.0.0\",\n)\n\n# These imports must remain below provider initialization.\nfrom .agent import AGENT_APP, CONNECTION_MANAGER\nfrom .start_server import start_server\n\nstart_server(\n    agent_application=AGENT_APP,\n    auth_configuration=(\n        CONNECTION_MANAGER.get_default_connection_configuration()\n    ),\n    telemetry=TELEMETRY,\n)\n```\n\nDo not move `microsoft_agents.hosting.core`,\n`microsoft_agents.hosting.aiohttp`, authentication, storage, connector, or\nagent-module imports above provider initialization.\n\n### 5. Instrument the libraries the app uses\n\nFor zero-code instrumentation, install only the applicable instrumentation\npackages and let the distro discover them. Do not also call their\n`instrument()` methods in application code.\n\nFor programmatic instrumentation, configure aiohttp server\u002Fclient and\nrequests explicitly:\n\n```python\nfrom opentelemetry.instrumentation.aiohttp_client import (\n    AioHttpClientInstrumentor,\n)\nfrom opentelemetry.instrumentation.aiohttp_server import (\n    AioHttpServerInstrumentor,\n)\nfrom opentelemetry.instrumentation.requests import RequestsInstrumentor\n\n\ndef instrument_libraries() -> None:\n    AioHttpServerInstrumentor().instrument()\n    AioHttpClientInstrumentor().instrument()\n    RequestsInstrumentor().instrument()\n```\n\nCall `instrument_libraries()` after provider setup and before creating the web\napplication or making instrumented requests.\n\nDo not enrich spans with complete URLs, query strings, headers, request\nbodies, response bodies, prompts, or agent messages. If custom hooks are\nrequired, add only reviewed, bounded attributes.\n\n### 6. Integrate graceful shutdown\n\nFor zero-code instrumentation, the distro-created SDK providers register\nprocess-exit shutdown hooks. Do not also shut those providers down from\napplication code. Ensure the application exits normally so the registered\nhooks can flush telemetry.\n\nFor programmatic instrumentation, make the application lifecycle the single\nowner of provider shutdown. For aiohttp, attach cleanup to the application\nrather than relying only on process exit:\n\n```python\nimport asyncio\nfrom aiohttp import web\n\nfrom .instrumentation import TelemetryProviders\n\n\ndef create_app(\n    telemetry: TelemetryProviders,\n) -> web.Application:\n    app = web.Application()\n\n    async def shutdown_telemetry(_: web.Application) -> None:\n        await asyncio.to_thread(telemetry.shutdown)\n\n    app.on_cleanup.append(shutdown_telemetry)\n    return app\n```\n\nFor another host, use its supported lifespan or shutdown callback. For a\nsimple synchronous process:\n\n```python\ntry:\n    run_application()\nfinally:\n    TELEMETRY.shutdown()\n```\n\nRegister one owner for shutdown. Do not call provider shutdown both from the\nweb host and an `atexit` handler.\n\n### 7. Configure OTLP\n\nFor the local Aspire Dashboard using OTLP\u002FgRPC, add non-secret defaults to the\nuncommitted `.env` and document them in `env.TEMPLATE` or `.env.example`:\n\n```dotenv\nOTEL_SERVICE_NAME=contoso-support-agent\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317\nOTEL_EXPORTER_OTLP_PROTOCOL=grpc\n```\n\nFor zero-code instrumentation, also select each signal exporter and enable\nPython logging auto-instrumentation:\n\n```dotenv\nOTEL_TRACES_EXPORTER=otlp\nOTEL_METRICS_EXPORTER=otlp\nOTEL_LOGS_EXPORTER=otlp\nOTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true\n```\n\nUse the standard names above. Do not use nested application-configuration\nforms such as `OTEL__EXPORTER__OTLP__ENDPOINT`; OpenTelemetry exporters read\n`OTEL_EXPORTER_OTLP_ENDPOINT`.\n\nStandard variables to support:\n\n| Variable | Purpose |\n|---|---|\n| `OTEL_SERVICE_NAME` | Stable application service name |\n| `OTEL_RESOURCE_ATTRIBUTES` | Stable resource metadata |\n| `OTEL_EXPORTER_OTLP_ENDPOINT` | Base OTLP collector endpoint |\n| `OTEL_EXPORTER_OTLP_PROTOCOL` | Usually `grpc` or `http\u002Fprotobuf` |\n| `OTEL_EXPORTER_OTLP_HEADERS` | Collector authentication headers; keep secret |\n| `OTEL_TRACES_EXPORTER` | Trace exporter selection; use `otlp` for an OTLP collector |\n| `OTEL_METRICS_EXPORTER` | Metric exporter selection; use `otlp` for an OTLP collector |\n| `OTEL_LOGS_EXPORTER` | Log exporter selection; use `otlp` for an OTLP collector |\n| `OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED` | Installs the zero-code OTel logging handler |\n| `OTEL_TRACES_SAMPLER` | Trace sampling strategy |\n| `OTEL_TRACES_SAMPLER_ARG` | Sampling strategy argument |\n| `OTEL_METRIC_EXPORT_INTERVAL` | Metric export interval in milliseconds |\n\nUse deployment secrets for OTLP headers and Azure Monitor connection strings.\nNever commit populated `.env` files.\n\n### 8. Add custom business telemetry only when useful\n\nThe Agents SDK already emits adapter, application, turn, connector, storage,\nauthentication, authorization, and user-token-client signals. Add custom\ntelemetry only for application-specific operations.\n\nImport this helper only after providers are configured:\n\n```python\nfrom opentelemetry import metrics, trace\n\nSOURCE_NAME = \"Contoso.SupportAgent\"\nSOURCE_VERSION = \"1.0.0\"\n\nTRACER = trace.get_tracer(SOURCE_NAME, SOURCE_VERSION)\nMETER = metrics.get_meter(SOURCE_NAME, SOURCE_VERSION)\n\nROUTE_EXECUTIONS = METER.create_counter(\n    \"agent.route.executions\",\n    unit=\"{execution}\",\n    description=\"Number of application route executions.\",\n)\nROUTE_DURATION = METER.create_histogram(\n    \"agent.route.duration\",\n    unit=\"ms\",\n    description=\"Application route execution duration.\",\n)\n```\n\nInstrument a route with bounded attributes:\n\n```python\nimport time\n\nfrom opentelemetry.trace import Status, StatusCode\n\nstarted = time.perf_counter()\nstatus = \"ok\"\n\nwith TRACER.start_as_current_span(\"agent.route.execute\") as span:\n    try:\n        await handle_message(context)\n    except Exception:\n        status = \"error\"\n        raise\n    finally:\n        attributes = {\n            \"route.type\": \"message\",\n            \"status\": status,\n        }\n        ROUTE_EXECUTIONS.add(1, attributes)\n        ROUTE_DURATION.record(\n            (time.perf_counter() - started) * 1000,\n            attributes,\n        )\n```\n\nThe span context manager ends the span automatically. Do not call `span.end()`\ninside the `with` block.\n\nUse normal Python `logging` records for operational logs. The OTel\n`LoggingHandler` correlates records emitted in an active context. Keep\nsensitive and high-cardinality content out of log messages and `extra`\nattributes.\n\n### 9. Filter selected SDK spans only when requested\n\nFor centrally managed removal of selected completed spans, prefer the\nOpenTelemetry Collector filter processor:\n\n```yaml\nprocessors:\n  filter\u002Fdrop_agents_storage:\n    error_mode: ignore\n    trace_conditions:\n      - span.name == \"agents.storage.read\"\n      - span.name == \"agents.storage.write\"\n      - span.name == \"agents.storage.delete\"\n  batch:\n\nservice:\n  pipelines:\n    traces:\n      receivers: [otlp]\n      processors: [filter\u002Fdrop_agents_storage, batch]\n      exporters: [otlp]\n```\n\nCollector filtering prevents matching spans from reaching the backend and\ncentralizes policy, but it does not reduce application or\napplication-to-Collector overhead. Dropping individual spans can orphan\ndescendants and produce incomplete traces.\n\nUse an SDK sampler when the goal is to avoid recording and transmitting the\ntelemetry. Prefer sampling whole traces. If a user explicitly requires\nspan-name filtering inside the application, wrap the deployment sampler:\n\n```python\nfrom opentelemetry.sdk.trace.sampling import (\n    Decision,\n    ParentBased,\n    Sampler,\n    SamplingResult,\n    TraceIdRatioBased,\n)\n\nSUPPRESSED_SPANS = frozenset(\n    {\n        \"agents.storage.read\",\n        \"agents.storage.write\",\n        \"agents.storage.delete\",\n    }\n)\n\n\nclass SpanFilterSampler(Sampler):\n    def __init__(self, delegate: Sampler) -> None:\n        self._delegate = delegate\n\n    def should_sample(\n        self,\n        parent_context,\n        trace_id,\n        name,\n        kind=None,\n        attributes=None,\n        links=None,\n        trace_state=None,\n    ):\n        if name in SUPPRESSED_SPANS:\n            return SamplingResult(Decision.DROP)\n\n        return self._delegate.should_sample(\n            parent_context=parent_context,\n            trace_id=trace_id,\n            name=name,\n            kind=kind,\n            attributes=attributes,\n            links=links,\n            trace_state=trace_state,\n        )\n\n    def get_description(self) -> str:\n        return f\"SpanFilterSampler({self._delegate.get_description()})\"\n\n\nsampler = SpanFilterSampler(\n    ParentBased(root=TraceIdRatioBased(0.1))\n)\ntracer_provider = TracerProvider(\n    resource=resource,\n    sampler=sampler,\n)\n```\n\nThe filter must wrap `ParentBased`; placing the filter only in the\n`ParentBased.root` delegate will not filter child SDK spans with a sampled\nparent.\n\nUse literal span names in the provider bootstrap. Importing Agents SDK\nconstant modules there can violate the provider-before-SDK import rule.\n\nDo not implement the default filtering policy in an application\n`SpanProcessor`. Processors receive spans that were already recorded, and a\nnormal processor chain does not let one processor prevent later processors\nfrom receiving the same span.\n\n### 10. Set up the Aspire Dashboard\n\nCopy `assets\u002Fstart-aspire-dashboard.ps1` from this skill into a local scripts\ndirectory and run:\n\n```powershell\n.\\start-aspire-dashboard.ps1\n```\n\nOpen `http:\u002F\u002Flocalhost:18888`. The script:\n\n- Binds the UI and OTLP ports to `127.0.0.1`.\n- Exposes OTLP\u002FgRPC on `4317` and OTLP\u002FHTTP on `4318`.\n- Enables unsecured access only for local development.\n- Pulls `mcr.microsoft.com\u002Fdotnet\u002Faspire-dashboard:latest`.\n\nDo not start a second container if `aspire-dashboard` already exists. Reuse or\nstop the existing container:\n\n```powershell\ndocker stop aspire-dashboard\n```\n\n### 11. Validate end to end\n\n1. Run the project's existing tests, type checker, or import\u002Fcompile check.\n2. Start Aspire Dashboard and confirm the container remains running.\n3. Start the exact instrumented entry point:\n   - For zero-code setup, use the documented `dotenv run` and\n     `opentelemetry-instrument` command. Confirm the application source has no\n     OTel provider setup or manual instrumentation.\n   - For programmatic setup, start the application module that configures\n     providers before the SDK imports.\n4. Send at least one message through Agents Playground or a configured\n   channel.\n   Metrics are exported periodically and can take one or more export intervals,\n   plus dashboard processing time, to appear. Wait and refresh the dashboard\n   before diagnosing missing metrics.\n5. In Aspire Dashboard, confirm:\n   - Telemetry is grouped under the application's `service.name`.\n   - Traces include `agents.adapter.process` or `agents.app.run`.\n   - Metrics include `agents.activities.received`, `agents.turn.count`, or\n     another exercised SDK operation.\n   - Python logging records appear with trace correlation.\n6. Stop the application normally and confirm provider shutdown completes.\n7. Exercise a failure path when practical and confirm the span is marked\n   `ERROR` while the exception still reaches normal application handling.\n\nSee [references\u002Fsdk-signals.md](references\u002Fsdk-signals.md) for the canonical\nAgents SDK spans, metrics, constants, and Aspire smoke test.\n\n## Exporter choices\n\n### Aspire Dashboard or another OTLP collector\n\nUse `opentelemetry-exporter-otlp` and select imports matching the collector's\ngRPC or HTTP\u002Fprotobuf protocol.\n\n### Azure Monitor \u002F Application Insights\n\nWhen requested, use the current stable `azure-monitor-opentelemetry`\ndistribution and call `configure_azure_monitor()` before importing the Agents\nSDK. Load `APPLICATIONINSIGHTS_CONNECTION_STRING` from a secret source.\n\nThe Azure Monitor distribution owns provider configuration. Do not also run\nthe complete manual provider template unless the current Azure Monitor\ndocumentation explicitly supports that combination. Preserve OTLP only when\ndual export is intentional.\n\n### Existing logging configuration\n\nPreserve the application's formatters, filters, levels, and handlers. Add one\nOTel `LoggingHandler` or use the exporter integration already provided by the\nselected distribution. Do not call `logging.basicConfig()` merely to enable\nOTel.\n\n## Troubleshooting\n\n| Symptom | Check |\n|---|---|\n| No SDK spans or metrics | Providers were configured after importing `microsoft_agents.hosting.core` |\n| Zero-code launch ignores `.env` | Load `.env` in the parent with `python -m dotenv run -- opentelemetry-instrument ...`; application `load_dotenv()` runs too late |\n| Direct Python launch has no telemetry | Zero-code setup requires `opentelemetry-instrument`; use the instrumented entry point |\n| Provider override warning | More than one module calls a global `set_*_provider` function |\n| aiohttp spans missing | Instrumentors ran after application creation or requests began |\n| Custom telemetry missing | Tracer\u002Fmeter helper was imported before provider setup |\n| Logs missing | One `LoggingHandler` and a batch log processor are configured |\n| Duplicate logs | Multiple OTel handlers were attached to the same logger hierarchy |\n| Dashboard empty | Endpoint is `http:\u002F\u002Flocalhost:4317`; exporter and protocol are gRPC |\n| Traces appear but metrics do not | Metrics can take one or more `OTEL_METRIC_EXPORT_INTERVAL` periods plus dashboard processing time to appear; wait and refresh before troubleshooting |\n| OTLP protocol error | Exporter import, endpoint port, and protocol do not match |\n| Last telemetry is absent | All three providers are shut down during graceful cleanup |\n| High telemetry cost | Remove high-cardinality attributes and reduce trace sampling |\n| Filtered child spans still appear | The filter was placed inside, rather than around, `ParentBased` |\n\n## Contributing\n\nIf SDK signals differ from [references\u002Fsdk-signals.md](references\u002Fsdk-signals.md),\nthe sample no longer runs, or the Aspire setup changes, draft an issue\ncontaining Python\u002Fpackage versions, startup import order, host framework,\nexpected signal, actual result, and any workaround:\nhttps:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fagents\u002Fissues\u002Fnew\n","# OpenTelemetry for Agents SDK (Python)\n\n## Goal\n\nConfigure traces, metrics, and logs for a Python Agents SDK application,\nincluding the SDK's built-in telemetry and a local Aspire Dashboard. Preserve\nthe project's dependency manager, web host, logging design, and startup\nlifecycle.\n\n## Non-negotiable rules\n\n- Configure global OpenTelemetry providers before importing most\n  `microsoft_agents` SDK modules. The Python SDK resolves tracers and meters at\n  import time. `microsoft_agents.activity` contains no telemetry and is safe\n  to import before provider setup.\n- Extend existing providers instead of attempting to replace already-set\n  global providers. OpenTelemetry Python does not permit provider replacement\n  after initialization.\n- Instrument aiohttp, requests, or other libraries after providers are\n  configured and before the application starts handling traffic.\n- Use one stable application-specific `service.name`.\n- Let exporters read standard OTEL environment variables. Never hardcode\n  collector credentials, API keys, or connection strings.\n- Never add prompts, responses, message text, tokens, authorization headers,\n  cookies, secrets, attachment contents, user names, user IDs, conversation\n  IDs, activity IDs, or arbitrary HTTP headers to custom telemetry by default.\n- Keep custom metric attributes low-cardinality. Good dimensions include\n  route type, activity type, channel ID, operation, status, and error type.\n- Use batch processors for normal applications. Simple processors are only\n  appropriate for narrow debugging or tests.\n- Do not set always-on sampling as a production default. Honor the deployment\n  sampling policy or configure a deliberate parent-based ratio.\n- Flush tracer, meter, and logger providers during graceful shutdown. Do not\n  silently ignore exporter or shutdown failures.\n- Avoid duplicate `LoggingHandler` instances on the root logger.\n- Aspire Dashboard anonymous mode is local-development only. Bind it to\n  loopback and never deploy that configuration.\n- Telemetry must record and re-raise application exceptions.\n\n## Workflow\n\nComplete these steps in order.\n\n### 1. Inspect the application\n\nFind:\n\n- `pyproject.toml`, `requirements*.txt`, lockfiles, Python version, virtual\n  environment convention, and dependency manager.\n- The actual startup module and import order.\n- Whether the app uses aiohttp, FastAPI, Flask, requests, httpx, or another\n  server\u002Fclient stack.\n- Existing global tracer, meter, or logger providers.\n- Existing OTLP, Azure Monitor, Application Insights, or vendor-specific\n  exporters.\n- Existing logging handlers and shutdown hooks.\n- Existing custom tracers, meters, instruments, and instrumentation calls.\n- OTEL settings in `.env` templates, deployment manifests, containers, and\n  CI\u002FCD configuration.\n\nIf any provider is already configured, merge the missing exporter,\ninstrumentation, processor, or logging behavior into that setup. Do not call\n`trace.set_tracer_provider`, `metrics.set_meter_provider`, or\n`set_logger_provider` a second time.\n\nChoose one provider setup:\n\n- Use zero-code instrumentation when the user requests no OTel setup code and\n  the application's process can be started through `opentelemetry-instrument`.\n- Use programmatic configuration when the application must own providers,\n  processors, custom exporters, shutdown behavior, or unsupported\n  instrumentation.\n- Preserve an existing provider setup instead of introducing either approach\n  alongside it.\n\n### 2. Add only the required packages\n\nUse the project's dependency manager and preserve its lockfile.\n\nFor zero-code instrumentation of a pip-based aiohttp application:\n\n```powershell\npython -m pip install `\n  \"python-dotenv[cli]\" `\n  opentelemetry-distro `\n  opentelemetry-exporter-otlp `\n  opentelemetry-instrumentation-aiohttp-server `\n  opentelemetry-instrumentation-aiohttp-client `\n  opentelemetry-instrumentation-requests `\n  opentelemetry-instrumentation-logging\n```\n\nFor programmatic instrumentation of a pip-based aiohttp application:\n\n```powershell\npython -m pip install `\n  opentelemetry-api `\n  opentelemetry-sdk `\n  opentelemetry-exporter-otlp `\n  opentelemetry-instrumentation-aiohttp-server `\n  opentelemetry-instrumentation-aiohttp-client `\n  opentelemetry-instrumentation-requests\n```\n\nInstall only instrumentations for libraries the application actually uses.\nExamples:\n\n- `opentelemetry-instrumentation-fastapi`\n- `opentelemetry-instrumentation-flask`\n- `opentelemetry-instrumentation-httpx`\n- `opentelemetry-instrumentation-logging`\n\nKeep OpenTelemetry API, SDK, exporter, and instrumentation versions compatible.\nDo not add a second dependency manifest or switch package managers.\n\n### 3. Configure providers\n\n#### Zero-code setup\n\nDo not add an `instrumentation.py` module, OTel imports, provider setup, or\nmanual instrumentation calls to application code. Configure the distro with\nstandard environment variables:\n\n```dotenv\nOTEL_SERVICE_NAME=contoso-support-agent\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317\nOTEL_EXPORTER_OTLP_PROTOCOL=grpc\nOTEL_TRACES_EXPORTER=otlp\nOTEL_METRICS_EXPORTER=otlp\nOTEL_LOGS_EXPORTER=otlp\nOTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true\n```\n\nThe process that launches `opentelemetry-instrument` must already contain\nthese variables. Calling `load_dotenv()` in the application startup module is\ntoo late: the zero-code launcher configures providers before it imports the\napplication. For a local `.env`, load it in the parent process:\n\n```powershell\npython -m dotenv run -- opentelemetry-instrument python -m src.main\n```\n\nThis command requires `python-dotenv[cli]`. In deployments, configure the same\nvariables in the process environment and use:\n\n```powershell\nopentelemetry-instrument python -m src.main\n```\n\nThe launcher is part of the required startup lifecycle. Running\n`python -m src.main` directly does not enable zero-code export. Installed\ninstrumentation packages are discovered by the distro and initialized before\nthe application starts.\n\n#### Programmatic setup\n\nCreate `instrumentation.py` without importing any Agents SDK telemetry module:\n\n```python\nfrom __future__ import annotations\n\nimport logging\nimport os\nimport socket\nfrom dataclasses import dataclass\n\nfrom opentelemetry import metrics, trace\nfrom opentelemetry._logs import set_logger_provider\nfrom opentelemetry.exporter.otlp.proto.grpc._log_exporter import (\n    OTLPLogExporter,\n)\nfrom opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (\n    OTLPMetricExporter,\n)\nfrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (\n    OTLPSpanExporter,\n)\nfrom opentelemetry.sdk._logs import LoggerProvider, LoggingHandler\nfrom opentelemetry.sdk._logs.export import BatchLogRecordProcessor\nfrom opentelemetry.sdk.metrics import MeterProvider\nfrom opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader\nfrom opentelemetry.sdk.resources import Resource\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\n\n\n@dataclass(frozen=True)\nclass TelemetryProviders:\n    tracer_provider: TracerProvider\n    meter_provider: MeterProvider\n    logger_provider: LoggerProvider\n\n    def shutdown(self) -> None:\n        failures: list[tuple[str, Exception]] = []\n\n        for name, provider in (\n            (\"logger\", self.logger_provider),\n            (\"meter\", self.meter_provider),\n            (\"tracer\", self.tracer_provider),\n        ):\n            try:\n                provider.shutdown()\n            except Exception as exception:\n                failures.append((name, exception))\n\n        if failures:\n            details = \"; \".join(\n                f\"{name}: {exception!r}\" for name, exception in failures\n            )\n            raise RuntimeError(\n                f\"Telemetry provider shutdown failed: {details}\"\n            ) from failures[0][1]\n\n\ndef configure_otel_providers(\n    service_name: str,\n    service_version: str | None = None,\n) -> TelemetryProviders:\n    resolved_service_name = os.getenv(\"OTEL_SERVICE_NAME\", service_name)\n    resource_attributes: dict[str, str] = {\n        \"service.name\": resolved_service_name,\n        \"service.instance.id\": socket.gethostname(),\n        \"telemetry.sdk.language\": \"python\",\n    }\n\n    if service_version:\n        resource_attributes[\"service.version\"] = service_version\n\n    resource = Resource.create(resource_attributes)\n\n    tracer_provider = TracerProvider(resource=resource)\n    tracer_provider.add_span_processor(\n        BatchSpanProcessor(OTLPSpanExporter())\n    )\n    trace.set_tracer_provider(tracer_provider)\n\n    meter_provider = MeterProvider(\n        resource=resource,\n        metric_readers=[\n            PeriodicExportingMetricReader(OTLPMetricExporter())\n        ],\n    )\n    metrics.set_meter_provider(meter_provider)\n\n    logger_provider = LoggerProvider(resource=resource)\n    logger_provider.add_log_record_processor(\n        BatchLogRecordProcessor(OTLPLogExporter())\n    )\n    set_logger_provider(logger_provider)\n\n    root_logger = logging.getLogger()\n    if not any(\n        isinstance(handler, LoggingHandler)\n        for handler in root_logger.handlers\n    ):\n        root_logger.addHandler(\n            LoggingHandler(\n                level=logging.NOTSET,\n                logger_provider=logger_provider,\n            )\n        )\n\n    return TelemetryProviders(\n        tracer_provider=tracer_provider,\n        meter_provider=meter_provider,\n        logger_provider=logger_provider,\n    )\n```\n\nExporter constructors intentionally omit endpoints and headers so they honor\nthe standard OTEL environment variables.\n\nIf the application already configured a provider, do not use this complete\ntemplate. Modify the existing provider setup instead.\n\n### 4. Enforce provider-before-SDK import order\n\nFor zero-code instrumentation, `opentelemetry-instrument` establishes the\nproviders before loading the startup module; do not duplicate provider setup\nin that module.\n\nFor programmatic instrumentation, the startup module must load environment\nvariables, configure providers, and only then import the agent:\n\n```python\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nfrom .instrumentation import configure_otel_providers\n\nTELEMETRY = configure_otel_providers(\n    service_name=\"contoso-support-agent\",\n    service_version=\"1.0.0\",\n)\n\n# These imports must remain below provider initialization.\nfrom .agent import AGENT_APP, CONNECTION_MANAGER\nfrom .start_server import start_server\n\nstart_server(\n    agent_application=AGENT_APP,\n    auth_configuration=(\n        CONNECTION_MANAGER.get_default_connection_configuration()\n    ),\n    telemetry=TELEMETRY,\n)\n```\n\nDo not move `microsoft_agents.hosting.core`,\n`microsoft_agents.hosting.aiohttp`, authentication, storage, connector, or\nagent-module imports above provider initialization.\n\n### 5. Instrument the libraries the app uses\n\nFor zero-code instrumentation, install only the applicable instrumentation\npackages and let the distro discover them. Do not also call their\n`instrument()` methods in application code.\n\nFor programmatic instrumentation, configure aiohttp server\u002Fclient and\nrequests explicitly:\n\n```python\nfrom opentelemetry.instrumentation.aiohttp_client import (\n    AioHttpClientInstrumentor,\n)\nfrom opentelemetry.instrumentation.aiohttp_server import (\n    AioHttpServerInstrumentor,\n)\nfrom opentelemetry.instrumentation.requests import RequestsInstrumentor\n\n\ndef instrument_libraries() -> None:\n    AioHttpServerInstrumentor().instrument()\n    AioHttpClientInstrumentor().instrument()\n    RequestsInstrumentor().instrument()\n```\n\nCall `instrument_libraries()` after provider setup and before creating the web\napplication or making instrumented requests.\n\nDo not enrich spans with complete URLs, query strings, headers, request\nbodies, response bodies, prompts, or agent messages. If custom hooks are\nrequired, add only reviewed, bounded attributes.\n\n### 6. Integrate graceful shutdown\n\nFor zero-code instrumentation, the distro-created SDK providers register\nprocess-exit shutdown hooks. Do not also shut those providers down from\napplication code. Ensure the application exits normally so the registered\nhooks can flush telemetry.\n\nFor programmatic instrumentation, make the application lifecycle the single\nowner of provider shutdown. For aiohttp, attach cleanup to the application\nrather than relying only on process exit:\n\n```python\nimport asyncio\nfrom aiohttp import web\n\nfrom .instrumentation import TelemetryProviders\n\n\ndef create_app(\n    telemetry: TelemetryProviders,\n) -> web.Application:\n    app = web.Application()\n\n    async def shutdown_telemetry(_: web.Application) -> None:\n        await asyncio.to_thread(telemetry.shutdown)\n\n    app.on_cleanup.append(shutdown_telemetry)\n    return app\n```\n\nFor another host, use its supported lifespan or shutdown callback. For a\nsimple synchronous process:\n\n```python\ntry:\n    run_application()\nfinally:\n    TELEMETRY.shutdown()\n```\n\nRegister one owner for shutdown. Do not call provider shutdown both from the\nweb host and an `atexit` handler.\n\n### 7. Configure OTLP\n\nFor the local Aspire Dashboard using OTLP\u002FgRPC, add non-secret defaults to the\nuncommitted `.env` and document them in `env.TEMPLATE` or `.env.example`:\n\n```dotenv\nOTEL_SERVICE_NAME=contoso-support-agent\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317\nOTEL_EXPORTER_OTLP_PROTOCOL=grpc\n```\n\nFor zero-code instrumentation, also select each signal exporter and enable\nPython logging auto-instrumentation:\n\n```dotenv\nOTEL_TRACES_EXPORTER=otlp\nOTEL_METRICS_EXPORTER=otlp\nOTEL_LOGS_EXPORTER=otlp\nOTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true\n```\n\nUse the standard names above. Do not use nested application-configuration\nforms such as `OTEL__EXPORTER__OTLP__ENDPOINT`; OpenTelemetry exporters read\n`OTEL_EXPORTER_OTLP_ENDPOINT`.\n\nStandard variables to support:\n\n| Variable | Purpose |\n|---|---|\n| `OTEL_SERVICE_NAME` | Stable application service name |\n| `OTEL_RESOURCE_ATTRIBUTES` | Stable resource metadata |\n| `OTEL_EXPORTER_OTLP_ENDPOINT` | Base OTLP collector endpoint |\n| `OTEL_EXPORTER_OTLP_PROTOCOL` | Usually `grpc` or `http\u002Fprotobuf` |\n| `OTEL_EXPORTER_OTLP_HEADERS` | Collector authentication headers; keep secret |\n| `OTEL_TRACES_EXPORTER` | Trace exporter selection; use `otlp` for an OTLP collector |\n| `OTEL_METRICS_EXPORTER` | Metric exporter selection; use `otlp` for an OTLP collector |\n| `OTEL_LOGS_EXPORTER` | Log exporter selection; use `otlp` for an OTLP collector |\n| `OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED` | Installs the zero-code OTel logging handler |\n| `OTEL_TRACES_SAMPLER` | Trace sampling strategy |\n| `OTEL_TRACES_SAMPLER_ARG` | Sampling strategy argument |\n| `OTEL_METRIC_EXPORT_INTERVAL` | Metric export interval in milliseconds |\n\nUse deployment secrets for OTLP headers and Azure Monitor connection strings.\nNever commit populated `.env` files.\n\n### 8. Add custom business telemetry only when useful\n\nThe Agents SDK already emits adapter, application, turn, connector, storage,\nauthentication, authorization, and user-token-client signals. Add custom\ntelemetry only for application-specific operations.\n\nImport this helper only after providers are configured:\n\n```python\nfrom opentelemetry import metrics, trace\n\nSOURCE_NAME = \"Contoso.SupportAgent\"\nSOURCE_VERSION = \"1.0.0\"\n\nTRACER = trace.get_tracer(SOURCE_NAME, SOURCE_VERSION)\nMETER = metrics.get_meter(SOURCE_NAME, SOURCE_VERSION)\n\nROUTE_EXECUTIONS = METER.create_counter(\n    \"agent.route.executions\",\n    unit=\"{execution}\",\n    description=\"Number of application route executions.\",\n)\nROUTE_DURATION = METER.create_histogram(\n    \"agent.route.duration\",\n    unit=\"ms\",\n    description=\"Application route execution duration.\",\n)\n```\n\nInstrument a route with bounded attributes:\n\n```python\nimport time\n\nfrom opentelemetry.trace import Status, StatusCode\n\nstarted = time.perf_counter()\nstatus = \"ok\"\n\nwith TRACER.start_as_current_span(\"agent.route.execute\") as span:\n    try:\n        await handle_message(context)\n    except Exception:\n        status = \"error\"\n        raise\n    finally:\n        attributes = {\n            \"route.type\": \"message\",\n            \"status\": status,\n        }\n        ROUTE_EXECUTIONS.add(1, attributes)\n        ROUTE_DURATION.record(\n            (time.perf_counter() - started) * 1000,\n            attributes,\n        )\n```\n\nThe span context manager ends the span automatically. Do not call `span.end()`\ninside the `with` block.\n\nUse normal Python `logging` records for operational logs. The OTel\n`LoggingHandler` correlates records emitted in an active context. Keep\nsensitive and high-cardinality content out of log messages and `extra`\nattributes.\n\n### 9. Filter selected SDK spans only when requested\n\nFor centrally managed removal of selected completed spans, prefer the\nOpenTelemetry Collector filter processor:\n\n```yaml\nprocessors:\n  filter\u002Fdrop_agents_storage:\n    error_mode: ignore\n    trace_conditions:\n      - span.name == \"agents.storage.read\"\n      - span.name == \"agents.storage.write\"\n      - span.name == \"agents.storage.delete\"\n  batch:\n\nservice:\n  pipelines:\n    traces:\n      receivers: [otlp]\n      processors: [filter\u002Fdrop_agents_storage, batch]\n      exporters: [otlp]\n```\n\nCollector filtering prevents matching spans from reaching the backend and\ncentralizes policy, but it does not reduce application or\napplication-to-Collector overhead. Dropping individual spans can orphan\ndescendants and produce incomplete traces.\n\nUse an SDK sampler when the goal is to avoid recording and transmitting the\ntelemetry. Prefer sampling whole traces. If a user explicitly requires\nspan-name filtering inside the application, wrap the deployment sampler:\n\n```python\nfrom opentelemetry.sdk.trace.sampling import (\n    Decision,\n    ParentBased,\n    Sampler,\n    SamplingResult,\n    TraceIdRatioBased,\n)\n\nSUPPRESSED_SPANS = frozenset(\n    {\n        \"agents.storage.read\",\n        \"agents.storage.write\",\n        \"agents.storage.delete\",\n    }\n)\n\n\nclass SpanFilterSampler(Sampler):\n    def __init__(self, delegate: Sampler) -> None:\n        self._delegate = delegate\n\n    def should_sample(\n        self,\n        parent_context,\n        trace_id,\n        name,\n        kind=None,\n        attributes=None,\n        links=None,\n        trace_state=None,\n    ):\n        if name in SUPPRESSED_SPANS:\n            return SamplingResult(Decision.DROP)\n\n        return self._delegate.should_sample(\n            parent_context=parent_context,\n            trace_id=trace_id,\n            name=name,\n            kind=kind,\n            attributes=attributes,\n            links=links,\n            trace_state=trace_state,\n        )\n\n    def get_description(self) -> str:\n        return f\"SpanFilterSampler({self._delegate.get_description()})\"\n\n\nsampler = SpanFilterSampler(\n    ParentBased(root=TraceIdRatioBased(0.1))\n)\ntracer_provider = TracerProvider(\n    resource=resource,\n    sampler=sampler,\n)\n```\n\nThe filter must wrap `ParentBased`; placing the filter only in the\n`ParentBased.root` delegate will not filter child SDK spans with a sampled\nparent.\n\nUse literal span names in the provider bootstrap. Importing Agents SDK\nconstant modules there can violate the provider-before-SDK import rule.\n\nDo not implement the default filtering policy in an application\n`SpanProcessor`. Processors receive spans that were already recorded, and a\nnormal processor chain does not let one processor prevent later processors\nfrom receiving the same span.\n\n### 10. Set up the Aspire Dashboard\n\nCopy `assets\u002Fstart-aspire-dashboard.ps1` from this skill into a local scripts\ndirectory and run:\n\n```powershell\n.\\start-aspire-dashboard.ps1\n```\n\nOpen `http:\u002F\u002Flocalhost:18888`. The script:\n\n- Binds the UI and OTLP ports to `127.0.0.1`.\n- Exposes OTLP\u002FgRPC on `4317` and OTLP\u002FHTTP on `4318`.\n- Enables unsecured access only for local development.\n- Pulls `mcr.microsoft.com\u002Fdotnet\u002Faspire-dashboard:latest`.\n\nDo not start a second container if `aspire-dashboard` already exists. Reuse or\nstop the existing container:\n\n```powershell\ndocker stop aspire-dashboard\n```\n\n### 11. Validate end to end\n\n1. Run the project's existing tests, type checker, or import\u002Fcompile check.\n2. Start Aspire Dashboard and confirm the container remains running.\n3. Start the exact instrumented entry point:\n   - For zero-code setup, use the documented `dotenv run` and\n     `opentelemetry-instrument` command. Confirm the application source has no\n     OTel provider setup or manual instrumentation.\n   - For programmatic setup, start the application module that configures\n     providers before the SDK imports.\n4. Send at least one message through Agents Playground or a configured\n   channel.\n   Metrics are exported periodically and can take one or more export intervals,\n   plus dashboard processing time, to appear. Wait and refresh the dashboard\n   before diagnosing missing metrics.\n5. In Aspire Dashboard, confirm:\n   - Telemetry is grouped under the application's `service.name`.\n   - Traces include `agents.adapter.process` or `agents.app.run`.\n   - Metrics include `agents.activities.received`, `agents.turn.count`, or\n     another exercised SDK operation.\n   - Python logging records appear with trace correlation.\n6. Stop the application normally and confirm provider shutdown completes.\n7. Exercise a failure path when practical and confirm the span is marked\n   `ERROR` while the exception still reaches normal application handling.\n\nSee [references\u002Fsdk-signals.md](references\u002Fsdk-signals.md) for the canonical\nAgents SDK spans, metrics, constants, and Aspire smoke test.\n\n## Exporter choices\n\n### Aspire Dashboard or another OTLP collector\n\nUse `opentelemetry-exporter-otlp` and select imports matching the collector's\ngRPC or HTTP\u002Fprotobuf protocol.\n\n### Azure Monitor \u002F Application Insights\n\nWhen requested, use the current stable `azure-monitor-opentelemetry`\ndistribution and call `configure_azure_monitor()` before importing the Agents\nSDK. Load `APPLICATIONINSIGHTS_CONNECTION_STRING` from a secret source.\n\nThe Azure Monitor distribution owns provider configuration. Do not also run\nthe complete manual provider template unless the current Azure Monitor\ndocumentation explicitly supports that combination. Preserve OTLP only when\ndual export is intentional.\n\n### Existing logging configuration\n\nPreserve the application's formatters, filters, levels, and handlers. Add one\nOTel `LoggingHandler` or use the exporter integration already provided by the\nselected distribution. Do not call `logging.basicConfig()` merely to enable\nOTel.\n\n## Troubleshooting\n\n| Symptom | Check |\n|---|---|\n| No SDK spans or metrics | Providers were configured after importing `microsoft_agents.hosting.core` |\n| Zero-code launch ignores `.env` | Load `.env` in the parent with `python -m dotenv run -- opentelemetry-instrument ...`; application `load_dotenv()` runs too late |\n| Direct Python launch has no telemetry | Zero-code setup requires `opentelemetry-instrument`; use the instrumented entry point |\n| Provider override warning | More than one module calls a global `set_*_provider` function |\n| aiohttp spans missing | Instrumentors ran after application creation or requests began |\n| Custom telemetry missing | Tracer\u002Fmeter helper was imported before provider setup |\n| Logs missing | One `LoggingHandler` and a batch log processor are configured |\n| Duplicate logs | Multiple OTel handlers were attached to the same logger hierarchy |\n| Dashboard empty | Endpoint is `http:\u002F\u002Flocalhost:4317`; exporter and protocol are gRPC |\n| Traces appear but metrics do not | Metrics can take one or more `OTEL_METRIC_EXPORT_INTERVAL` periods plus dashboard processing time to appear; wait and refresh before troubleshooting |\n| OTLP protocol error | Exporter import, endpoint port, and protocol do not match |\n| Last telemetry is absent | All three providers are shut down during graceful cleanup |\n| High telemetry cost | Remove high-cardinality attributes and reduce trace sampling |\n| Filtered child spans still appear | The filter was placed inside, rather than around, `ParentBased` |\n\n## Contributing\n\nIf SDK signals differ from [references\u002Fsdk-signals.md](references\u002Fsdk-signals.md),\nthe sample no longer runs, or the Aspire setup changes, draft an issue\ncontaining Python\u002Fpackage versions, startup import order, host framework,\nexpected signal, actual result, and any workaround:\nhttps:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fagents\u002Fissues\u002Fnew\n",{"name":5,"description":7},"main","8171bc7e0ca3b8defd578a6bb317367c2901983f","agent-plugins\u002Fagents-for-python\u002Fskills\u002Fagents-sdk-python-otel",346,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents","https:\u002F\u002Faka.ms\u002Fagentsdkdocs","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-14 08:54:12",{"source":8,"skillName":5,"commands":57,"prompt":67,"zipAvailable":68},[58,61,64],{"tool":59,"command":60},"npx","npx skills add microsoft\u002FAgents --skill agents-sdk-python-otel",{"tool":62,"command":63},"bunx","bunx skills add microsoft\u002FAgents --skill agents-sdk-python-otel",{"tool":65,"command":66},"pnpm","pnpm dlx skills add microsoft\u002FAgents --skill agents-sdk-python-otel","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-python\u002Fskills\u002Fagents-sdk-python-otel\u002FSKILL.md",true,[70,76,82,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,296,300],{"path":71,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":74,"sourceHtmlUrl":75},"assets\u002Fstart-aspire-dashboard.ps1","SCRIPT","脚本",963,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-python\u002Fskills\u002Fagents-sdk-python-otel\u002Fassets\u002Fstart-aspire-dashboard.ps1",{"path":77,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":80,"sourceHtmlUrl":81},"html2pptx.md","REFERENCE","参考文档",19859,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fhtml2pptx.md",{"path":83,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":86,"sourceHtmlUrl":87},"LICENSE.txt","LICENSE","许可证",1467,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002FLICENSE.txt",{"path":89,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":90,"sourceHtmlUrl":91},"ooxml.md",10388,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml.md",{"path":93,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":94,"sourceHtmlUrl":95},"ooxml\u002Fschemas\u002Fecma\u002Ffouth-edition\u002Fopc-contentTypes.xsd",1963,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fecma\u002Ffouth-edition\u002Fopc-contentTypes.xsd",{"path":97,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":98,"sourceHtmlUrl":99},"ooxml\u002Fschemas\u002Fecma\u002Ffouth-edition\u002Fopc-coreProperties.xsd",2515,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fecma\u002Ffouth-edition\u002Fopc-coreProperties.xsd",{"path":101,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":102,"sourceHtmlUrl":103},"ooxml\u002Fschemas\u002Fecma\u002Ffouth-edition\u002Fopc-digSig.xsd",2856,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fecma\u002Ffouth-edition\u002Fopc-digSig.xsd",{"path":105,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":106,"sourceHtmlUrl":107},"ooxml\u002Fschemas\u002Fecma\u002Ffouth-edition\u002Fopc-relationships.xsd",1344,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fecma\u002Ffouth-edition\u002Fopc-relationships.xsd",{"path":109,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":110,"sourceHtmlUrl":111},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-chart.xsd",74984,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-chart.xsd",{"path":113,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":114,"sourceHtmlUrl":115},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-chartDrawing.xsd",6956,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-chartDrawing.xsd",{"path":117,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":118,"sourceHtmlUrl":119},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-diagram.xsd",51302,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-diagram.xsd",{"path":121,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":122,"sourceHtmlUrl":123},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-lockedCanvas.xsd",624,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-lockedCanvas.xsd",{"path":125,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":126,"sourceHtmlUrl":127},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-main.xsd",152039,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-main.xsd",{"path":129,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":130,"sourceHtmlUrl":131},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-picture.xsd",1231,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-picture.xsd",{"path":133,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":134,"sourceHtmlUrl":135},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-spreadsheetDrawing.xsd",8862,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-spreadsheetDrawing.xsd",{"path":137,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":138,"sourceHtmlUrl":139},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-wordprocessingDrawing.xsd",14795,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fdml-wordprocessingDrawing.xsd",{"path":141,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":142,"sourceHtmlUrl":143},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fpml.xsd",83612,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fpml.xsd",{"path":145,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":146,"sourceHtmlUrl":147},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-additionalCharacteristics.xsd",1269,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-additionalCharacteristics.xsd",{"path":149,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":150,"sourceHtmlUrl":151},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-bibliography.xsd",7328,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-bibliography.xsd",{"path":153,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":154,"sourceHtmlUrl":155},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-commonSimpleTypes.xsd",6382,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-commonSimpleTypes.xsd",{"path":157,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":158,"sourceHtmlUrl":159},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-customXmlDataProperties.xsd",1248,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-customXmlDataProperties.xsd",{"path":161,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":162,"sourceHtmlUrl":163},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-customXmlSchemaProperties.xsd",880,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-customXmlSchemaProperties.xsd",{"path":165,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":166,"sourceHtmlUrl":167},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-documentPropertiesCustom.xsd",2608,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-documentPropertiesCustom.xsd",{"path":169,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":170,"sourceHtmlUrl":171},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-documentPropertiesExtended.xsd",3507,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-documentPropertiesExtended.xsd",{"path":173,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":174,"sourceHtmlUrl":175},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-documentPropertiesVariantTypes.xsd",7507,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-documentPropertiesVariantTypes.xsd",{"path":177,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":178,"sourceHtmlUrl":179},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-math.xsd",23313,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-math.xsd",{"path":181,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":182,"sourceHtmlUrl":183},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-relationshipReference.xsd",1367,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fshared-relationshipReference.xsd",{"path":185,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":186,"sourceHtmlUrl":187},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fsml.xsd",242277,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fsml.xsd",{"path":189,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":190,"sourceHtmlUrl":191},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-main.xsd",26148,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-main.xsd",{"path":193,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":194,"sourceHtmlUrl":195},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-officeDrawing.xsd",25279,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-officeDrawing.xsd",{"path":197,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":198,"sourceHtmlUrl":199},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-presentationDrawing.xsd",535,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-presentationDrawing.xsd",{"path":201,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":202,"sourceHtmlUrl":203},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-spreadsheetDrawing.xsd",5712,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-spreadsheetDrawing.xsd",{"path":205,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":206,"sourceHtmlUrl":207},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-wordprocessingDrawing.xsd",4010,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fvml-wordprocessingDrawing.xsd",{"path":209,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":210,"sourceHtmlUrl":211},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fwml.xsd",171367,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fwml.xsd",{"path":213,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":214,"sourceHtmlUrl":215},"ooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fxml.xsd",4646,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002FISO-IEC29500-4_2016\u002Fxml.xsd",{"path":217,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":218,"sourceHtmlUrl":219},"ooxml\u002Fschemas\u002Fmce\u002Fmc.xsd",3127,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fmce\u002Fmc.xsd",{"path":221,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":222,"sourceHtmlUrl":223},"ooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-2010.xsd",26549,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-2010.xsd",{"path":225,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":226,"sourceHtmlUrl":227},"ooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-2012.xsd",3745,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-2012.xsd",{"path":229,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":230,"sourceHtmlUrl":231},"ooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-2018.xsd",901,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-2018.xsd",{"path":233,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":234,"sourceHtmlUrl":235},"ooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-cex-2018.xsd",1778,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-cex-2018.xsd",{"path":237,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":238,"sourceHtmlUrl":239},"ooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-cid-2016.xsd",1002,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-cid-2016.xsd",{"path":241,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":242,"sourceHtmlUrl":243},"ooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-sdtdatahash-2020.xsd",600,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-sdtdatahash-2020.xsd",{"path":245,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":246,"sourceHtmlUrl":247},"ooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-symex-2015.xsd",745,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fschemas\u002Fmicrosoft\u002Fwml-symex-2015.xsd",{"path":249,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":250,"sourceHtmlUrl":251},"ooxml\u002Fscripts\u002Fpack.py",5596,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fscripts\u002Fpack.py",{"path":253,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":254,"sourceHtmlUrl":255},"ooxml\u002Fscripts\u002Funpack.py",1037,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fscripts\u002Funpack.py",{"path":257,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":258,"sourceHtmlUrl":259},"ooxml\u002Fscripts\u002Fvalidate.py",1959,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fscripts\u002Fvalidate.py",{"path":261,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":262,"sourceHtmlUrl":263},"ooxml\u002Fscripts\u002Fvalidation\u002F__init__.py",336,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fscripts\u002Fvalidation\u002F__init__.py",{"path":265,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":266,"sourceHtmlUrl":267},"ooxml\u002Fscripts\u002Fvalidation\u002Fbase.py",39892,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fscripts\u002Fvalidation\u002Fbase.py",{"path":269,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":270,"sourceHtmlUrl":271},"ooxml\u002Fscripts\u002Fvalidation\u002Fdocx.py",9996,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fscripts\u002Fvalidation\u002Fdocx.py",{"path":273,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":274,"sourceHtmlUrl":275},"ooxml\u002Fscripts\u002Fvalidation\u002Fpptx.py",12327,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fscripts\u002Fvalidation\u002Fpptx.py",{"path":277,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":278,"sourceHtmlUrl":279},"ooxml\u002Fscripts\u002Fvalidation\u002Fredlining.py",11179,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fooxml\u002Fscripts\u002Fvalidation\u002Fredlining.py",{"path":281,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":282,"sourceHtmlUrl":283},"references\u002Fsdk-signals.md",5634,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-python\u002Fskills\u002Fagents-sdk-python-otel\u002Freferences\u002Fsdk-signals.md",{"path":285,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":286,"sourceHtmlUrl":287},"scripts\u002Fhtml2pptx.js",37795,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fscripts\u002Fhtml2pptx.js",{"path":289,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":290,"sourceHtmlUrl":291},"scripts\u002Finventory.py",38126,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fscripts\u002Finventory.py",{"path":293,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":294,"sourceHtmlUrl":295},"scripts\u002Frearrange.py",8514,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fscripts\u002Frearrange.py",{"path":297,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":298,"sourceHtmlUrl":299},"scripts\u002Freplace.py",13594,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fscripts\u002Freplace.py",{"path":301,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":302,"sourceHtmlUrl":303},"scripts\u002Fthumbnail.py",15484,"https:\u002F\u002Fgithub.com\u002Fshengdabai\u002FTony-Claude-Code-Skills\u002Fblob\u002Fmain\u002Fskills\u002F_collections\u002Ftravisvn-awesome-claude-skills\u002Fanthropics-skills\u002Fskills\u002Fpptx\u002Fscripts\u002Fthumbnail.py",[305,323,343,355,367,376],{"skillNo":306,"name":307,"nameZh":6,"description":308,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":309,"categories":310,"keywords":311,"publishedAt":41},"01M6PJCYCYJQDX318SQN3EBF0E","sync-teams-samples-to-agents-sdk","CI instructions for a bounded Teams SDK to Agents SDK sample synchronization using the selected language profile.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fautomation\u002Fteams-sample-sync\u002Fskills\u002Fsync-teams-samples-to-agents-sdk\u002FSKILL.md",[],[30,31,312,313,314,315,316,317,318,319,320,321,322],"sync","teams","sync teams samples to agents sdk","ci","synchronization","instructions","profile","language","sample","for","bounded",{"skillNo":324,"name":325,"nameZh":6,"description":326,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":327,"categories":328,"keywords":329,"publishedAt":41},"01M6PJCFNGCX555YERYQ459JFE","teams-sdk-to-agents-sdk-typescript-migration","Migrate a JavaScript or TypeScript application using the Microsoft Teams SDK App runtime to Microsoft 365 Agents SDK while preserving its Teams behaviors. Use for Teams SDK migrations, including automated sample synchronization; use the separate Bot Framework migration skill for botbuilder applications.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-js\u002Fskills\u002Fteams-sdk-to-agents-sdk-typescript-migration\u002FSKILL.md",[],[31,330,30,313,331,332,333,334,321,335,320,336,337,316,338,339,340,341,9,342],"typescript","agents sdk typescript","migration","teams sdk to agents sdk typescript migration","app","runtime","migrations","use","migrate","applications","microsoft teams","javascript","bot",{"skillNo":344,"name":345,"nameZh":6,"description":346,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":347,"categories":348,"keywords":352,"publishedAt":41},"01M69B8QV24JVPXH25EH77X0SZ","teams-app-manifest","Create or audit a Microsoft Teams app manifest for an existing Microsoft 365 Agents SDK application by mapping declared intent and source-code evidence to released manifest capabilities. Use when manifest.json is missing, incomplete, or must be checked against implemented Teams features. Does not configure Microsoft Entra, Azure Bot, Developer Portal, or deployment unless separately requested.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-sdk-common\u002Fskills\u002Fteams-app-manifest\u002FSKILL.md",[349],{"categoryNo":350,"categoryName":351,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师",[313,353,342,30,31,9,38,354],"teams app manifest","deployment",{"skillNo":356,"name":357,"nameZh":6,"description":358,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":359,"categories":360,"keywords":361,"publishedAt":41},"01M69B8MN62NBY93YTJAQG2Y81","agents-sdk-provision","Use when provisioning Azure resources for a Microsoft Agents SDK application — including creating an Azure Bot Service resource, setting up Entra app registrations, configuring identity credentials (UserManagedIdentity, FederatedCredentials, or ClientSecret), adding a Teams channel, running Bicep deployments for SSO, or setting up OAuth user sign-in connections via az CLI. Trigger even if the user doesn't say \"provision\" — use on requests like \"set up my bot on Azure\", \"deploy my bot\", \"configure Azure for my bot\", or \"get Teams SSO working.\" Applies to all languages (dotnet, Node.js, Python).","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-sdk-common\u002Fskills\u002Fagents-sdk-provision\u002FSKILL.md",[],[30,31,362,38,342,363,29,9,364,365,366,313],"agents sdk provision","cli","dotnet","identity","deploy",{"skillNo":368,"name":369,"nameZh":6,"description":370,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":371,"categories":372,"keywords":373,"publishedAt":41},"01M69B8HFZ45NQGWQQD483TWPB","agents-sdk-to-prod","Assess, create, harden, deploy, or review production readiness of Python Microsoft 365 Agents SDK agents and their direct hosting\u002Foperations files. Use only for Agents SDK scenarios, not unrelated application hardening.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-python\u002Fskills\u002Fagents-sdk-to-prod\u002FSKILL.md",[],[31,374,30,29,9,366,375],"agents sdk to prod","review",{"skillNo":377,"name":378,"nameZh":6,"description":379,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":380,"categories":381,"keywords":382,"publishedAt":41},"01M69B8C2FGRWXRJ35ZETW8ZV2","teams-sdk-to-agents-sdk-dotnet-migration","Use when migrating a customer's Teams SDK (teams.net) bot to the Microsoft 365 Agents SDK in .NET. Triggered by projects that depend on Microsoft.Teams.Plugins.AspNetCore, Microsoft.Teams.Apps, or Microsoft.Teams.Api and call builder.AddTeams() \u002F app.UseTeams().","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FAgents\u002Fblob\u002Fmain\u002Fagent-plugins\u002Fagents-for-net\u002Fskills\u002Fteams-sdk-to-agents-sdk-dotnet-migration\u002FSKILL.md",[],[30,383,313,332,364,384,31,385,9,386,342,387,334,388,389,337,390,391],"teams sdk to agents sdk dotnet migration","agents sdk dotnet","plugins","customer","apps","call","builder","projects","api"]