---
title: "Trace the Pi Coding Agent with Langfuse"
sidebarTitle: Pi Agent
logo: /images/integrations/pi-agent_icon.svg
description: "Trace Pi coding agent sessions with Langfuse — agent turns, model generations, token usage with cache and reasoning splits, cost, tool calls, and nested subagents."
category: Integrations
---

# Pi Coding Agent tracing with Langfuse

> **What is Pi?** [Pi](https://pi.dev) is a minimal, extensible AI coding agent that runs in your terminal. It supports 15+ providers and hundreds of models, and adapts to your workflows through extensions, skills, prompt templates, and themes.

> **What is Langfuse?** [Langfuse](https://langfuse.com/) is an open-source AI engineering platform. It helps teams trace agentic applications, debug issues, evaluate quality, and monitor costs in production.

The [`@langfuse/pi-observability-plugin`](https://github.com/langfuse/pi-observability-plugin) extension is built and maintained by the Langfuse team. If you run into issues, please open an issue on the repository.

This extension is an experimental release. Future versions can bring breaking changes to the setup and to the trace structure.

## What can this integration trace?

The plugin listens to Pi's core lifecycle events and sends every user prompt to Langfuse as its own trace:

- **Agent turns**: one trace per user prompt, with all turns of a Pi session grouped under one session ID. Turn numbering survives a Pi restart.
- **Model generations**: every model request with inputs, outputs, cost, time to first token, and token usage including cache-read and reasoning splits.
- **Tool calls**: each tool Pi invokes, with input, output, and an `ERROR` level when the call fails.
- **Images**: images you add to a prompt are uploaded as Langfuse media and render inside the trace.
- **Subagents**: Pi processes spawned by other extensions nest under the turn that started them.

## How it works

Pi has an extension API with core lifecycle events. An extension that subscribes to them sees every user prompt, model request and tool call of a session.

1. You register the extension in your pi settings with `pi install`, or load it for a single run with `pi -e`.
2. On startup, pi loads the extension and subscribes it to its core lifecycle events.
3. The extension converts turns, generations, tool calls and images into Langfuse traces and sends them to your project using the [Langfuse TypeScript SDK](/docs/observability/sdk/overview).
4. Credentials and options (`userId`, `environment`, `release`) are resolved from a config file or environment variables. See the [environment variables](#environment-variables).

## Quick start

<Callout type="info" title="Prerequisites">
Pi needs Node.js, and pi's package installer shells out to `npm`:

```bash
node --version   # must be 22.0.0 or newer
npm --version    # must print a version
```

If `node` is missing or older than 22, install Node.js 22+ with a version manager such as [fnm](https://github.com/Schniz/fnm), [nvm](https://github.com/nvm-sh/nvm), or [mise](https://mise.jdx.dev/). npm ships with Node.js, so it is present once Node.js is.

</Callout>

<Steps>

### Set up Langfuse

1. Sign up for [Langfuse Cloud](https://cloud.langfuse.com) or [self-host Langfuse](/self-hosting).
2. Create a new project and copy your API keys from the project settings.

### Install pi [#install-pi]

Install pi by following the [pi documentation](https://pi.dev/docs).

### Log in to a model provider

Pi needs a model before it can run a session. Start it:

```bash
pi
```

Type `/login` and pick a provider. Built-in subscription logins include Claude Pro/Max, ChatGPT Plus/Pro, and GitHub Copilot. If you would rather use an API key, see [pi's provider docs](https://pi.dev/docs). Once the login succeeds, type `/quit` to leave pi and proceed with the setup.

### Install the Langfuse extension

This downloads the extension and registers it in your pi settings (`~/.pi/agent/settings.json`):

```bash
pi install npm:@langfuse/pi-observability-plugin
```

Two variations, both optional:

| Goal                                        | Command                                               |
| ------------------------------------------- | ----------------------------------------------------- |
| Install for one project only, not globally  | `pi install -l npm:@langfuse/pi-observability-plugin` |
| Try it for a single run, without installing | `pi -e npm:@langfuse/pi-observability-plugin`         |

`-l` writes to `.pi/settings.json` inside the current project instead of your user settings, so you can commit it and share the setup with your team.

### Add your Langfuse credentials [#set-credentials]

Create a credentials file at `~/.pi/agent/langfuse.json`:

```json
{
  "publicKey": "pk-lf-...",
  "secretKey": "sk-lf-...",
  "baseUrl": "https://cloud.langfuse.com",
  "userId": "your-user-id",
  "environment": "development"
}
```

Only `publicKey` and `secretKey` are required. If `baseUrl` is omitted, the plugin uses `https://cloud.langfuse.com` (EU region). `userId`, `environment` and `release` are optional labels that let you segment traces by teammate, stage or version. Keep the file private, because it holds a secret key.

Alternatively, set your credentials with environment variables:

```bash
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_BASE_URL="https://cloud.langfuse.com"
export LANGFUSE_TRACING_ENVIRONMENT="development"
export LANGFUSE_USER_ID="your-user-id"
```

Environment variables take precedence over the config file, so you can override a single value without editing the file. These exports only apply to the current shell session. Add them to your shell profile to keep them.

### Run your first trace

Start pi in any project and give it a prompt:

```bash
cd your-project
pi "Summarize this repository"
```

### View traces in Langfuse

Open your Langfuse project to see the captured traces. The structure mirrors how pi actually works:

- **Turn trace**: one trace per user prompt, named `Pi - Turn 1 (...)`, with a `Conversational Turn` span that holds the whole turn.
- **Generations**: one `LLM Call` per model request, with its input, output, cost, time to first token, and token usage including the cache-read and reasoning splits.
- **Tool spans**: a `Tool: ...` observation for every tool pi invokes, with its input, its output, and an `ERROR` level when the call fails.
- **Sessions**: all turns of one pi session share a [`session_id`](/docs/observability/features/sessions), so you can replay the session in order. Turn numbering continues across a pi restart.
- **Environment and user**: traces are labeled with the configured [`environment`](/docs/observability/features/environments) and [`userId`](/docs/observability/features/users), so you can filter your own sessions or separate dev from CI.

</Steps>

## Environment variables

| Variable                       | Description                                                                                                                                                             | Required            |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `LANGFUSE_PUBLIC_KEY`          | Your Langfuse public key (`pk-lf-...`)                                                                                                                                  | Yes                 |
| `LANGFUSE_SECRET_KEY`          | Your Langfuse secret key (`sk-lf-...`)                                                                                                                                  | Yes                 |
| `LANGFUSE_BASE_URL`            | Langfuse host. EU: `https://cloud.langfuse.com`, US: `https://us.cloud.langfuse.com`, Japan: `https://jp.cloud.langfuse.com`, HIPAA: `https://hipaa.cloud.langfuse.com` | No (defaults to EU) |
| `LANGFUSE_TRACING_ENVIRONMENT` | Environment label for the traces (e.g. `production`)                                                                                                                    | No                  |
| `LANGFUSE_USER_ID`             | User ID attached to all traces                                                                                                                                          | No                  |

## Enable and disable tracing

| Scope                   | How                                                         |
| ----------------------- | ----------------------------------------------------------- |
| One run                 | `LANGFUSE_TRACING_ENABLED=false pi`                         |
| The current shell       | `export LANGFUSE_TRACING_ENABLED=false` (undo with `unset`) |
| Global or project scope | `pi config`, then switch the extension off                  |
| Remove the plugin       | `pi remove npm:@langfuse/pi-observability-plugin`           |

The kill switch has priority over environment keys and the config file. When tracing is off, the status line shows `langfuse: off (no keys)` and nothing is sent — note that this message reads the same whether the kill switch is set or the keys are genuinely missing. To remove stored keys, delete `~/.pi/agent/langfuse.json`.

## Troubleshooting

### No traces appearing in Langfuse

1. **Check the status line.** `langfuse: off (no keys)` means the plugin found no usable configuration. Two different causes produce this same message: the kill switch `LANGFUSE_TRACING_ENABLED=false` is set (check your shell profile and any inherited environment), or the credentials were not found — see [credentials setup](#set-credentials).
2. **Plugin not registered.** Run `pi list` and confirm the plugin appears.
3. **Region mismatch.** `baseUrl` (or `LANGFUSE_BASE_URL`) must match the region your keys belong to.
4. **Malformed credentials file.** A trailing comma or a missing quote makes `~/.pi/agent/langfuse.json` unreadable and the extension falls back to "no keys". Validate it:

   ```bash
   node -e "console.log(JSON.parse(require('fs').readFileSync(process.env.HOME + '/.pi/agent/langfuse.json', 'utf8')))"
   ```

5. **Environment variables from a previous terminal.** Variables set with `export` only live in that shell. If you configured credentials that way, either add them to your shell profile or use the credentials file instead.
6. **Inspect the plugin's steps.** Run with `PI_LANGFUSE_DEBUG=true` to log its activity to standard error.

### Authentication errors

Verify your API keys are correct and that the host matches the region your keys belong to:

- **EU region**: `https://cloud.langfuse.com`
- **US region**: `https://us.cloud.langfuse.com`
- **Japan region**: `https://jp.cloud.langfuse.com`
- **HIPAA region**: `https://hipaa.cloud.langfuse.com`

### Data privacy

The plugin sends Pi session data to Langfuse, which includes prompts, model outputs, tool inputs and outputs, and prompt images. Your Langfuse API keys are masked from all captured payloads before upload. Use the kill switch for sessions you do not want stored in Langfuse, and keep `~/.pi/agent/langfuse.json` private.

## Next steps

- **[Sessions](/docs/observability/features/sessions)**: review whole Pi sessions turn by turn.
- **[Users](/docs/observability/features/users) and [environments](/docs/observability/features/environments)**: segment traces by teammate or by dev/CI stage via `userId` and `environment`.
- **[Evaluation](/docs/evaluation/overview)**: score captured turns, for example with LLM-as-a-judge, to monitor agent quality over time.

## Resources

- [`pi-observability-plugin` repository (GitHub)](https://github.com/langfuse/pi-observability-plugin)
- [`@langfuse/pi-observability-plugin` on npm](https://www.npmjs.com/package/@langfuse/pi-observability-plugin)
- [Pi documentation](https://pi.dev/docs)
- [Langfuse TypeScript SDK](/docs/observability/sdk/overview)

<!-- agent-instructions -->

---

## Agent Instructions

This page is part of the [Langfuse](https://langfuse.com) documentation, published as plain Markdown for AI agents. Every page is available as Markdown by appending `.md` to its URL, or by sending an `Accept: text/markdown` header. This page: `https://langfuse.com/integrations/developer-tools/pi-agent.md`.

### Querying these docs

If the answer is not on this page, query the documentation instead of guessing:

- **Semantic search** across all Langfuse docs, returning an answer with the relevant pages and excerpts. Ask a specific, self-contained question:

  ```bash
  curl -sG "https://langfuse.com/api/search-docs" --data-urlencode "query=How do I trace a LangGraph agent?"
  ```

- **Index of every page**: <https://langfuse.com/llms.txt>, with per-section indexes [llms-docs.txt](https://langfuse.com/llms-docs.txt), [llms-integrations.txt](https://langfuse.com/llms-integrations.txt), and [llms-self-hosting.txt](https://langfuse.com/llms-self-hosting.txt).

### Before writing Langfuse code

- **Install the [Langfuse Agent Skill](https://langfuse.com/docs/api-and-data-platform/features/agent-skill).** It encodes Langfuse's own best practices for instrumentation, prompt management, and evaluation, and materially improves results.
- **Read [What does a good trace look like?](https://langfuse.com/docs/observability/best-practices.md)** before instrumenting an application.
- **Verify endpoints, parameters, and response fields** against the [API reference](https://api.reference.langfuse.com) instead of inferring them from code examples.
- **Use the [Langfuse CLI](https://langfuse.com/docs/api-and-data-platform/features/cli)** (`npx langfuse-cli api <resource> <action>`) to read or write traces, prompts, datasets, and scores from the terminal.

Found an error in these docs? Please open an issue at <https://github.com/langfuse/langfuse-docs/issues>.
