Note
Building with AI doesn’t have to be a solo grind.
Join our Discord community to meet other people exploring the latest models, tools, workflows, and ideas: https://discord.gg/whhrDtCrSS
We talk about what’s new, what’s useful, and what’s actually worth paying attention to in AI.
And if you want more than conversation, members also get access to heavily discounted AI products and services — including deals on tools like ChatGPT Plus and more for just a few dollars.
Full-stack Langfuse observability for Pi Coding Agent — from live traces to redacted training exports.
Every prompt, turn, tool call, and streaming response is traced with cost and token metadata. Secrets and PII are redacted at the extension boundary before anything leaves your machine. An optional append-only JSONL companion stream gives you training-ready, audit-safe data without touching Pi's original session files.
- Hierarchical Tracing: Maps user prompts to per-turn spans and nested tool executions.
- Streaming Generation: Captures assistant responses as they stream.
- LLM Metadata: Records model, provider, token usage, and cost fields when pricing is configured.
- Tool Observability: Captures tool calls, sanitized arguments/results, and duration.
- Session Correlation: Groups prompts from the same Pi session into one Langfuse session.
- Setup Wizard:
/langfuse-initconfigures either local self-hosted Langfuse or a remote/Langfuse Cloud endpoint. - Local-First Setup: Local mode creates a self-hosted localhost Langfuse stack with generated secrets.
- Autostart: Once local init is complete, the extension starts Docker Compose on demand when tracing begins.
- Raw Traces: Optional redacted JSONL companion stream for training, distillation, and audit workflows.
pi install git:github.com/edxeth/pi-langfuse/langfuse-init --yes --local
This creates a private Docker Compose stack with generated secrets. Defaults:
URL: http://localhost:3100/auth/sign-in
Email: local@example.test
Name: Local User
Password: local-langfuse
Files are written to $PI_CODING_AGENT_DIR/langfuse/. Init refuses to run in a non-empty directory.
After init, pi starts tracing on sessionful prompts. If local Langfuse is not healthy, the extension runs docker compose up -d automatically. Unpersisted/no-session runs are skipped by default.
Disable autostart for one process:
PI_LANGFUSE_AUTOSTART=0 pi/langfuse-init --yes --remote \
--host https://cloud.langfuse.com \
--public-key pk-lf-... \
--secret-key sk-lf-...
Remote mode creates only $PI_CODING_AGENT_DIR/langfuse/pi-langfuse.json. No Docker files, no autostart.
You can also configure keys manually via env vars or settings. Configuration precedence:
/extensions:settingsif the optional settings extension is installed$PI_CODING_AGENT_DIR/langfuse/pi-langfuse.jsonconfig.jsonin this extensionLANGFUSE_*environment variables
| Setting | Env Var | Default | Description |
|---|---|---|---|
| Enabled | - | true |
Global toggle for tracing. |
| Public Key | LANGFUSE_PUBLIC_KEY |
- | Langfuse project public key. |
| Secret Key | LANGFUSE_SECRET_KEY |
- | Langfuse project secret key. |
| Base URL | LANGFUSE_HOST |
https://cloud.langfuse.com |
API host. Use http://localhost:3100 for local. |
| User ID | PI_LANGFUSE_USER_ID |
$USER |
Associate traces with a specific user. |
| Environment | PI_LANGFUSE_ENV |
- | Tag traces, e.g. local, staging, production. |
| Release | PI_LANGFUSE_RELEASE |
- | Tag traces with a version or release ID. |
| Local Autostart | PI_LANGFUSE_AUTOSTART |
config dependent |
0 disables Docker autostart, 1 forces it. |
| Local Autostart Dir | PI_LANGFUSE_AUTOSTART_DIR |
$PI_CODING_AGENT_DIR/langfuse |
Directory containing docker-compose.yml. |
| Capture Provider Payload | PI_LANGFUSE_CAPTURE_PROVIDER_PAYLOAD |
false |
Optional provider payload capture inside Langfuse metadata. |
| Secret Redaction | PI_LANGFUSE_REDACTION / PI_LANGFUSE_UNREDACTED=1 |
true |
Redact known secrets and common token/PII-shaped patterns before Langfuse/raw-trace writes. Settings/config values take precedence over env opt-outs. |
| Additional Redaction Secrets | PI_LANGFUSE_REDACTION_SECRETS |
- | Comma-separated literal secrets to redact in addition to env/config secrets. |
| Raw Trace Export | PI_LANGFUSE_RAW_TRACE |
false |
Redacted JSONL companion stream for training/distillation data. |
| Raw Trace Directory | PI_LANGFUSE_RAW_TRACE_DIR |
$PI_CODING_AGENT_DIR/langfuse/raw-traces |
Root directory for raw trace companion files. |
| Raw Provider Request Mode | PI_LANGFUSE_RAW_PROVIDER_REQUEST |
summary |
Controls provider_request raw records: summary stores bounded request shape, full stores the exact redacted message array, off skips the record. |
/langfuse:toggle [on|off]
/langfuse-init --yes --local
/langfuse-init --yes --local --no-start
/langfuse-init --yes --remote --host https://cloud.langfuse.com --public-key pk-lf-... --secret-key sk-lf-...
/langfuse-init --dir ~/.pi/agent/langfuse
Every Pi event fans out to three destinations. Redaction happens at the pi-langfuse boundary -- Pi's own session file is never modified.
YOU TYPE A PROMPT
pi "..."
|
+------------------+------------------+
| |
v v
+---------------------------+ +---------------------------+
| Pi session JSONL | | pi-langfuse extension |
| (Pi core writes this) | | |
| | | sanitize() runs BEFORE |
| Unredacted originals. | | every write boundary |
| pi-langfuse never | | |
| touches these. | | Redacts: secrets, keys, |
| | | tokens, PII, credentials|
| ~/.pi/agent/ | | blobs, assignments. |
| sessions/ | | |
+---------------------------+ +------+------------+-------+
| |
+-----------+ +----------+
v v
+-------------------------+ +------------------+
| Raw trace JSONL | | Langfuse |
| (if enabled) | | server |
| | | |
| Append-only companion | | Local: |
| Redacted on write. | | localhost:3100 |
| | | Cloud: |
| langfuse/raw-traces/ | | cloud.langfuse |
+-------------------------+ | |
| Redacted on |
| send. |
+------------------+
Layer Redacted? By whom? When?
----------------------- ---------- ----------------- ---------------
Pi session JSONL NO Pi core On write
(originals) (untouchable)
Raw trace JSONL YES pi-langfuse Before append
(companion) (sanitize->write)
Langfuse traces YES pi-langfuse Before SDK send
(server) (sanitize->send)
Export derivatives YES export pipeline On copy
(output/) (always-on)
Trace (name: "pi-agent")
└── Span (name: "agent.prompt")
└── Span (name: "agent.turn")
├── Generation (name: "llm-response") <-- Cost/Token tracking
└── Span (name: "tool:<name>") <-- Arguments/Results
Langfuse is optimized for observability, not training archives. UI fields can be truncated and traces may be restructured. Raw traces are the append-only JSONL companion for fine-tuning, distillation, and audit.
Enable in config:
{
"rawTraceEnabled": true,
"rawTraceDir": "$PI_CODING_AGENT_DIR/langfuse/raw-traces",
"rawTraceProviderRequestMode": "summary"
}Raw traces mirror Pi's session layout under raw-traces/:
Pi session: <agent-dir>/sessions/--project--/<session>.jsonl
Raw trace: <agent-dir>/langfuse/raw-traces/--project--/<session>.jsonl
Fallback: <agent-dir>/langfuse/raw-traces/--unknown--/<session>.jsonl
Record types: session_start, agent_prompt_start, provider_request, tool_call, tool_result_first_seen, tool_execution_end, assistant_output, session_compact, session_end.
The key record is tool_result_first_seen: it captures a redacted summary of tool output immediately (no truncation — only secrets are redacted), before later extensions can compress or rewrite it. Raw traces continue writing even if Langfuse tracing is disabled or the server is unavailable. Raw trace writes are queued from event handlers and drained synchronously on session shutdown so no data is lost on clean exit. Very large records still require redaction, JSON serialization, and disk I/O, so use full provider-request capture only for controlled debug or data-capture runs.
provider_request records store bounded summaries by default: model, message count, estimated bytes, and redacted message summaries. Set rawTraceProviderRequestMode or PI_LANGFUSE_RAW_PROVIDER_REQUEST=full to capture the exact full redacted message array sent to the LLM. Set it to off to skip provider_request records entirely. PI_LANGFUSE_RAW_PROVIDER_REQUEST is a per-process override, so PI_LANGFUSE_RAW_PROVIDER_REQUEST=full pi can run one controlled exact-capture session without permanently changing the config file. session_end marks a clean session shutdown.
| Action | Raw trace behavior |
|---|---|
| Normal session | Writes one companion JSONL file with the same project directory and filename. |
| Display rename | No change; the session filename does not change. |
| Fork or clone | Starts a new raw trace file; parent evidence stays with the parent session. |
| Delete Pi session | Raw trace remains as training/audit evidence. |
| Manual filesystem move | Move the matching raw trace file yourself to keep paths mirrored. |
For a deep dive, see docs/architecture.md.
Use /langfuse:export inside Pi for small exports, or the standalone pi-langfuse-export CLI for bulk exports. Originals are never modified.
+-----------+ +-----------+ +------------+ +----------+
| DISCOVER |--->| COPY & |--->| SCAN |--->| GATE |
| | | REDACT | | | | |
| Walk | | | | Built-in | | approved |
| sessions/ | | JSON | | residual | | if 0 |
| raw- | | parse | | checks + | | findings |
| traces/ | | per line | | TruffleHog | | |
+-----------+ +-----------+ +------------+ +-----+----+
|
v
+--------------------------------------------------------------+
| ~/export/ |
| |
| sessions/ redacted Pi session copies |
| raw-traces/ redacted raw trace copies |
| manifest.jsonl one record per exported file |
| approved.jsonl approved file records |
| rejected.jsonl rejected file records |
| training-index.jsonl approved redacted derivatives |
| report.json scanner findings + approved/rejected |
| REVIEW.md human review summary |
| |
| Nothing uploaded. Nothing sent. Purely local. |
+--------------------------------------------------------------+
/langfuse:export
Synchronous -- convenient for small exports, but blocks the TUI during processing.
pi-langfuse-export \
--sessions-dir ~/.pi/agent/sessions \
--raw-dir ~/.pi/agent/langfuse/raw-traces \
--out ~/export \
--require-trufflehogStreams progress to stderr, prints JSON summary to stdout. Speed depends on JSONL size, disk, and TruffleHog scan time. Large archives can take minutes.
Flags:
--sessions-only export sessions only
--raw-only export raw traces only
--require-trufflehog reject export if TruffleHog is unavailable
--no-trufflehog skip external scan (local debug only)
- Redaction is always on.
PI_LANGFUSE_UNREDACTEDandredactionEnabledonly affect live telemetry, not exports. - Absolute source paths are replaced with
[PATH_ROOT]. - Original files are never modified (read-only copy).
- Langfuse web/API binds to
127.0.0.1:3100. Postgres, Redis, ClickHouse, and MinIO bind to localhost-only ports. - Langfuse telemetry is disabled in the generated
.envand Compose file. - Cloud is not used unless you explicitly configure a cloud host/key pair.
This does not change where your LLM provider sends prompts.
Redaction is enabled by default. Every raw trace record includes { "redaction": { "applied": true } }. Disable only for local debugging:
PI_LANGFUSE_UNREDACTED=1 piThe sanitizer covers: configured secret keys, secret-like env values, PI_LANGFUSE_REDACTION_SECRETS literals, sensitive object fields, private-key blocks, bearer tokens, GitHub/HuggingFace/OpenAI/Anthropic/AWS/Stripe/SendGrid/Docker/Slack tokens, JWTs, .env-style assignments, URL-embedded credentials, email/phone/SSN/credit-card PII, data URLs, and large base64/hex blobs.
Even redacted traces can contain private business data that is not token-shaped. Treat raw traces as private.
Redaction is forward-going. It does not rewrite old data.
| Existing data | After installing | Assume |
|---|---|---|
| Old Pi sessions | Unchanged | Contaminated originals. Use /langfuse:export for redacted copies. |
| Old raw traces | Unchanged | Reprocess before sharing, then archive or delete originals. |
| Old Langfuse traces | Unchanged | If secrets were sent, delete affected traces and rotate credentials. |
Do not train from raw originals. Train from redacted derivative exports.
Pi sessions + raw traces
-> /langfuse:export
-> redacted derivatives
-> scan/review/filter
-> normalize into training examples
-> train/fine-tune/distill
- Canonical session rewrite: Not done. Pi core owns session persistence. Use export for redacted copies.
- Binary/media payloads: Redacted as strings when seen in telemetry. No OCR or forensic inspection.
- Unknown secret formats: Covered by configured literals, broad patterns, and export scanner. No scanner catches everything -- add literals via
PI_LANGFUSE_REDACTION_SECRETS. - Semantic confidentiality: PII patterns catch tokens and identifiers. Business-sensitive content needs human review before sharing.
- No traces? Check
http://localhost:3100/api/public/health, API keys, and Pi console warnings. - Docker did not start? Run
docker compose up -dinside the local Langfuse directory. - Wrong login? Check the generated
.envforLANGFUSE_INIT_USER_EMAILandLANGFUSE_INIT_USER_PASSWORD. - Incomplete traces? Ensure your Pi version supports
message_*, tool, and session lifecycle events. - Cost is zero? Token usage can be captured even when model pricing is not configured.
- Large payloads in Langfuse UI? Adjust the max-char limits in config/settings.
- No raw trace file? Check
rawTraceEnabled,rawTraceDir, and that the run uses a persisted session rather than--no-session.
Heavily refactored fork of hdkiller/pi-langfuse.
MIT

