Skip to content
Get started
Integrations

Tabstack for the Pi coding agent

Give the Pi coding agent reliable web access with @tabstack/pi-agent: schema-enforced extraction, research, generation, and browser automation registered as native Pi tools.

@tabstack/pi-agent gives the Pi coding agent reliable web access: schema-enforced extraction, multi-source research, AI transformation, and browser automation, all registered as native Pi tools through a Pi extension, backed by the official @tabstack/sdk.

A Pi extension is a .ts file whose default export Pi calls with its extension API. This package ships that default export, so wiring Tabstack into Pi is a one-line file.

Terminal window
npm install @tabstack/pi-agent @earendil-works/pi-coding-agent typebox zod

@earendil-works/pi-coding-agent (v0.82 or later), typebox (v1), and zod are peer dependencies, and all three are runtime dependencies of the adapter, not typecheck-only: it calls Pi’s defineTool, builds each tool’s parameters with Typebox’s Type.Unsafe, and validates tool input with Zod.

Keep the installed @earendil-works/pi-coding-agent in step with the pi you actually run. A copy installed next to the adapter takes precedence for the adapter’s own imports, so a stale one means the tool objects handed to registerTool were built by an older defineTool than the Pi loading them. Pi’s loader does alias @earendil-works/pi-coding-agent and typebox to its own copies, but that applies to imports written directly in your extension file, and otherwise only as a fallback when neither is installed alongside the adapter. zod is never aliased: it always resolves from your project, so it is genuinely shared with your own code.

A live Pi session also needs the pi CLI installed and a model provider key configured in Pi (for example ANTHROPIC_API_KEY or OPENAI_API_KEY, per your Pi model config), alongside your Tabstack key.

Create and Setup Your API Key

Before you can start using Tabstack API, you’ll need to create an API key and set it up in your environment.

1. Create Your API Key

  1. Visit the Tabstack Console
  2. Sign in to your account (or create one if you haven’t already)
  3. Navigate to the API Keys section and click the “Manage API Keys”
  4. Once you are on the API Keys page, Click “Create New API Key”
  5. Give your key a descriptive name (e.g., “Development”, “Production”) and click the “Create API Key”
  6. Copy the generated API key and store it securely

2. Set Up Environment Variable

For security and convenience, we recommend storing your API key as an environment variable rather than hardcoding it in your scripts.

macOS/Linux
Terminal window
# Add to your shell profile (~/.bashrc, ~/.zshrc, or ~/.bash_profile)
export TABSTACK_API_KEY="your_api_key_here"
# Or set it temporarily for the current session
export TABSTACK_API_KEY="your_api_key_here"
# Reload your shell or run:
source ~/.bashrc # or ~/.zshrc
Windows (Command Prompt)
# Set temporarily for current session
set TABSTACK_API_KEY=your_api_key_here
# Set permanently (requires restart)
setx TABSTACK_API_KEY "your_api_key_here"
Windows (PowerShell)
# Set temporarily for current session
$env:TABSTACK_API_KEY = "your_api_key_here"
# Set permanently for current user
[Environment]::SetEnvironmentVariable("TABSTACK_API_KEY", "your_api_key_here", "User")

3. Verify Your Setup

Test that your environment variable is set correctly:

macOS/Linux/Windows (Git Bash):

Terminal window
echo $TABSTACK_API_KEY

Windows (Command Prompt):

Terminal window
echo %TABSTACK_API_KEY%

Windows (PowerShell):

Terminal window
echo $env:TABSTACK_API_KEY

You should see your API key printed in the terminal.

Re-export the package’s default extension from a file, and Pi registers all five Tabstack tools:

tabstack.ts
export { default } from "@tabstack/pi-agent";

Load it with the pi CLI:

Terminal window
pi -e ./tabstack.ts

Then ask Pi something that needs the web (“Read https://tabstack.ai and summarize what it does”) and it picks the tool itself.

The tools resolve TABSTACK_API_KEY lazily on first call, so loading the extension never requires a key to be set.

Pi also auto-discovers extensions in two locations, but each has a condition worth knowing before you move the file there:

  • .pi/extensions/*.ts (project-local, checked into the repo). It loads only after the project is trusted, so on a fresh clone the Tabstack tools are absent until someone accepts Pi’s trust prompt.
  • ~/.pi/agent/extensions/*.ts (global, applies to every project). Pi resolves an extension’s bare imports from the extension file’s own directory upward, not from the project you installed into, so @tabstack/pi-agent will not resolve here on its own. Give the directory a package.json and run the install there as well:
Terminal window
cd ~/.pi/agent/extensions
npm install @tabstack/pi-agent @earendil-works/pi-coding-agent typebox zod

Without that, Pi reports Failed to load extension. The project-local path avoids it because your project’s node_modules is already in a parent directory.

Tool nameLabel in PiWhat it does
extract_structured_dataExtract Structured DataPull specific fields from a URL into a JSON shape you define.
extract_page_contentExtract Page ContentFetch a page as clean markdown.
research_questionResearch QuestionSynthesize a cited answer across multiple pages.
generate_structured_dataGenerate Structured DataFetch a page, then AI-transform it into derived or reshaped JSON.
automate_browser_taskAutomate Browser TaskRun a multi-step, natural-language browser task.

The model fills these in, but it helps to know the shapes:

  • extract_structured_data: url, json_schema_json (a JSON-encoded JSON Schema string).
  • extract_page_content: url.
  • research_question: query.
  • generate_structured_data: url, instructions, json_schema_json.
  • automate_browser_task: task, plus optional url, guardrails, data, country, max_iterations, max_validation_attempts.

See Schema design for writing json_schema_json that extracts reliably.

The model can pass these for finer control; they are sent to Tabstack only when present.

  • extract_structured_data, extract_page_content, generate_structured_data:
    • effort: "min", "standard", or "max". Use "max" for JS-heavy pages. See Effort levels.
    • nocache: bypass the cache.
    • country: ISO 3166-1 alpha-2 code for geotargeting.
  • research_question: mode ("fast" or "balanced"), nocache.
  • automate_browser_task: guardrails (constraints on what the agent may do), data (context for form filling), country, max_iterations, max_validation_attempts.

A coding agent that should read and research but never drive a browser can register just those tools. Pass tools to pick the subset; they are registered 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 tools yourself in a hand-written extension. Each tool is exported as a Pi ToolDefinition bound to the default client, so it sits alongside your own tools:

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { extractPageContentTool, researchQuestionTool } from "@tabstack/pi-agent";
export default function (pi: ExtensionAPI): void {
pi.registerTool(extractPageContentTool);
pi.registerTool(researchQuestionTool);
// ...and your own tools alongside them.
}

createTabstackPiTools(config) returns the same definitions keyed by tool name, for the same pattern with a custom client.

For a custom API key or base URL, or to reuse one client, build the extension explicitly:

tabstack.ts
import { createTabstackPiExtension } from "@tabstack/pi-agent";
export default createTabstackPiExtension({ apiKey: process.env.MY_KEY });
// or pass an SDK client you already have: createTabstackPiExtension({ client })
// combine with a subset: createTabstackPiExtension({ apiKey, tools: ["research_question"] })

Pi types a tool’s parameters as a Typebox schema. Rather than hand-authoring duplicate Typebox schemas, the adapter converts each tool’s shared schema to JSON Schema with Zod 4’s native z.toJSONSchema and tags it with Type.Unsafe, which Pi sends straight to the provider.

Pi validates the model’s arguments against that schema before it dispatches the call, rejecting a bad one with Validation failed for tool "<tool_name>" and a per-field reason. Type.Unsafe is opaque to TypeScript, not to Pi, so the tool body then re-parses the input to recover its type before the request runs, which doubles as defense in depth.

When a tool call fails it throws TabstackToolError (a normalized message plus an HTTP status for API errors). Pi reports a failed tool by the thrown error, so the failure reaches the model as a tool result rather than aborting the session.

Results come back as text content (markdown for extract_page_content, JSON for the rest), with the raw object also attached as the tool call’s details.