# How to Integrate Earendil Pi with the Anthropic API: A Complete Guide

> Integrate Earendil Pi with the Anthropic API. Configure credentials, select a Claude model, and use the streaming SDK or CLI with the anthropic-messages provider for seamless integration.

- Repository: [Earendil Works/pi](https://github.com/earendil-works/pi)
- Tags: how-to-guide
- Published: 2026-05-25

---

**To integrate Earendil Pi with the Anthropic API, configure your credentials via environment variables or OAuth, select a Claude model from the built-in registry, and invoke the streaming SDK or CLI using the `anthropic-messages` provider.**

The **earendil-works/pi** repository provides first-class integration with Anthropic’s Claude models through a dedicated provider architecture. Whether you prefer command-line workflows or programmatic SDK access, Pi handles credential resolution, streaming response parsing, and model selection automatically. This guide covers the complete integration path from authentication to advanced proxy configurations.

## Installation and Setup

Install the Pi CLI globally via npm or download the standalone binary:

```bash
npm i -g @earendil-works/pi

```

Alternatively, use the pre-built binary for your platform:

```bash
curl -L https://github.com/earendil-works/pi/releases/latest/download/pi-linux-x64 -o pi && chmod +x pi

```

## Authentication Methods

Pi supports two authentication mechanisms for Anthropic, resolving credentials automatically through [`packages/ai/src/env-api-keys.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/env-api-keys.ts).

### API Key Authentication

Set the `ANTHROPIC_API_KEY` environment variable with your Anthropic API key:

```bash
export ANTHROPIC_API_KEY=sk-ant-...

```

The `getEnvApiKey()` function checks for this variable when initializing requests.

### OAuth Authentication

For Anthropic subscription accounts, use the built-in OAuth helper in [`packages/ai/src/utils/oauth/anthropic.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/utils/oauth/anthropic.ts):

```bash
npx @earendil-works/pi-ai login anthropic

```

This command opens a browser for authentication and stores a refresh token in `~/.pi/agent/settings.json`. **Note:** `ANTHROPIC_OAUTH_TOKEN` takes precedence over `ANTHROPIC_API_KEY` if both are present, as implemented in the credential resolver.

## Selecting Anthropic Models

Pi maintains a model registry in [`packages/ai/src/model-catalog.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/model-catalog.ts) that defines supported Claude models with `api: "anthropic-messages"` identifiers.

List available Anthropic models via the CLI:

```bash
pi list-models | grep anthropic

```

Common built-in model IDs include:

- **claude-sonnet-4-5** (default)
- **claude-opus-4-6**
- **claude-3-5-haiku-20241022**

Each registry entry specifies `cacheControlFormat: "anthropic"` for compatible models, enabling automatic cache-control header management.

## Integration Methods

### Using the CLI

The CLI entry point in [`packages/ai/src/cli.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/cli.ts) exposes the `pi login anthropic` command and the `--provider anthropic` flag.

Execute a simple prompt:

```bash
pi --provider anthropic --model claude-opus-4-6 \
    -p "Write a short poem about the moon."

```

The CLI pipeline performs the following actions:

1. Resolves credentials via `getEnvApiKey()`
2. Looks up the model in the registry using `modelRegistry.find("anthropic", "<model-id>")`
3. Applies Anthropic-specific options through `buildBaseOptions()` in [`simple-options.ts`](https://github.com/earendil-works/pi/blob/main/simple-options.ts)
4. Streams the response to stdout using the provider implementation in [`packages/ai/src/providers/anthropic.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/providers/anthropic.ts)

### Using the TypeScript SDK

For programmatic integration, import the streaming functions exported from [`packages/ai/src/index.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/index.ts):

```typescript
import { getModel, streamSimpleAnthropic } from "@earendil-works/pi-ai";

async function main() {
  // Resolve model configuration from the registry
  const model = getModel("anthropic", "claude-opus-4-6");

  // Stream text chunks from Claude
  for await (const chunk of streamSimpleAnthropic(model, {
    messages: [{ role: "user", content: "Explain recursion in 50 words." }],
    maxTokens: 512,
    temperature: 0.7,
  })) {
    process.stdout.write(chunk);
  }
}

main().catch(console.error);

```

The `streamSimpleAnthropic()` function is a convenience wrapper around `streamAnthropic()` that yields raw text chunks rather than full `AssistantMessage` objects. For advanced use cases requiring tool calls or metadata, use `streamAnthropic()` directly with the `AnthropicOptions` type definition.

## Advanced Configuration

### Custom Base URLs and Proxies

To route requests through a proxy such as Cloudflare AI Gateway, register a custom provider at runtime:

```typescript
import { registerProvider, getModel } from "@earendil-works/pi-ai";
import Anthropic from "@anthropic-ai/sdk";

registerProvider("my-anthropic", {
  api: "anthropic-messages",
  baseUrl: "https://my-proxy.example.com/v1",
  stream: async (model, opts) => {
    const client = new Anthropic({ 
      apiKey: opts.apiKey, 
      baseUrl: "https://my-proxy.example.com/v1" 
    });
    // Forward opts to client.messages.createStreaming()
  },
});

const model = getModel("my-anthropic", "claude-sonnet-4-5");
await streamSimpleAnthropic(model, { 
  messages: [{ role: "user", content: "Hi!" }] 
});

```

Reference the complete implementation in [`packages/coding-agent/examples/extensions/custom-provider-anthropic/index.ts`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/examples/extensions/custom-provider-anthropic/index.ts) for handling streaming JSON parsing and event normalization.

## Summary

- **Credential Resolution:** Pi automatically selects between OAuth tokens (`ANTHROPIC_OAUTH_TOKEN`) and API keys (`ANTHROPIC_API_KEY`) via [`packages/ai/src/env-api-keys.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/env-api-keys.ts).
- **Provider Architecture:** The `anthropic-messages` provider in [`packages/ai/src/providers/anthropic.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/providers/anthropic.ts) handles streaming SSE events and Claude-specific tool name canonicalization.
- **Model Registry:** Built-in models are defined in [`packages/ai/src/model-catalog.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/model-catalog.ts) with automatic cache-control formatting.
- **Dual Interface:** Use the CLI for quick interactions or the SDK (`streamSimpleAnthropic`, `streamAnthropic`) for programmatic integration.
- **Extensibility:** Register custom providers to support proxies or alternative Anthropic-compatible endpoints without modifying core code.

## Frequently Asked Questions

### How does Pi handle authentication priority between OAuth and API keys?

According to the source code in [`packages/ai/src/env-api-keys.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/env-api-keys.ts), the `getEnvApiKey()` function checks for `ANTHROPIC_OAUTH_TOKEN` before falling back to `ANTHROPIC_API_KEY`. This design allows seamless switching between authentication methods without code changes, with OAuth tokens taking precedence when available.

### What is the difference between `streamAnthropic` and `streamSimpleAnthropic`?

Both functions are exported from [`packages/ai/src/index.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/index.ts) and reside in the core provider implementation. `streamSimpleAnthropic()` returns an async iterator of raw text strings for basic use cases, while `streamAnthropic()` yields full `AssistantMessage` objects containing metadata, tool calls, and thinking blocks required for complex interactions.

### Can I use a custom Anthropic-compatible API endpoint?

Yes. The SDK supports runtime provider registration via `registerProvider()`, allowing you to specify a custom `baseUrl` for proxies like Cloudflare AI Gateway or self-hosted Claude instances. The [`packages/coding-agent/examples/extensions/custom-provider-anthropic/index.ts`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/examples/extensions/custom-provider-anthropic/index.ts) file demonstrates implementing the streaming interface with custom endpoints while reusing Pi's normalization logic.

### Where does Pi store OAuth tokens after running `pi login anthropic`?

The CLI stores refresh tokens in `~/.pi/agent/settings.json` under the `apiKeys.anthropic` path. The OAuth helper in [`packages/ai/src/utils/oauth/anthropic.ts`](https://github.com/earendil-works/pi/blob/main/packages/ai/src/utils/oauth/anthropic.ts) manages token refresh automatically, ensuring long-running sessions remain authenticated without manual intervention.