Skip to content
telemetry.dev
Esc
navigateopen⌘Jpreview
On this page

Pi coding agent

Trace pi agent loops, model calls, tool executions, usage, cost, and lifecycle events.

@telemetry-dev/pi adds telemetry.dev to @earendil-works/pi-coding-agent. It targets pi 0.82.1 and accepts pi 0.80.4 or later.

What it captures

A session shares one trace across prompts:

session
└── invoke_agent
    ├── chat {model}
    │   ├── execute_tool {toolName}
    │   └── execute_tool {toolName}
    └── chat {model}
  • session wraps the full pi session; each prompt adds an invoke_agent child.
  • invoke_agent records the prompt, final assistant content, result, and session ID.
  • chat {model} records provider, models, response ID, finish reason, token usage, pi’s estimated USD cost, the provider-formatted request, and all returned content blocks.
  • execute_tool {toolName} records the tool-call ID, arguments, result, and error state.
  • Session, turn, compaction, model-change, and shutdown events become logs.

Tool spans nest under the chat span that issued the tool call. A tool without a matching chat span nests under invoke_agent.

Each event reads the current pi session ID and records it as gen_ai.conversation.id, so session changes keep their own telemetry.

Content capture

Prompt input includes image blocks. Chat input comes from before_provider_request, after pi’s context handlers and model-message conversion. System instructions come from the effective ctx.getSystemPrompt() at that request boundary.

Assistant output includes text, thinking, tool-call blocks, and provider signatures. Tool arguments and results are also captured. captureInput and captureOutput default to true; use them to disable the corresponding content, or use mask to remove selected values before serialization. Model names, usage, cost, session IDs, and lifecycle metadata are still recorded when content capture is off.

The request is not necessarily the final wire payload: a later handler can replace it. Custom providers must call pi’s onPayload callback for request and system-instruction capture. Without it, those fields are absent; prompt, output, and tool capture still work.

Set up the integration

Make a project at telemetry.dev. Then copy an API key from the project’s setup page.

Set these variables in the environment that starts pi:

export TELEMETRY_DEV_API_KEY=td_live_...
export TELEMETRY_DEV_ENVIRONMENT=development
export OTEL_SERVICE_NAME=pi

The integration reads all setup values from the environment when pi loads the package entry.

Pi package

Add the package to ~/.pi/agent/settings.json:

{
  "packages": ["npm:@telemetry-dev/pi"]
}

The package manifest points to ./dist/register.mjs. The public @telemetry-dev/pi/register entry exports telemetryDevExtension() with environment setup.

Extension file

If pi can resolve the package, add ~/.pi/agent/extensions/telemetry-dev.ts:

import { telemetryDevExtension } from "@telemetry-dev/pi";

export default telemetryDevExtension();

Use the factory form when you must set options in code:

import { telemetryDevExtension } from "@telemetry-dev/pi";

export default telemetryDevExtension({
  agentName: "pair-programmer",
  captureInput: false,
  captureOutput: true,
});

Span lifecycle

agent_start opens the invoke_agent span. Retries and compaction can start the agent loop again, but they keep the same span.

This behavior lets a later retry replace a retryable result before the prompt settles. session_shutdown closes an unfinished prompt and the session span, then waits for the final flush. A session change does not shut down the SDK.

Pi does not supply TTFT or request-duration values. The integration measures chat duration from message_start to message_end with the local clock.

Environment variables

Variable Required Default Description
TELEMETRY_DEV_API_KEY Yes None Ingest API key. Without a key, the integration is a no-op.
TELEMETRY_DEV_BASE_URL No https://ingest.telemetry.dev OTLP ingest base URL.
TELEMETRY_DEV_ENVIRONMENT No production Environment on exported telemetry.
OTEL_SERVICE_NAME No pi OpenTelemetry service name.

Options

telemetryDevExtension() accepts TelemetryDevExtensionOptions. The type contains SDK options except registerGlobal, plus agentName.

Option Type Default Description
agentName string pi Value for gen_ai.agent.name.
apiKey string TELEMETRY_DEV_API_KEY Ingest API key.
baseUrl string TELEMETRY_DEV_BASE_URL or production ingest Ingest base URL.
environment string TELEMETRY_DEV_ENVIRONMENT or production Deployment environment.
serviceName string OTEL_SERVICE_NAME or pi Service name on each trace.
enabled boolean true Set to false for a complete no-op.
exportMode "batched" | "immediate" batched Span export mode.
captureInput boolean true Capture prompts, images, provider requests, system instructions, and tool arguments.
captureOutput boolean true Capture assistant content blocks and tool results.
mask (value, context) => unknown None Change captured values before serialization.
maxAttributeLength number 65536 Maximum content attribute length.
batch BatchOptions SDK defaults Batch size, delay, queue, and timeout settings.
spanFilter (span) => boolean None Select spans for export.
resourceAttributes Record<string, AttributeValue> None Add OpenTelemetry resource attributes.
logLevel "debug" | "info" | "warn" | "error" | "silent" warn SDK diagnostic level.
fetch typeof fetch globalThis.fetch Custom fetch implementation.
waitUntil (promise) => void None Extend serverless work for export.
onError (error) => void None Receive integration errors. The extension does not throw them into pi.

The integration forces registerGlobal to false. The first initialization in a process supplies the SDK options.

Open the trace explorer after a prompt settles. For API key setup, refer to the quickstart.

Last updated on September 5, 2026

Was this page helpful?