How to Integrate Earendil Pi with the Anthropic API: A Complete Guide
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:
npm i -g @earendil-works/pi
Alternatively, use the pre-built binary for your platform:
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.
API Key Authentication
Set the ANTHROPIC_API_KEY environment variable with your Anthropic API key:
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:
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 that defines supported Claude models with api: "anthropic-messages" identifiers.
List available Anthropic models via the CLI:
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 exposes the pi login anthropic command and the --provider anthropic flag.
Execute a simple prompt:
pi --provider anthropic --model claude-opus-4-6 \
-p "Write a short poem about the moon."
The CLI pipeline performs the following actions:
- Resolves credentials via
getEnvApiKey() - Looks up the model in the registry using
modelRegistry.find("anthropic", "<model-id>") - Applies Anthropic-specific options through
buildBaseOptions()insimple-options.ts - Streams the response to stdout using the provider implementation in
packages/ai/src/providers/anthropic.ts
Using the TypeScript SDK
For programmatic integration, import the streaming functions exported from packages/ai/src/index.ts:
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:
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 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) viapackages/ai/src/env-api-keys.ts. - Provider Architecture: The
anthropic-messagesprovider inpackages/ai/src/providers/anthropic.tshandles streaming SSE events and Claude-specific tool name canonicalization. - Model Registry: Built-in models are defined in
packages/ai/src/model-catalog.tswith 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, 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 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 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 manages token refresh automatically, ensuring long-running sessions remain authenticated without manual intervention.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →