Why Pi + Tabstack
Wiring web access into a coding agent usually means hand-rolled fetches, HTML parsing, and prompt gymnastics to coax structured data out of messy text. @tabstack/pi-agent replaces that with a hosted API registered as native Pi tools through a Pi extension: schema-enforced output, server-side rendering of JS-heavy pages, and one key for extraction, research, generation, and automation.
Quickstart
Install the adapter and set your key:
npm install @tabstack/pi-agent @earendil-works/pi-coding-agent typebox zod
export TABSTACK_API_KEY="your-key-here"@earendil-works/pi-coding-agent (v0.82 or later), typebox (v1), and zod (v4) are peer dependencies.
A Pi extension is a .ts file with a default export that Pi calls with its extension API. Re-export this package's default extension and Pi registers all five tools:
// tabstack.ts
export { default } from "@tabstack/pi-agent";Then load it with the pi CLI:
pi -e ./tabstack.tsPi also auto-discovers extensions dropped into ~/.pi/agent/extensions/*.ts (global, every project) or .pi/extensions/*.ts (project-local, checked into the repo), with no -e flag needed. The tools resolve TABSTACK_API_KEY lazily on first call, so loading the extension never requires a key.
Registering a subset
You often do not want every tool. A coding agent that should read and research but never drive a browser can register just those two, in the order given:
// tabstack.ts
import { createTabstackPiExtension } from "@tabstack/pi-agent";
// Read-and-research only, no browser automation.
export default createTabstackPiExtension({
tools: ["extract_page_content", "research_question"],
});For full control, register individual tools in a hand-written extension. Every tool is exported as a Pi ToolDefinition, and createTabstackPiTools(config) returns them keyed by name for a custom client:
import { extractPageContentTool, researchQuestionTool } from "@tabstack/pi-agent";
export default function (pi) {
pi.registerTool(extractPageContentTool);
pi.registerTool(researchQuestionTool);
// ...and your own tools alongside them.
}The tools
| Tool name | Label | What it does |
|---|---|---|
extract_structured_data | Extract Structured Data | Pull specific fields from a URL into a JSON shape you define. |
extract_page_content | Extract Page Content | Fetch a page as clean markdown. |
research_question | Research Question | Synthesized answer with cited sources across multiple pages. |
generate_structured_data | Generate Structured Data | Fetch a page, then AI-transform it into derived or reshaped JSON. |
automate_browser_task | Automate Browser Task | Run a multi-step, natural-language browser task. |
The names stay in lockstep with the @tabstack/langchain, @tabstack/openai-agents, @tabstack/eve, and Python langchain-tabstack packages.
Good to know
- Cancellation works. Pi's abort signal is threaded into the Tabstack request, so cancelling a tool call, for example a long
research_questionorautomate_browser_task, aborts the request and stops billing rather than just the agent loop. automate_browser_taskruns non-interactively. It does not pause for human-in-the-loop form input, so it never blocks. It returns the final answer plus the data it extracted and the pages it visited.- Failed calls throw
TabstackToolError, a normalized message plus an HTTPstatusfor API errors. Pi surfaces the failure to the model as a tool result rather than aborting the session. - Requires Zod 4. The adapter uses Zod 4's native
z.toJSONSchemato derive each tool's Typebox parameters.
Common use cases
- Give a coding agent cited research without leaving the terminal.
- Read a page as clean markdown mid-task, with no browser to install.
- Register a read-only subset so the agent can research but never act.
- Check the extension into
.pi/extensions/so the whole team gets the tools.