@the-agency/pi-observability

Record tool usage, tokens, models, skills, and sessions as JSONL timeseries data in OpenTelemetry format.

Packages

Package details

extension

Install @the-agency/pi-observability from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@the-agency/pi-observability
Package
@the-agency/pi-observability
Version
0.2.1
Published
May 15, 2026
Downloads
not available
Author
joshmock
License
MIT
Types
extension
Size
20.5 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@the-agency/pi-observability

Pi extension that emits one OTel GenAI-compatible span document per assistant turn. Documents are written to a configurable sink (Elasticsearch by default) and share a schema with pi-sessions-to-otel.ts so both sources index into the same index without mapping conflicts.

What it captures

Each span document represents one LLM API call and includes:

  • OTel GenAI semantic convention fields (gen_ai.*)
  • Token usage and cost per turn (gen_ai.usage.*, cost.*)
  • Full assistant text, thinking blocks, tool calls, and tool results
  • User message text (skill injection blocks stripped)
  • Session context: working directory, session file, session ID, active skills, tools, and registered commands
  • Model and provider info, thinking level, response ID
  • A stable pi.turn.exchange_id grouping all turns from one user prompt

Schema

All documents share these top-level fields:

Field Type Description
@timestamp ISO-8601 When the assistant turn completed
span.id UUID Unique span identifier
trace.id string Session ID (groups all spans in one session)
span.name string gen_ai chat <model>
duration.us long Turn duration in microseconds
gen_ai.system keyword Normalized provider name (e.g. anthropic, openai)
gen_ai.operation.name keyword Always chat
gen_ai.request.model keyword Model ID sent in the request
gen_ai.response.model keyword Model ID returned in the response
gen_ai.response.finish_reasons keyword[] Stop reason(s) from the provider
gen_ai.usage.input_tokens long
gen_ai.usage.output_tokens long
gen_ai.usage.cache_read_input_tokens long
gen_ai.usage.cache_creation_input_tokens long
gen_ai.usage.total_tokens long
message.user.text text User prompt text
message.assistant.text text Assistant response text
message.assistant.thinking text Thinking block content, if present
tool_calls object[] {id, name, arguments, arguments_text} per call
tool_results object[] {tool_call_id, tool_name, output} per result
turn.tool_call_count long
turn.tool_result_count long
pi.session.id keyword Stable session UUID
pi.session.cwd keyword Working directory
pi.session.start ISO-8601 Session start time
pi.session.file keyword Path to the .pi session file
pi.session.skills object[] {name, path, source, scope} for each loaded skill
pi.session.skill_names keyword[] Skill names only
pi.session.tools object[] {name, source, scope} for each active tool
pi.session.active_tools keyword[] Active tool names only
pi.session.commands keyword[] Registered slash command names
pi.turn.exchange_id keyword UUID shared across all turns in one user prompt
pi.model.provider keyword Raw provider name from pi
pi.model.api keyword API identifier
pi.thinking_level keyword Thinking level if set
pi.thinking.present boolean Whether a thinking block was present
pi.response_id keyword Provider response ID (used as ES _id)
cost.total_usd float
cost.input_usd float
cost.output_usd float
service.name keyword Always pi-coding-agent
telemetry.sdk.name keyword Always pi-observability-extension

Fields with no value are omitted (not written as null).

pi-sessions-to-otel.ts

A standalone ETL script that reads existing pi session JSONL files and bulk-indexes them into Elasticsearch. Produces the same schema as the live extension so historical and live data share one index.

Environment variables

Variable Required Default Description
PI_OTEL_ES_URL yes Elasticsearch base URL
PI_OTEL_ES_API_KEY yes Elasticsearch API key
PI_OTEL_INDEX no pi-otel-genai-spans Target index name
PI_OTEL_SESSIONS_ROOT no ~/.pi/agent/sessions Root directory of pi session folders

Usage

PI_OTEL_ES_URL=http://localhost:9200 \
PI_OTEL_ES_API_KEY=your_key \
node --experimental-transform-types pi-sessions-to-otel.ts

Installation

Project-local

Add to .pi/settings.json in your project:

{
  "packages": ["npm:@the-agency/pi-observability"]
}

Global

pi install npm:@the-agency/pi-observability