@ravan08/pi-langfuse
Langfuse observability and provenance-safe observational memory for Pi Coding Agent.
Package details
Install @ravan08/pi-langfuse from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@ravan08/pi-langfuse- Package
@ravan08/pi-langfuse- Version
2.0.0- Published
- Aug 18, 2026
- Downloads
- 395/mo · 89/wk
- Author
- saravananravi11
- License
- MIT
- Types
- extension
- Size
- 805.7 KB
- Dependencies
- 4 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./index.ts"
],
"image": "https://raw.githubusercontent.com/saravananravi08/pi-langfuse-extension/main/docs/screenshot1.jpg"
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
Pi Langfuse Observability + Memory
Langfuse integration for Pi Coding Agent combining production-grade tracing with optional observational memory. It records Pi turns, model usage, cost, and tool calls; generates structured trace observations; consolidates long sessions into reflections; and can safely replace covered model-visible history with compact memory.
Stored Pi session history is never deleted or rewritten. Memory context replacement is opt-in and blocks rather than guessing when exact Pi-entry provenance cannot be verified.

🔭 What It Does
📊 Observability
- Maps each Pi turn to a Langfuse trace.
- Records model, provider, latency, token usage, and cost.
- Captures nested tool calls, arguments, results, and errors.
- Groups traces by Pi session and working directory.
🧠 Observational Memory
- Creates asynchronous episodic
memory_trace_observationscores with exact user requests, question/answer pairs, corrections, durable items, and Pi provenance. - Consolidates active observations into append-only canonical
memory_session_reflectionscores. - Keeps exact recent user requests as deterministic working memory.
- Reduces durable state by authority: user corrections > user state > verified results > assistant proposals.
- Retrieves prompt-relevant episodes automatically instead of injecting every observation.
- Creates safe in-turn checkpoints after 20 completed tool calls, 8k new textual tokens, or 70% context usage.
- Exposes scoped recall through the
langfuse_memory_lookuptool. - Optionally replaces structurally and semantically covered model-visible history through
/memory-context on. - Records exact Pi session entries and complete tool-call/result pairs as provenance.
- Provides read-only audits, controlled backfill, redacted diagnostics, and bounded source retrieval.
🧠 Memory Flow
Pi agent turn
│
├─ Langfuse trace
│ ├─ LLM generation
│ └─ tool spans
│
└─ memory_trace_observation score
│
├─ latest uncovered observations
└─ threshold reached
│
▼
memory_session_reflection score
│
▼
active memory + scoped lookup
│
▼
optional provenance-safe model context
Observations and reflections are Langfuse scores, not additions to raw trace events. Reflections are append-only; the current reflection is selected by highest generation, then generatedAt.
🛡️ Safety Guarantees
- Pi's stored JSONL session history remains unchanged.
- Context replacement affects only messages sent to the model.
- Covered ranges must belong to the current Pi session and active branch.
- Observations from abandoned sibling branches remain available for lookup but are excluded from active context and reflection inputs.
- Entry ranges must be complete, contiguous, non-overlapping, and exactly mapped.
- Semantic coverage must preserve every user request, correction, and question before raw messages become replaceable.
- The latest two raw user turns are retained where they fit; oversized turns keep the exact request and newest complete tail.
- A latest branch-compatible v1 reflection and deterministic v1 observations after it may replace only exact, complete Pi-provenance ranges. V2 ranges win on overlap; v1 semantic details remain lower-priority context, and recent exact turns are retained.
- Tool calls and results remain complete pairs.
- Calls emitted by errored or aborted assistant responses are accepted only when proven unexecuted.
- Current trailing user messages and pending parallel tool results are retained safely.
- Invalid or incomplete provenance disables replacement immediately.
- In-turn checkpoints start near 70% of the selected model window. Validated replacement may use up to 80%, leaving headroom for continued work and Pi compaction.
- Lookup output and diagnostic logs redact secret-like values.
- Session changes and shutdown abort queued or running memory work.
📦 Install
Stable npm package
pi install npm:@ravan08/pi-langfuse
Git repository
pi install git:github.com/saravananravi08/pi-langfuse-extension
The provenance-safe lookup and context-replacement work is currently being tested on feature/provenance-memory-context and has not been published to npm yet. To test that exact build:
pi install git:github.com/saravananravi08/pi-langfuse-extension@feature/provenance-memory-context
Pi packages execute with full system access. Review third-party package source before installing.
🚀 Quick Start
Requires Node.js 20+ and Langfuse Cloud or a self-hosted Langfuse v4 server. Tracing uses the GA JS/TS SDK v5 OpenTelemetry path; memory reads use Observations API v2 and Scores API v3.
1. Create Langfuse keys
Create project API keys in Langfuse Cloud or your self-hosted Langfuse v4 instance.
2. Create config.json
Copy config.example.json to config.json in the installed package directory, then set your credentials and observer model:
{
"publicKey": "YOUR_LANGFUSE_PUBLIC_KEY",
"secretKey": "YOUR_LANGFUSE_SECRET_KEY",
"host": "https://cloud.langfuse.com",
"observer": {
"enabled": true,
"api": "anthropic",
"baseUrl": "https://api.example.com/anthropic",
"apiKey": "YOUR_OBSERVER_API_KEY",
"model": "YOUR_OBSERVER_MODEL",
"fallback": {
"provider": "openai-codex",
"model": "gpt-5.4-mini",
"reasoning": "low",
"cooldownMs": 300000
}
},
"memory": {
"reflection": {
"enabled": true,
"thresholdTokens": 20000,
"minNewObservationTokens": 8000,
"minNewObservations": 5
}
}
}
Install paths depend on package source, Pi scope, and Node installation. Use pi list to confirm the source. For a global npm install, find npm's actual package root with:
npm root -g
Place config.json beside this package's index.ts. Typical locations are:
npm, global: <npm-root>/@ravan08/pi-langfuse/config.json
npm, project: <project>/.pi/npm/@ravan08/pi-langfuse/config.json
git, global: ~/.pi/agent/git/github.com/saravananravi08/pi-langfuse-extension/config.json
git, project: <project>/.pi/git/github.com/saravananravi08/pi-langfuse-extension/config.json
config.json is gitignored and must never be committed.
The observer supports Anthropic-compatible and OpenAI-compatible endpoints. Optional fallback models are resolved through Pi's model registry and existing auth; OAuth tokens are never copied into extension config. After two primary failures, memory generation uses the fallback directly for cooldownMs. Background retry details stay in the private JSONL log; the TUI shows only a temporary concise footer status.
Example OpenAI-compatible configuration:
{
"observer": {
"enabled": true,
"api": "openai",
"baseUrl": "https://api.openai.com",
"apiKey": "YOUR_OBSERVER_API_KEY",
"model": "YOUR_OBSERVER_MODEL"
}
}
3. Fully restart Pi
A full process restart is required after extension module changes. /reload may retain imported modules in Node's cache.
4. Run a turn and verify memory
pi "inspect this project and summarize its architecture"
After the turn completes, Langfuse should contain a pi-agent trace and, when the observer is enabled, a memory_trace_observation score. In interactive Pi:
/memory-context preview
/memory-context on
preview shows the exact replacement plan without changing model context. on succeeds only when all safety checks pass.
🧭 Usage
Automatic tracing
Pi auto-loads the extension. Normal prompts require no special command:
pi "your prompt"
Memory context commands
/memory-context preview Show structural/semantic coverage, retained entries, tool pairs, and token estimates
/memory-context explain <topic> Show winning/superseded durable state and exact provenance
/memory-context on Enable provenance-gated model-visible context replacement
/memory-context off Restore full Pi model context
/memory-context status Show current setting
/memory-context Toggle on/off
While replacement is active, Pi shows compact status such as:
Memory 24.9%/272k · est 7.1k · $1.235
The percentage is actual provider input usage against the selected model's context window. est is the estimated textual replacement-message size. Cost is cumulative main-model cost reported by the provider; OAuth subscription models show $0.000 (sub), matching Pi, and cost is omitted when neither pricing nor subscription status is available. Binary image data is excluded and reported separately, for example est 7.1k + 2 images, because image token accounting varies by provider and model.
Scoped memory lookup
Pi can call langfuse_memory_lookup when exact older decisions, files, errors, symbols, IDs, or source traces are needed.
langfuse_memory_lookup({
query: "authentication migration decision",
scope: "path",
includeSource: true,
includePiEntries: true
})
Scopes:
session— current session and cwd; default.path— sessions sharing the selected cwd/path key.all— all available memory scores.
Exact traceId and scoreId filters are supported. includeSource returns bounded details for at most two source traces. includePiEntries returns at most 50 exact, redacted Pi entries per matched session.
⚙️ Configuration
Tracing requires publicKey, secretKey, and host. Memory generation additionally requires an observer API key and model.
| Setting | Default | Purpose |
|---|---|---|
observer.enabled |
true |
Generate trace observation scores when model config exists. |
observer.api |
anthropic |
anthropic or openai compatible request format. |
observer.baseUrl |
Provider default | Observer/reflector API base URL. |
observer.apiKey |
Provider environment key | Observer/reflector API credential. |
observer.model |
none | Observer and reflector model ID. |
observer.fallback.provider |
none | Pi model-registry provider used after primary failure. |
observer.fallback.model |
none | Authenticated Pi fallback model ID. |
observer.fallback.reasoning |
low |
Fallback reasoning level. |
observer.fallback.cooldownMs |
300000 |
Time to bypass unhealthy primary after two failures. |
memory.reflection.enabled |
false |
Enable automatic session reflection. |
memory.reflection.thresholdTokens |
20000 |
Minimum active structured-memory size. |
memory.reflection.minNewObservationTokens |
8000 |
Minimum uncovered observation size. |
memory.reflection.minNewObservations |
5 |
Minimum uncovered observation count. |
All three reflection thresholds must pass. Token estimates count every structured reflector field, not only rendered Markdown.
Environment variables override file configuration:
PI_LANGFUSE_OBSERVER_ENABLED=true
PI_LANGFUSE_OBSERVER_API=anthropic
PI_LANGFUSE_OBSERVER_BASE_URL=https://api.example.com/anthropic
PI_LANGFUSE_OBSERVER_API_KEY=...
PI_LANGFUSE_OBSERVER_MODEL=...
PI_LANGFUSE_OBSERVER_FALLBACK_PROVIDER=openai-codex
PI_LANGFUSE_OBSERVER_FALLBACK_MODEL=gpt-5.4-mini
PI_LANGFUSE_OBSERVER_FALLBACK_REASONING=low
PI_LANGFUSE_OBSERVER_FALLBACK_COOLDOWN_MS=300000
PI_LANGFUSE_REFLECTION_ENABLED=true
PI_LANGFUSE_REFLECTION_THRESHOLD_TOKENS=20000
PI_LANGFUSE_REFLECTION_MIN_NEW_TOKENS=8000
PI_LANGFUSE_REFLECTION_MIN_NEW_OBSERVATIONS=5
PI_LANGFUSE_MEMORY_ERROR_LOG=~/.pi/agent/logs/langfuse-memory-errors.jsonl
Prompts are centralized in memory/memory-prompts.js. observer-v3 and reflection-v5 outputs must pass structured schema, authority, semantic-coverage, retention, duplication, and contradiction checks. Reflection Markdown is rendered deterministically within the computed target (maximum 10k estimated tokens), while complete canonical fields remain in Langfuse metadata. Default injected memory is bounded to approximately 10k estimated textual tokens.
🗃️ Langfuse Data Model
Logical trace: pi-agent
├─ Root observation: pi-agent
│ ├─ sessionId: Pi session ID
│ ├─ input/output: user and assistant messages
│ └─ metadata: model, provider, cwd, completion state
├─ Generation observation: llm-response
│ ├─ model and provider
│ ├─ input/output tokens
│ └─ input/output/total cost
├─ Tool observation: tool:<name>
│ ├─ arguments and result
│ └─ error state
└─ Score: memory_trace_observation
├─ exact user requests and question/answer pairs
├─ corrections, durable items, task delta, files, and tools
├─ replacementEligible + semanticCoverage
└─ exact pi-entry-v1 provenance
Session score: memory_session_reflection
├─ generation and coveredUntil
├─ canonical durable state with authority/status/source IDs
├─ active/superseded decisions and constraints
├─ source observation/reflection score IDs
├─ source trace IDs
└─ aggregated Pi entry ranges and tool pairs
Trace name, session ID, cwd, model, and provider are propagated to every child observation. Overall user input and final assistant output live on the root observation; deprecated trace-level input/output is not emitted. LANGFUSE_TRACING_ENVIRONMENT and LANGFUSE_RELEASE configure deployment attributes.
Active memory is scoped by Langfuse session ID and cwd/path key. A persistent context mirror is stored at ~/.pi/agent/cache/langfuse-memory/<path-hash>/<session-id>.json. Resume loads this validated local snapshot first, then refreshes Langfuse asynchronously. Files are atomically replaced with 0600 permissions and are rejected when host, project-key hash, session, path, schema, or score scope differs. Langfuse remains canonical; explicit refreshes and source lookups still use Langfuse.
🧰 Audit, Backfill, and Reflection Scripts
Read-only audit
node scripts/observe-langfuse-session.mjs <session-id> --audit
--audit does not write. It reports missing observations, historical pre-coverage traces, incomplete or invalid Pi provenance, semantic-coverage failures, active decision conflicts, duplicate scores, overlapping entries, deterministic-ID mismatches, and prompt versions.
Controlled observation backfill
node scripts/observe-langfuse-session.mjs <session-id> --audit --backfill --dry-run
node scripts/observe-langfuse-session.mjs <session-id> --audit --backfill
node scripts/observe-langfuse-session.mjs <session-id> --audit --backfill --include-pre-coverage
Backfill writes only eligible traces that map uniquely to complete Pi provenance. --include-pre-coverage explicitly includes older historical traces.
Additional controls:
node scripts/observe-langfuse-session.mjs <session-id> --dry-run --limit 1
node scripts/observe-langfuse-session.mjs <session-id> --trace <trace-id> --audit --backfill
node scripts/observe-langfuse-session.mjs <session-id> --force
Version-2 migration is append-only. Use --trace for a targeted repair or --include-pre-coverage for an explicitly reviewed historical migration.
Reflection inspection or generation
node scripts/reflect-langfuse-session.mjs <session-id>
node scripts/reflect-langfuse-session.mjs <session-id> --dry-run
node scripts/reflect-langfuse-session.mjs <session-id> --force --dry-run
node scripts/reflect-langfuse-session.mjs <session-id> --path /project/cwd --limit 10
Without --force, configured thresholds apply. --dry-run may call the reflector but never writes a score.
Both scripts read the same config.json. One-off observer aliases and authenticated Pi models are supported:
OBSERVER_API=openai OBSERVER_BASE_URL=https://api.openai.com OBSERVER_API_KEY=... OBSERVER_MODEL=... \
node scripts/observe-langfuse-session.mjs <session-id>
node scripts/observe-langfuse-session.mjs <session-id> --backfill \
--pi-provider openai-codex --pi-model gpt-5.4-mini --pi-reasoning low
node scripts/reflect-langfuse-session.mjs <session-id> --force \
--pi-provider openai-codex --pi-model gpt-5.4-mini --pi-reasoning low
Pi-model mode resolves fresh credentials through Pi's auth storage and never prints or copies OAuth tokens.
🩺 Diagnostics
Memory failures are appended to:
~/.pi/agent/logs/langfuse-memory-errors.jsonl
The file is created with 0600 permissions. Records contain safe request, validation, scope, and provenance details but never raw observer or reflector model output. Use PI_LANGFUSE_MEMORY_ERROR_LOG to override the path.
⚠️ Operational Limits
- Version-1 reflections or tail observations without complete Pi provenance remain lookup-only. Complete branch-compatible v1 ranges support migration-free structural compatibility; v2 remains semantic authority.
- Context replacement orders the latest reflection and 20 recent text turns, reducing toward 10 whole turns when needed. Only observations not already covered by the reflection are inserted after their matching turns. Every retained completed tool pair uses deterministic bounded payloads; only the active uncheckpointed tail and exact errors remain raw. Older thinking, images, and tool payloads are removed from model-visible context.
langfuse_memory_lookupmodel output is capped at 12,000 characters by default or 24,000 with explicit source/Pi-entry retrieval; internal tool details contain only bounded accounting metadata.- Context replacement intentionally fails closed on ambiguous branches, mappings, or tool pairs.
- Request throttling is coordinated within one Pi process; multiple concurrent Pi processes do not yet share a global rate limiter.
- Pi auto-compaction behavior is unchanged.
- Traces are buffered by the OpenTelemetry processor, force-flushed after each completed Pi turn, and shut down gracefully with the Pi session. Process termination that bypasses
session_shutdowncan still lose buffered spans. - Imported extension modules may remain cached after
/reload; use a full restart when testing code changes.
🛠️ Troubleshooting
No traces
- Verify Langfuse keys and
host. - Confirm the extension appears in
pi list. - Fully restart Pi.
No memory_trace_observation
- Set
observer.enabled=true. - Configure
observer.modelandobserver.apiKey. - Final observation runs asynchronously after
agent_end; long turns can also emit non-overlapping in-turn checkpoints. - Transient
408,429, and5xxresponses retry up to eight times with bounded exponential or provider-directed backoff. - If all retries fail, run the read-only audit, then controlled
--backfillafter the provider recovers. - Inspect the private diagnostic log.
No memory_session_reflection
- Set
memory.reflection.enabled=true. - Confirm all three thresholds pass.
- Run
scripts/reflect-langfuse-session.mjs <session-id>for status.
Memory context is blocked
- Run
/memory-context previewand inspect the exact reason. - Run the session audit for incomplete, invalid, or overlapping provenance.
- Do not bypass the gate; retain full Pi context until provenance is valid.
Model cost is missing
Not every provider reports pricing data. Token usage may still be available.
🤝 Contributing
Contributions are welcome.
- Fork the repository.
- Create a focused feature or fix branch.
- Install dependencies with
npm install. - Make the smallest relevant change and add or update tests.
- Run
npm test. - Submit a pull request describing the problem, solution, and verification.
Open an issue before large architectural changes. Never commit config.json, API keys, private session data, or files under documents/.
📚 Dependencies
@langfuse/tracing— Langfuse JS/TS SDK v5 observation API.@langfuse/otel— Langfuse OpenTelemetry span processor.@opentelemetry/sdk-node— Node.js OpenTelemetry lifecycle.@mariozechner/pi-coding-agent— Pi extension API.
📄 License
MIT
