| name | instrument-agent |
| description | Add Progress Observability instrumentation to an existing AI agent or LLM app — Python, TypeScript/JavaScript, or .NET, including LangChain, LangGraph, LlamaIndex, CrewAI, OpenAI Agents, Haystack, MCP servers and Microsoft.Extensions.AI — with the smallest possible diff, then hand off with where to confirm the traces. Use when the user asks to "instrument my agent", "add observability", "add tracing/telemetry to this repo", "connect this to Progress Observability", or has an existing uninstrumented project they want on the platform. Not for creating a project from scratch — this only edits code that already exists. |
| license | MIT |
| compatibility | Edits files only — needs no MCP server and no MCP key. The instrumented app needs a Progress Observability Integration key (ac_p_…) at runtime, and the project's own package manager (pip/uv/poetry, npm/yarn/pnpm, or dotnet) to install the SDK. |
| metadata | {"author":"observability-oss","languages":"Python, TypeScript, .NET","source":"observability-oss/observability-skills","verified-against":{"pypi":"progress-observability@1.4.3","npm":"@progress/observability@2.1.2","nuget":"Progress.Observability.Instrumentation@1.2.2"}} |
Instrument an existing agent
Retrofit Progress Observability onto an existing codebase with the smallest
possible diff, then run it once so spans start flowing. For a project that
does not exist yet, this is the wrong skill — it only edits what is already
there.
This skill writes code — the instrumentation edits and nothing else. It never
restructures the app, and it never reads the platform back: confirming the traces
arrived is left to /health-check.
1 · Detect — before touching anything
Scan the repo and report what you found, then the diff you intend to make,
before editing:
-
Language & entry point — pyproject.toml/requirements.txt,
package.json (check "type": "module" — it decides the wiring path),
*.csproj.
-
LLM SDKs and frameworks in use — imports of openai, anthropic,
langchain, llama_index, @langchain/*, Microsoft.Extensions.AI, etc.
Check each against the supported-instruments list in the language reference.
A client pointed at an OpenAI-compatible endpoint (OpenRouter, LiteLLM,
vLLM, Together, most gateways) counts as OpenAI — see the reference.
A .NET agent built from AIProjectClient (Azure AI Foundry) has no
wrappable chat client — different wiring; see the Foundry section in
references/dotnet.md.
-
Existing telemetry — OpenTelemetry setup, Traceloop, or a previous
Progress Observability init. Look for it before writing anything, and check
the reference for ordering rather than assuming init belongs first.
Python (measured). The SDK attaches to a provider the app already
installed, so Progress ends up alongside the app's exporter rather than
replacing it — but only if init runs after the app's own setup. Init
first and the app's set_tracer_provider() becomes a no-op with one warning
line, killing its existing telemetry while Progress spans keep arriving.
Grep for set_tracer_provider / TracerProvider(. Details in
references/python.md.
.NET (measured). No ordering constraint: providers coexist and the
app's own tracing is unaffected. The hazard is different — a chat client
that already has .UseOpenTelemetry() records every call twice once
.AddObservability() is added, doubling token and cost figures. Grep for
UseOpenTelemetry before wiring and report the overlap rather than
removing either layer yourself. One hit is not overlap:
UseOpenTelemetry(sourceName: ObservabilityTracer.SourceName) on an
agent builder is Progress wiring itself — leave it. Progress spans land
in their own trace by design; see references/dotnet.md.
TypeScript: not measured here. Don't carry the Python behavior across;
if you hit an app with existing OTel, say the interaction is unverified
rather than guessing, and check the traces on both sides before declaring
success.
If a framework in use is not in the supported list — DSPy, AutoGen,
Pydantic AI, Semantic Kernel and Google ADK are the common ones — say so
plainly and offer the decorator / manual-span fallback from the reference.
Never imply auto-instrumentation covers a framework it doesn't. LangGraph is
supported in Python (it rides the LangChain instrumentor and produces full
graph topology); it is not supported in the JS SDK. Check the language
reference rather than assuming either way.
2 · Wire — follow the language reference exactly
Open the matching reference and use its snippets verbatim — they are verified
against the published packages, not reconstructed:
references/python.md — progress-observability (PyPI)
references/typescript.md — @progress/observability (npm)
references/dotnet.md — Progress.Observability.Instrumentation (NuGet)
Rules that hold across all three:
-
Init at process start, before any LLM client exists. In ESM Node that
means the hooks import and Observability.instrument() run before the app is
even imported; in Python, before clients are constructed; in .NET, before the
agent is built. Two exceptions, both in the language references: an app
that installs its own OpenTelemetry provider (init goes after that), and
Haystack (init goes after import haystack.tracing). Check the reference
before assuming earlier is safer — in both cases it isn't.
-
Minimal diff. Typically: one dependency, one import, one init call, env
var wiring, and a flush-on-exit. If you find yourself moving app code around,
stop and reconsider — including "just" exporting a module-scope script so you
have something to wrap. That is restructuring, and it is never the answer.
-
App with no LLM calls: instrument every step, not the entry point alone.
Decorators (Python/.NET) and wrapFunctionWithSpan (TS) are the only span
source in that app, so wrap the entry point and each internal step and
every tool-like callable, on the functions the app already has. One span
around the top is the failure mode to avoid: it produces a clean, plausible
trace that misrepresents a multi-step pipeline as a single unit, and nothing
in the output reveals it. Each reference has the kind-by-kind table. When
auto-instrumentation is doing the work instead, add none of them.
-
Python + LangChain or LlamaIndex: the meta package is a REQUIRED edit.
langchain-core / llama-index-core alone leave the instrumentor off: the
app runs, LLM spans arrive, and no structure is ever emitted — silently.
(Measured: 2 spans → 8 for LangChain, 1 → 17 for LlamaIndex, from that one
line.) Add langchain / llama-index to the dependency file alongside the
-core package, never in place of it — the app imports langchain_core /
llama_index.core by name, so those stay declared. Say in your report that
you added it and why; gate table in references/python.md.
-
Python: declare httpx alongside the SDK. traceloop-sdk imports it
without declaring it, so importing progress.observability dies with
ModuleNotFoundError: No module named 'httpx' in a project with no other
source. Most LLM SDKs provide it transitively; add it every time regardless.
3 · Run once
Have the user run the app so it emits at least one trace (run it yourself if it
is runnable here). If LLM credentials aren't available, the decorator/manual
span path in each reference produces real spans with no LLM call — wire one
workflow-decorated function and run that, so the pipeline can be proven
end-to-end before the model keys exist.
4 · Confirm & hand off — no platform read
Instrumentation is finished once the edits are in and the app has emitted at
least one trace. This skill does not read back over MCP. Confirming that the
spans actually landed is a separate, read-only step the user runs when they want
it — never something this skill does automatically. Do not call
list_observations, get_observation_details, or any other platform tool here.
Report what you already know from the edits themselves — the language, the
framework, and whether auto-instrumentation or manual spans are carrying the
trace — then tell the user plainly that wiring is done, and hand off with where
to confirm the traces:
Wiring is complete. Run your agent so it produces some traffic, then open
observability.progress.com and confirm the traces are flowing in for
service <app_name> — they should appear within a minute of the run.
An unverified wiring is a normal, healthy outcome — especially for a new user on
the free tier, who has no MCP key to read traces with. Treating it as a failure
is a bad first experience for exactly the people most likely to be trying the
product for the first time.
Never touch the platform from this skill — no reads, no writes. The only changes
it makes are the local instrumentation edits.