pi-otel
OpenTelemetry traces for pi-coding-agent — per-prompt span tree (interaction → llm_request, tool.<name>) exported via OTLP. Aspire-dashboard ready.
Package details
Install pi-otel from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-otel- Package
pi-otel- Version
0.3.0- Published
- Sep 13, 2026
- Downloads
- 4,497/mo · 1,349/wk
- Author
- nikiforovall
- License
- Apache-2.0
- Types
- extension
- Size
- 174.1 KB
- Dependencies
- 8 dependencies · 1 peer
Pi manifest JSON
{
"image": "https://raw.githubusercontent.com/nikiforovall/pi-otel/master/assets/pi-otel-poster.png",
"video": "https://raw.githubusercontent.com/NikiforovAll/pi-otel/master/assets/demo.mp4",
"extensions": [
"./dist/index.js"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-otel
OpenTelemetry tracing for pi agent.
Full OTel GenAI semantic-convention coverage (gen_ai.*) for token usage, cost, model, finish reasons, and tool calls.
Install
pi install npm:pi-otel
Quickstart
/otel start # spawn local Aspire dashboard
Backend auto-detect: Aspire CLI first, then Docker / Podman. Install one:
- Aspire CLI
- Docker or Podman
Configuration
.pi/settings.json (project) or ~/.pi/agent/settings.json (global):
{
"otel": {
"enabled": true,
"endpoint": "http://localhost:4317",
"protocol": "grpc",
"headers": {},
"serviceName": "pi",
"captureContent": "metadata_only",
"spanNaming": "legacy",
"sampleRatio": 1.0,
"signals": { "traces": true, "metrics": false, "logs": false }
}
}
For the http/protobuf and http/json protocols, endpoint is the base URL — each signal appends its own resource path (/v1/traces, /v1/metrics, /v1/logs). For grpc the endpoint is used as-is.
spanNaming: "genai" (default "legacy") renames spans to the OTel GenAI agent conventions — invoke_agent pi / chat {model} / execute_tool {tool} — and adds gen_ai.operation.name plus the spec SpanKind, so backends recognise pi as an agent. It also adds gen_ai.agent.name on the interaction span and, on chat spans only, gen_ai.provider.name (the request's inference provider, e.g. openai, aws.bedrock). No existing attribute is ever removed in either mode; legacy keeps the pi.* names existing dashboards query.
Key env var overrides: OTEL_EXPORTER_OTLP_ENDPOINT, PI_OTEL_SPAN_NAMING=genai, PI_OTEL_METRICS=1, PI_OTEL_LOGS=1, PI_OTEL_DISABLED=1.
Custom providers that skip pi's onPayload hook (pi-vertex and others) still get a pi.llm_request span with tokens and cost, opened from the assistant message_start and tagged pi.llm_request.synthesized=true. See custom providers.
propagateToShell: true (default false) passes TRACEPARENT to processes started by the bash and powershell tools, so instrumented children nest under the tool span. It overrides the built-in tool, which pi reports with a one-time warning. See shell propagation.
Only one OpenTelemetry SDK can own a process. If another extension registers its providers first, pi-otel warns once and stays disabled instead of silently routing spans into the other SDK. See running alongside other OTel extensions.
Full reference — settings, env vars, content capture modes, sampling, logs signal, and extensibility: nikiforovall.blog/pi-otel/configuration
