Skip to content
How-to guide

Trace with Phoenix

PowerContext exports OpenTelemetry spans for transport and application operations. When tracing is enabled, the generation and embedding calls that PowerContext itself constructs are traced too, so one trace shows the request, the Memory operation, and the model calls underneath it.

This guide sends those spans to Phoenix running locally.

Start Phoenix

docker run -d --name powercontext-phoenix -p 6006:6006 arizephoenix/phoenix:20.1.0

Phoenix serves both its UI and its OTLP HTTP receiver on port 6006. Open http://localhost:6006 to confirm it is running. Pin an explicit tag so the endpoint and UI layout match this guide.

Install the export dependency

Recording and export require the tracing-otlp extra:

uv tool install "powercontext[cli,server,tracing-otlp] @ git+https://github.com/oceanbase/powercontext.git@master"

Without this extra, enabling tracing fails at startup with an explicit error instead of silently dropping spans.

Configure and start the Server

Enable tracing, point the exporter at Phoenix, and configure a generation model so inference spans have something to record:

export POWERCONTEXT_SERVER_TRACING_ENABLED=true
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:6006
export OTEL_SERVICE_NAME=powercontext-server
export POWERCONTEXT_SERVER_INFERENCE_GENERATION_MODEL=provider:model-name
powercontext server run

The OpenTelemetry SDK appends /v1/traces to OTEL_EXPORTER_OTLP_ENDPOINT, so the spans arrive at http://localhost:6006/v1/traces. Use OTEL_EXPORTER_OTLP_HEADERS for a Phoenix deployment that requires authentication. Set the provider credentials your generation model needs; PowerContext never records them.

Trigger one inference request

Capture a Source, then convert it into Memory:

curl -X POST http://localhost:8000/v1/sources/content \
  -H 'content-type: application/json' \
  -d '{"scope_id":"project:demo","source_id":"task-1","content":"I always book aisle seats."}'
curl -X POST http://localhost:8000/v1/memory/flush \
  -H 'content-type: application/json' \
  -d '{"scope_id":"project:demo"}'

Memory extraction runs during the flush, not during capture.

Read the trace

Open http://localhost:6006, select the default project, and open the most recent trace for powercontext-server. The flush produces four nested spans in one trace:

Span Meaning
HTTP flush_memory The inbound HTTP request. powercontext.request.id matches the X-PowerContext-Request-ID response header.
powercontext flush_memory The application operation, independent of the transport that invoked it.
invoke_agent memory_extraction One PowerContext generation task. The name identifies the purpose, not the model.
chat <model> One request to the model provider, with token usage and latency.

Scoped operations add the following internal stage spans beneath their application operation. Read-only searches never take the write lock, so they emit no scope.lock span:

Span Meaning
scope.context Resolving the scope's context from the configured provider; near zero for the built-in provider, visible when a provider does I/O here.
scope.lock Waiting for the scope write lock, ending the moment it is acquired. powercontext.scope.lock.contended reports whether another operation already held it.
memory.search Memory lookup for search_memory or prepare_context; embedding and reranking spans, when present, are nested beneath it.
memory.rerank One actual reranker call; model-backed reranking nests invoke_agent memory_rerank beneath it.
experience.search Experience recall during prepare_context; emitted even when recall is not configured.
context.build The synchronous step that selects and renders the final prepared context from recalled candidates.

The other PowerContext generation tasks appear under the same convention: experience_incubation, experience_generation, skill_generation, handoff_generation, and memory_rerank. When an embedding model is configured, embedding calls appear as embeddings <model> spans under the operation that triggered them.

Spans are exported in batches, so allow a few seconds before refreshing. An MCP request produces MCP mcp.tools.call in place of the HTTP span. Readiness probes are deliberately not traced, so health checks do not create single-span traces.

What is not exported

PowerContext configures inference instrumentation to exclude content. Spans carry model identifiers, token usage, durations, and error categories. Prompts, model responses, Memory content, and vectors are excluded, and message attributes record only the shape of each message rather than its text.

Stop Phoenix

docker rm -f powercontext-phoenix

Span names and attributes follow the Pydantic AI GenAI semantic conventions and can change when that dependency is upgraded across a major version. Do not treat them as a stable contract.