@lifanh/pi-langfuse-extension
Langfuse observability extension for Pi Coding Agent
Package details
Install @lifanh/pi-langfuse-extension from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@lifanh/pi-langfuse-extension- Package
@lifanh/pi-langfuse-extension- Version
0.1.3- Published
- Jun 6, 2026
- Downloads
- 254/mo · 254/wk
- Author
- lifanh
- License
- MIT
- Types
- extension
- Size
- 171.5 KB
- Dependencies
- 6 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./dist/index.js"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@lifanh/pi-langfuse-extension
Langfuse observability for Pi Coding Agent.
Use this extension to send Pi agent runs, model calls, tool executions, token usage, cost, and errors to Langfuse. By default it sends metadata only. Prompt, response, tool I/O, system prompt, and cwd capture are opt-in. Captured local paths are redacted or replaced with stable hashes before transmission.
Quickstart
Install the extension:
pi install npm:@lifanh/pi-langfuse-extension
Configure Langfuse from inside Pi:
/langfuse-configure publicKey=pk-lf-... secretKey=sk-lf-...
/langfuse-test
/langfuse-status
After an agent run, check Langfuse for a pi-agent-run trace with nested generation and tool observations.
Current status
Version 0.1.2 is prepared for npm as @lifanh/pi-langfuse-extension.
This package is still in pre-1.0 development. Releases are published from GitHub Releases through the Publish GitHub Actions workflow using npm Trusted Publishing.
Do not publish a stable 1.0.0 until golden trace tests, REST fallback behavior, and production burn-in are completed.
What it records
Each Pi agent run creates:
- an
agentobservation for the overall run generationobservations for provider/model callstoolobservations for tool executions
Default traces answer questions like:
- Did a Pi agent run happen?
- Which model and provider were used?
- Which turns and tools ran?
- How many tokens were used?
- What did the call cost, if Pi/provider reported cost?
- Did a provider or tool report an error?
Default metadata includes:
| Observation | Sent by default | Not sent by default |
|---|---|---|
| Agent run | agent, extension, model, provider, sessionId |
user prompt, attachments/images/context, system prompt, cwd |
| Generation | model, model parameters, usage, cost, provider/API, response id, stop reason, turn index, HTTP status/headers |
provider request payload and assistant response content |
| Tool | toolName, toolCallId, isError |
tool arguments and tool results |
Enabling content capture
Content capture is controlled by explicit flags. Captured content is redacted before it is sent to Langfuse.
Enable individual fields:
/langfuse-configure captureInputs=true captureOutputs=true
Available flags:
| Flag | Default | When enabled |
|---|---|---|
captureInputs / LANGFUSE_CAPTURE_INPUTS |
off | Captures provider request/user input content after redaction. |
captureOutputs / LANGFUSE_CAPTURE_OUTPUTS |
off | Captures assistant/provider output content after redaction. |
captureToolIo / LANGFUSE_CAPTURE_TOOL_IO |
off | Captures tool arguments and results after redaction. |
captureSystemPrompt / LANGFUSE_CAPTURE_SYSTEM_PROMPT |
off | Captures the effective system prompt after redaction. |
captureCwd / LANGFUSE_CAPTURE_CWD |
off | Captures the current working directory after path redaction/hashing. |
debug / LANGFUSE_DEBUG |
off | Enables extension debug logging. |
To return to metadata-only tracing:
/langfuse-configure captureInputs=false captureOutputs=false captureToolIo=false captureSystemPrompt=false captureCwd=false
Configuration
Configure from Pi:
/langfuse-configure publicKey=pk-lf-... secretKey=sk-lf-... host=https://cloud.langfuse.com
/langfuse-configure preserves omitted fields when a saved config file already exists. For example, this updates only the host:
/langfuse-configure host=https://us.cloud.langfuse.com
Configuration is saved at:
~/.pi/agent/@lifanh/pi-langfuse-extension/config.json
You can also configure non-interactively with environment variables:
export LANGFUSE_PUBLIC_KEY=pk-lf-...
export LANGFUSE_SECRET_KEY=sk-lf-...
export LANGFUSE_HOST=https://cloud.langfuse.com
Configuration source is selected as a whole:
- If both
LANGFUSE_PUBLIC_KEYandLANGFUSE_SECRET_KEYare set, environment configuration is used.LANGFUSE_HOSTorLANGFUSE_BASE_URLandLANGFUSE_CAPTURE_*flags are read from the same environment. - Otherwise, the saved config file is used (
~/.pi/agent/@lifanh/pi-langfuse-extension/config.json). - Built-in defaults fill in missing optional values (
https://cloud.langfuse.com, metadata-only tracing, all content capture flags off).
Environment host and capture flags are not merged into a saved config unless the environment also provides both credentials. If both environment credentials and the config file are present, environment configuration wins. /langfuse-status shows this as environment variables (overrides config file).
Commands
| Command | Purpose |
|---|---|
/langfuse-status |
Show configuration source, masked public key, host, capture settings, debug setting, config path, and last transport error. |
/langfuse-configure ... |
Save or update credentials, host, debug, and capture flags. Omitted fields are preserved from the saved config file. |
/langfuse-test |
Make a timeout-bounded authenticated Langfuse API request and report success or failure in Pi. |
Commands validate arguments before changing configuration. If a command receives captureInputs instead of captureInputs=true, an unknown option such as capturePrompts=true, or an invalid boolean such as captureInputs=yes, Pi shows a warning with accepted usage and an example.
When the extension is loaded but unconfigured, Pi shows a one-time onboarding hint. During configured agent runs, the footer displays ◉ langfuse and clears it when the run ends or the session shuts down.
Verify setup
- Run
/langfuse-statusto confirm the effective source, host, capture settings, and last error. - Run
/langfuse-testto verify credentials and host connectivity. - Start an agent run and check for the
◉ langfusefooter indicator. - Check Langfuse for a
pi-agent-runtrace with nested generation/tool observations.
Disable or reset
To temporarily disable tracing, unset LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY, then remove the saved config file shown by /langfuse-status:
rm ~/.pi/agent/@lifanh/pi-langfuse-extension/config.json
To keep tracing but disable content capture:
/langfuse-configure captureInputs=false captureOutputs=false captureToolIo=false captureSystemPrompt=false captureCwd=false
Troubleshooting
| Symptom | Fix |
|---|---|
/langfuse-status says not configured |
Run /langfuse-configure publicKey=... secretKey=... or set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY. |
/langfuse-test returns 401 or 403 |
Check that the public and secret keys belong to the same Langfuse project and host. |
/langfuse-test times out |
Verify network access and LANGFUSE_HOST; self-hosted instances must be reachable from the Pi process. |
| Status shows environment variables overriding the file | Update/unset the environment variables, or expect them to take precedence over /langfuse-configure values. |
| No prompt/response content appears in Langfuse | This is the default. Enable only the needed fields with /langfuse-configure. |
| Pi runs continue despite Langfuse errors | Expected. Langfuse failures are isolated; check /langfuse-status for the last captured error. |
Architecture
Pi Agent Events
│
├── session_start ──▶ one-time onboarding hint if unconfigured
├── before_agent_start ──▶ initTransport() ──▶ createAgentSpan() ──▶ footer status
├── before_provider_request ──▶ createGenerationSpan() (child of agent span)
├── after_provider_response ──▶ store response metadata for generation
├── message_end ──▶ cache assistant message
├── turn_end ──▶ endGenerationSpan() (usage + output + errors)
├── tool_execution_start ──▶ createToolSpan() (child of agent span)
├── tool_execution_end ──▶ endToolSpan() (update + end)
├── agent_end ──▶ endAgentSpan() ──▶ flush() ──▶ clear footer
└── session_shutdown ──▶ shutdown() ──▶ clear footer
Transport details:
- Uses
BasicTracerProviderfrom@opentelemetry/sdk-trace-basewithLangfuseSpanProcessorfrom@langfuse/otel. - Creates Langfuse observations via
startObservationfrom@langfuse/tracing. - Uses Langfuse's isolated tracer provider hook instead of registering a global OpenTelemetry provider.
- Sets trace-level attributes (
langfuse.trace.name, tags, metadata, andsession.id) on agent spans and copies them to child generation/tool spans. - Reinitializes transport if saved/env host or credentials change during a long-running Pi process.
- Records the last transport error for
/langfuse-statuswhile keeping Langfuse failures isolated from Pi agent execution.
Redaction
Captured content passes through a shared redaction pipeline before transmission. The redactor covers:
- API keys and bearer tokens
- Authorization, cookie, token, password, and secret-like fields
- Langfuse, OpenAI, Anthropic, GitHub, npm, and AWS-style token patterns
- Private key blocks
.env-style key/value secrets- Common local absolute paths (
/Users,/home,/tmp,/private/tmp, andC:\Users), replaced with stable short hashes - Large or deeply nested payloads, with bounded traversal
Development
Install dependencies and run checks:
npm install
npm run typecheck
npm test
npm run build
npm pack --dry-run
Changes here should preserve these constraints:
- No production telemetry payload bypasses
redactValue. - No raw prompt, response, tool I/O, system prompt, cwd, or file path capture without an explicit capture flag.
- Langfuse failures must not break Pi agent execution.
- REST fallback remains disabled until duplicate/idempotent behavior is tested.
- Tests must cover redaction and disabled capture behavior before transport changes.
Release
Publishing is automated through GitHub Actions:
- Update the package version.
- Push the version commit and tag to GitHub.
- Publish a GitHub Release for that tag.
- The
Publishworkflow runsnpm ci, typechecking, tests, build,npm pack --dry-run, andnpm publish.
The workflow publishes to the official npm registry with OIDC-based npm Trusted Publishing, so no long-lived npm token is stored in GitHub.
License
MIT