Pify

Quickstart: Build your first Pi agent

Create a small TypeScript program that streams a model response through the current Pi AI API.

This guide targets the official Pi 0.85.0 release and creates a small TypeScript program that streams a model response. You will install @earendil-works/pi-ai, register the built-in providers, resolve one model, and consume its event stream. No prior Pi knowledge is required.

What you will have at the end

A TypeScript file that calls one model through the Models.streamSimple() interface. You can then add tools, event handling, session persistence, and an agent loop.

Before you start

You need:

  • Node.js 22.19 or later - check with node --version
  • An API key for one provider - Anthropic, OpenAI, Google, or any local proxy that speaks the OpenAI Chat Completions protocol. Anthropic is used in the snippets below.
  • A terminal in an empty folder

Cost and safety

This guide makes real API calls. Set a low spending limit on your provider account, and never commit the API key.

1. Initialize the project

mkdir pi-quickstart && cd pi-quickstart
npm init -y
npm pkg set type=module
npm install @earendil-works/pi-ai@0.85.0
npm install --save-dev tsx

This gives you:

  • a package.json configured for ECMAScript modules
  • @earendil-works/pi-ai and the tsx TypeScript loader in node_modules

2. Add your API key

Create a file called .env in the same folder:

.env
ANTHROPIC_API_KEY=sk-ant-...

Why a .env file and not a hardcoded string

The key is read by the SDK at runtime. Keeping it in .env means you can .gitignore the file and never leak the key to source control.

Add .env to .gitignore:

.gitignore
node_modules
.env

3. Write the agent

Create agent.ts:

agent.ts
import { builtinModels } from "@earendil-works/pi-ai/providers/all";

const models = builtinModels();
const model = models.getModel("anthropic", "claude-sonnet-4-5");
if (!model) throw new Error("Model not found");

const stream = models.streamSimple(model, {
  systemPrompt: "You are a concise assistant. Reply in one sentence.",
  messages: [
    {
      role: "user",
      content: "What is the capital of France?",
      timestamp: Date.now(),
    },
  ],
});

for await (const event of stream) {
  if (event.type === "text_delta") {
    process.stdout.write(event.delta);
  } else if (event.type === "done") {
    console.log("\n[done] reason:", event.reason);
  }
}

Four steps happen in this file:

  1. builtinModels() creates a Models collection with the built-in providers registered.
  2. models.getModel("anthropic", "claude-sonnet-4-5") resolves a model descriptor from that collection.
  3. models.streamSimple(model, context) opens a streaming request and returns an async iterable of events.
  4. The for await loop consumes events until the stream finishes. text_delta carries text fragments; done is the terminal event.

4. Load the key and run

The provider reads ANTHROPIC_API_KEY from the process environment. Node can load the .env file directly:

node --env-file=.env --import tsx agent.ts

Or use a script

Add a script to package.json if you want a shorter command:

package.json
{
  "scripts": {
    "start": "node --env-file=.env --import tsx agent.ts"
  }
}

Then run npm start.

You should see something like:

The capital of France is Paris.
[done] reason: stop

If you see that, you have a working Pi agent.

5. Try one variation

Change the user message and run it again:

agent.ts
const stream = models.streamSimple(model, {
  systemPrompt: "You are a concise assistant. Reply in one sentence.",
  messages: [
    {
      role: "user",
      content: "Name three Pi SDK packages.",
      timestamp: Date.now(),
    },
  ],
});

The {6} metadata asks the Fumadocs code renderer to highlight line 6.

Where to go next

You now have a working Models.streamSimple() call. Continue with the topic that matches your goal:

GoalRead
Understand the full agent loop, not just one model callChapter 3: Agent Loop
Add a tool the model can callHow to add a custom tool
Plug in a model provider the SDK does not ship withHow to plug in a new model
Persist the conversation across runsHow to persist sessions

Troubleshooting

Error: ANTHROPIC_API_KEY is not set

The SDK did not find the key. Confirm .env exists in the current directory and that you launched Node with --env-file=.env.

Error: model not found

models.getModel() could not resolve the descriptor. Check both the provider ID and model ID. See Reference: Configuration.

SyntaxError: Cannot use import statement outside a module

Your package.json is missing "type": "module". Run npm pkg set type=module and try again.

On this page