pi is built for an agent that runs in one process: a terminal coding agent, a bot, or a script. TanStack AI does that too, and it also lets you split the agent across a client and a server. Pick pi if you want pi's coding agent CLI or its subscription logins. Pick TanStack AI for everything else, and for any app with a browser in it.
Both are open-source TypeScript toolkits under the MIT license. Both stream model output, call tools, run an agent loop, and talk to many providers. The difference is where the agent can run.
| pi | TanStack AI | |
|---|---|---|
| In one process | Yes. agentLoop() runs next to the code that reads its events (agent.subscribe) | Yes. chat() returns an async stream you read in the same process. A harness keeps a session open across turns |
| In a terminal | pi-tui, or pi-coding-agent | runCli from @tanstack/ai-harness-cli: line mode, print mode for scripts and CI, NDJSON, and ACP for editors |
| Split across client and server | Not built in. pi-protocol and RPC mode can send events to another process. streamProxy keeps the loop in the browser and sends only the model call through your server | Built in. The loop and the server tools run on the server. The browser gets AG-UI events over HTTP and renders them with useChat |
| With a browser UI | Your own code | useChat for React, Solid, Vue, Svelte, Preact, Angular and more, with approvals, reconnects and saved history |
So pi gives you an agent to embed in one process. TanStack AI gives you the same agent, plus a client and a server that talk to each other when you need them.
TanStack AI also has these, each in its own package:
| pi | TanStack AI |
|---|---|
| @earendil-works/pi-ai | @tanstack/ai and one adapter package per provider |
| createModels(), setProvider(anthropicProvider()), models.getModel('anthropic', id) | anthropicText(id) from @tanstack/ai-anthropic |
| models.streamSimple(model, context) | chat({ adapter, messages }) |
| models.completeSimple(model, context) | chat({ adapter, messages, stream: false }) |
| systemPrompt in the context | systemPrompts: ['...'] |
| AgentTool with TypeBox parameters and execute | toolDefinition({ inputSchema }).server(fn) |
| agentLoop() or the Agent class | chat({ tools }), which runs the loop |
| beforeToolCall / afterToolCall | middleware: [...] with tool call hooks |
| agent.followUp(message) | The message queue of useChat |
| agent.subscribe() and AgentEvent | The AG-UI events of chat(), read by useChat on the client |
| streamProxy() in the browser | toServerSentEventsResponse on the server, useChat on the client |
| @earendil-works/pi-mcp | @tanstack/ai-mcp. See MCP. |
| @earendil-works/pi-codemode | @tanstack/ai-code-mode. See Code Mode. |
Versions: pi 1.4 and TanStack AI 1.0.
| Feature | pi | TanStack AI |
|---|---|---|
| License | MIT | MIT |
| Main use | An agent in one process: coding agent CLI, and the libraries under it | Agents in one process, in a terminal, or split across client and server |
| Wire protocol | In-process AgentEvent objects. Remote sessions over CBOR (pi-protocol) | Native AG-UI, in both directions |
| Providers | About 35 in pi-ai, plus any OpenAI-compatible API | OpenAI, Anthropic, Gemini, Vertex, Bedrock, Grok, Groq, Mistral, OpenRouter, and more. Any OpenAI-compatible endpoint |
| Subscription logins | OAuth for Claude Pro and Max, ChatGPT, GitHub Copilot, OpenRouter (Node only) | API keys |
| UI | pi-tui for the terminal | Terminal (runCli), plus React, Solid, Vue, Svelte, Preact, Angular, Octane, Remix, React Native |
| Tools | AgentTool with a TypeBox schema, run in the agent | One toolDefinition(), with .server() and .client() |
| Tool approval | beforeToolCall can block a call | Per-tool needsApproval, with batched approvals and interrupts |
| Steering and follow-up | Built-in queues on the Agent | A message queue in useChat. The harness also steers a running turn (experimental) |
| Subagents | Task-owned child conversations in pi-durable (experimental) | Built in, with a card per child run |
| Structured output | Constrained sampling for tool arguments | Typed message part, streamed with tools and kept in the history |
| Token usage | Usage and cost on each assistant message | Usage on each model call, and cost when the provider reports it |
| Persistence | JSONL session files with branching. pi-durable is experimental | withPersistence middleware, server or browser stores |
| Resumable streams | pi-durable resumes a turn after a crash (experimental) | Built in. useChat reconnects by itself |
| MCP client | pi-mcp: stdio and Streamable HTTP | @tanstack/ai-mcp: multi-server pools, generated types, lazy tools, managed lifecycle |
| Code Mode | pi-codemode: QuickJS on Node, Bun and Cloudflare | 6 isolate drivers: Node, QuickJS WASM, QuickJS Bun, Cloudflare, Daytona, E2B |
| Coding agents | pi-coding-agent, a CLI with extensions, skills and themes | Claude Code, Codex, OpenCode, Grok Build, and any ACP agent, on a local process or a sandbox |
| Image | Image generation through OpenRouter | Stable, typed per model |
| Video, speech, music | Not built in | Stable |
| Realtime voice | Not built in | Stable: OpenAI, Gemini, Grok, ElevenLabs |
To try TanStack AI, start with the Quick Start.