> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thecontext.company/llms.txt
> Use this file to discover all available pages before exploring further.

# Pi

> Integrate The Context Company with Pi using the Pi CLI extension or the Pi Agent SDK.

## Set TCC environment variables

<Tip>The Pi extension and SDK both default to using the `TCC_API_KEY` environment variable.</Tip>

```typescript .env.local theme={null}
TCC_API_KEY="your-api-key"
```

## Instrument Pi

Use the SDK path when you create Pi sessions or event streams from your own TypeScript code. Use the Extension path when you run Pi from the command line.

<Tabs>
  <Tab title="SDK">
    #### Step 1: Install dependencies

    <CodeGroup>
      ```Title pnpm theme={null}
      pnpm add @contextcompany/pi @mariozechner/pi-coding-agent
      ```

      ```Title npm theme={null}
      npm i @contextcompany/pi @mariozechner/pi-coding-agent
      ```

      ```Title bun theme={null}
      bun add @contextcompany/pi @mariozechner/pi-coding-agent
      ```
    </CodeGroup>

    #### Step 2: Add instrumentation to your agent

    Import the `instrumentPiSession` function and call it with your Pi agent session. This subscribes to all agent events and automatically exports traces to The Context Company.

    ```typescript agent.ts theme={null}
    import { createAgentSession } from "@mariozechner/pi-coding-agent";
    import { instrumentPiSession } from "@contextcompany/pi";

    const { session } = await createAgentSession();

    instrumentPiSession(session);

    await session.prompt("What files are in the current directory?");
    ```

    That's it! All your agent runs will now be automatically tracked in The Context Company.

    #### Step 3: Instrument Pi event streams

    If you're working with Pi event streams directly instead of a session object, you can use `instrumentPiEventStream` to wrap an `AsyncIterable` of events. This forwards each event through the telemetry listener and automatically exports traces to The Context Company.

    ```typescript agent.ts theme={null}
    import { instrumentPiEventStream } from "@contextcompany/pi";

    // Wrap your event stream with instrumentation
    const instrumentedStream = instrumentPiEventStream(events);

    for await (const event of instrumentedStream) {
      // Process events as usual — telemetry is captured automatically
      console.log(event);
    }
    ```

    The `instrumentPiEventStream` function accepts the same [config options](#adding-custom-metadata) as `instrumentPiSession`, including `metadata`, `sessionId`, `conversational`, and `debug`.

    ```typescript agent.ts theme={null}
    import { instrumentPiEventStream } from "@contextcompany/pi";

    const instrumentedStream = instrumentPiEventStream(events, {
      metadata: {
        environment: "staging",
        feature: "repo-review",
        customerTier: "enterprise",
      },
      sessionId: "some-session-id",
      conversational: true,
    });

    for await (const event of instrumentedStream) {
      console.log(event);
    }
    ```

    You can retrieve the last run ID from the instrumented stream:

    ```typescript agent.ts theme={null}
    const instrumentedStream = instrumentPiEventStream(events);

    for await (const event of instrumentedStream) {
      // ...
    }

    const lastRunId = instrumentedStream.getLastRunId();
    ```
  </Tab>

  <Tab title="Extension">
    #### Step 1: Install the Pi CLI extension

    If you use Pi from the command line, install The Context Company as a Pi extension. The extension automatically records Pi agent runs, messages, and tool executions without changing your agent code.

    ```bash theme={null}
    pi install npm:@contextcompany/pi
    ```

    #### Step 2: Start Pi

    ```bash theme={null}
    pi
    ```

    Run `/tcc-status` inside Pi to confirm that telemetry is active. If a run has completed, the command also returns the last TCC run ID recorded by the extension.

    #### Step 3: Add extension metadata

    To attach metadata to runs captured by the extension, add a `.pi/tcc.json` file to your project.

    ```json .pi/tcc.json theme={null}
    {
      "metadata": {
        "environment": "staging",
        "feature": "repo-review",
        "customerTier": "enterprise",
        "tcc.sessionId": "conversation-123",
        "tcc.conversational": true
      }
    }
    ```

    You can also set default metadata globally in `~/.pi/agent/tcc.json`. Project metadata in `.pi/tcc.json` is merged on top of global metadata.

    <Note>
      The extension uses `TCC_API_KEY` for authentication. Debug logging is covered in [Debug mode](#debug-mode).
    </Note>

    <Note>
      The extension handles Pi CLI runs automatically. SDK-only controls such as `instrumentPiEventStream`, `unsubscribe`, and assigning a run ID before each prompt with `setRunId()` are only available when you instrument Pi from code.
    </Note>
  </Tab>
</Tabs>

## Adding custom metadata

Custom metadata allows you to add additional properties to your [agent runs](/concepts#agent-runs).

This is particularly useful for tying agent runs to your own specific business logic, letting you filter and analyze agent runs by user, organization, feature, or some other dimension.

<Tabs>
  <Tab title="SDK">
    Pass custom metadata and reserved `tcc.*` metadata as key-value pairs to the `metadata` object in the config.

    ```typescript agent.ts theme={null}
    import { createAgentSession } from "@mariozechner/pi-coding-agent";
    import { instrumentPiSession } from "@contextcompany/pi";

    const { session } = await createAgentSession();

    instrumentPiSession(session, {
      metadata: {
        environment: "staging",
        feature: "repo-review",
        customerTier: "enterprise",
        "tcc.sessionId": "conversation-123",
        "tcc.conversational": true,
        "tcc.agent": "coding-agent",
        "tcc.userId": "user-123",
        "tcc.orgId": "org-456",
      },
    });
    ```
  </Tab>

  <Tab title="Extension">
    Add the same metadata fields to `.pi/tcc.json`:

    ```json .pi/tcc.json theme={null}
    {
      "metadata": {
        "environment": "staging",
        "feature": "repo-review",
        "customerTier": "enterprise",
        "tcc.sessionId": "conversation-123",
        "tcc.conversational": true,
        "tcc.agent": "coding-agent",
        "tcc.userId": "user-123",
        "tcc.orgId": "org-456"
      }
    }
    ```
  </Tab>
</Tabs>

Agent runs are automatically indexed by your custom metadata fields and can be filtered directly in the dashboard.

<Note>
  The `tcc.*` namespace is reserved. Only the [reserved TCC metadata keys](/concepts#tcc-metadata-keys) (`tcc.runId`, `tcc.sessionId`, `tcc.conversational`, `tcc.agent`, `tcc.userId`, `tcc.userName`, `tcc.orgId`, `tcc.orgName`) are recognized; any other `tcc.*` keys are ignored. None of them appear in your custom metadata.

  A Pi session can fire many runs, but `metadata` is captured once and reused for every run in that session. Do not put `tcc.runId` here. In SDK instrumentation, use `instrumentation.setRunId(...)` before each prompt to assign a per-run ID.
</Note>

## Adding user feedback

User feedback allows you to collect score (thumbs up & thumbs down) and text feedback (up to 2000 characters) from end users on your [agent runs](/concepts#agent-runs).

This is useful for tracking user satisfaction, identifying problematic responses, and filtering agent runs in the dashboard to focus on positive or negative feedback.

### Step 1: Generate and pass a run ID

Use `setRunId()` on the instrumentation object to assign a unique run ID before each prompt. After the run completes, retrieve it with `getLastRunId()`.

```typescript agent.ts theme={null}
import { createAgentSession } from "@mariozechner/pi-coding-agent";
import { instrumentPiSession } from "@contextcompany/pi";
import { randomUUID } from "crypto";

const { session } = await createAgentSession();

const instrumentation = instrumentPiSession(session);

// Generate a unique run ID (must be a UUID) before each prompt
const runId = randomUUID();
instrumentation.setRunId(runId);

await session.prompt("What files are in the current directory?");

// Return the runId to your client
return { runId };
```

<Note>
  Programmatic feedback is only supported with SDK instrumentation. The Pi CLI extension can show the last completed run ID with `/tcc-status` for debugging, but it does not provide a stable app-facing `setRunId()` flow for collecting feedback from users.
</Note>

### Step 2: Submit feedback from your client

Store the `runId` on your client, then when the user provides feedback, submit it using the `submitFeedback` function.

Both `score` and `text` are optional individually, but each request must include at least one of them:

`score` is the thumbs rating. Use only `"thumbs_up"` or `"thumbs_down"`.

`text` is written feedback from your user, up to 2000 characters.

```typescript feedback.ts theme={null}
import { submitFeedback } from "@contextcompany/pi";

// Submit score and/or text feedback:
await submitFeedback({
  runId: runId, // The run ID from your agent execution
  score: "thumbs_up", // Optional thumbs rating: "thumbs_up" or "thumbs_down"
  text: "This was a helpful response!", // Optional written user feedback, up to 2000 characters
});
```

Agent runs with feedback can be filtered in the dashboard using the feedback filter.

## Tracking agent sessions

[Agent sessions](/concepts#agent-sessions) represent multiple agent runs that are grouped together. The most common use case is tracking entire conversations between a human user and an AI agent in chatbot interfaces.

Agent sessions can be tracked by setting a session ID.

<Tabs>
  <Tab title="SDK">
    ```typescript agent.ts theme={null}
    import { createAgentSession } from "@mariozechner/pi-coding-agent";
    import { instrumentPiSession } from "@contextcompany/pi";

    const { session } = await createAgentSession();

    instrumentPiSession(session, {
      sessionId: "conversation-123", // Track agent sessions
      metadata: {
        environment: "staging",
        feature: "repo-review",
        customerTier: "enterprise",
      },
    });
    ```
  </Tab>

  <Tab title="Extension">
    ```json .pi/tcc.json theme={null}
    {
      "metadata": {
        "environment": "staging",
        "feature": "repo-review",
        "customerTier": "enterprise",
        "tcc.sessionId": "conversation-123"
      }
    }
    ```
  </Tab>
</Tabs>

The value of `sessionId` should be a unique identifier for the agent session. This can be any string, but it's generally recommended to use a UUID.

Agent sessions are automatically indexed and can be filtered directly in the dashboard.

## Marking runs as conversational

A [conversational run](/concepts#conversational-runs) is an agent run that was initiated by a user. Marking a run as conversational tells The Context Company that this run involves direct user interaction.

This is important because conversational runs are the only runs monitored for user insights, such as user confusion, frustration, or any other custom insights you want to track. Runs that are not marked as conversational (e.g. background jobs, cron tasks, or internal automations) are excluded from user insight analysis.

Mark a run as conversational by setting `tcc.conversational` in extension metadata or `conversational` in SDK config.

<Tabs>
  <Tab title="SDK">
    ```typescript agent.ts theme={null}
    import { createAgentSession } from "@mariozechner/pi-coding-agent";
    import { instrumentPiSession } from "@contextcompany/pi";

    const { session } = await createAgentSession();

    instrumentPiSession(session, {
      conversational: true,
      metadata: {
        environment: "staging",
        feature: "repo-review",
        customerTier: "enterprise",
      },
    });
    ```
  </Tab>

  <Tab title="Extension">
    ```json .pi/tcc.json theme={null}
    {
      "metadata": {
        "environment": "staging",
        "feature": "repo-review",
        "customerTier": "enterprise",
        "tcc.conversational": true
      }
    }
    ```
  </Tab>
</Tabs>

<Note>
  The `conversational`, `sessionId`, and `runId` options on `instrumentPiSession` are typed shortcuts for the reserved [TCC metadata keys](/concepts#tcc-metadata-keys).
</Note>

## Identifying the agent

If your product ships more than one named agent, set the reserved `tcc.agent` metadata key to scope the session to a specific [agent](/concepts#agents). The dashboard's top-level agent selector, per-agent patterns and recaps, and the `agent` filter on the [REST API](/access-data/api) and [MCP tools](/access-data/mcp) all read from this key.

<Tabs>
  <Tab title="SDK">
    ```typescript agent.ts theme={null}
    import { instrumentPiSession } from "@contextcompany/pi";

    instrumentPiSession(session, {
      metadata: {
        environment: "staging",
        feature: "repo-review",
        customerTier: "enterprise",
        "tcc.agent": "coding-agent",
      },
    });
    ```
  </Tab>

  <Tab title="Extension">
    ```json .pi/tcc.json theme={null}
    {
      "metadata": {
        "environment": "staging",
        "feature": "repo-review",
        "customerTier": "enterprise",
        "tcc.agent": "coding-agent"
      }
    }
    ```
  </Tab>
</Tabs>

<Note>
  Agent names that collide with reserved dashboard routes (for example `runs`, `sessions`, `patterns`, `recaps`, `overview`, `search`, `failures`, `feedback`, `tools`, `topics`, `views`, `settings`, `mcp-and-api`) are dropped.
</Note>

## Identifying users and organizations

Attach the end user and their organization to a Pi session as first-class identity using the reserved `tcc.userId`, `tcc.userName`, `tcc.orgId`, and `tcc.orgName` metadata keys. This is **not the same** as adding a `userId` field to custom metadata — these keys promote user and org identity to dedicated dashboard filters and unlock native user/org search, per-user views, and per-org analytics. See [User and organization identity](/concepts#user-and-organization-identity) for the full concept.

Set these whenever you have a stable identifier for the end user or their organization in your product.

<Tabs>
  <Tab title="SDK">
    ```typescript agent.ts theme={null}
    import { instrumentPiSession } from "@contextcompany/pi";

    instrumentPiSession(session, {
      metadata: {
        environment: "staging",
        feature: "repo-review",
        customerTier: "enterprise",
        "tcc.userId": "user-123",
        "tcc.userName": "Jane Doe",
        "tcc.orgId": "org-456",
        "tcc.orgName": "Acme Inc.",
      },
    });
    ```
  </Tab>

  <Tab title="Extension">
    ```json .pi/tcc.json theme={null}
    {
      "metadata": {
        "environment": "staging",
        "feature": "repo-review",
        "customerTier": "enterprise",
        "tcc.userId": "user-123",
        "tcc.userName": "Jane Doe",
        "tcc.orgId": "org-456",
        "tcc.orgName": "Acme Inc."
      }
    }
    ```
  </Tab>
</Tabs>

<Note>
  `tcc.userName` and `tcc.orgName` require the corresponding ID (`tcc.userId` / `tcc.orgId`) to also be set. Names without IDs are dropped.
</Note>

## Cleanup

The `instrumentPiSession` function returns an object with an `unsubscribe` method you can call to stop listening for events. This is only needed for SDK instrumentation; the Pi CLI extension manages its own lifecycle.

```typescript agent.ts theme={null}
const instrumentation = instrumentPiSession(session);

// Later, when you're done:
instrumentation.unsubscribe();
```

## Debug mode

You can enable debug mode, which will log any events that are captured and sent.

For the Pi CLI extension, set `TCC_DEBUG=true` before starting Pi:

```bash theme={null}
TCC_DEBUG=true pi
```

For SDK instrumentation, pass `debug: true`:

```typescript agent.ts theme={null}
import { createAgentSession } from "@mariozechner/pi-coding-agent";
import { instrumentPiSession } from "@contextcompany/pi";

const { session } = await createAgentSession();

instrumentPiSession(session, {
  debug: true, // Enable debug mode
});
```
