@ferologics/pi-web0.2.0
Web search (Exa, Brave, Claude, Codex, Google) and page fetching tools for Pi
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-web
Web search and page reading for Pi. A single web_search tool covers five providers, and web_fetch reads one page. There is no MCP server, curator UI, cookie access, or provider fallback chain. The model picks the provider, and errors come back as they are.
Tools
| Tool | Behavior |
|---|---|
web_search |
Search with exa (default), brave, claude, codex, or google. Optional numResults, freshness, domains |
web_fetch |
Read a URL as markdown. It fetches the page directly, then falls back to Exa's page cache when EXA_API_KEY is set |
Output over Pi's tool limits (2000 lines or 50KB) is truncated, and the full text is saved to a temp file whose path appears in the result.
Providers
| Provider | Returns | Credentials |
|---|---|---|
exa |
Ranked pages with query-relevant excerpts | EXA_API_KEY |
brave |
Ranked pages with snippets | BRAVE_API_KEY |
claude |
Cited summary from Claude's web search tool | Pi anthropic login (subscription or API key) |
codex |
Cited summary from Codex's web search tool | Pi openai-codex login |
google |
Cited summary from Gemini's Google grounding | npm:pi-antigravity and its antigravity login |
exasearches withtype: "auto"and Dynamic Highlights. When it fails, the error tells the model to retry withbrave.braveuses the plain web search endpoint and addssite:operators fordomains.clauderunsclaude-haiku-5-5with up to 5 searches. Subscription tokens get the same billing identity thatpi-cc-patchgives Pi's own Anthropic requests.codexrunsgpt-6-lunaat low reasoning effort with Codex'sweb_searchtool.googlecalls pi-antigravity's own search function, then resolves Google's opaque grounding redirect links to the real URLs. SetANTIGRAVITY_NO_SEARCH_TOOL=1so pi-antigravity does not also register itsgoogle_searchtool.
Answers from claude, codex, and google are labeled as another model's summary. Their token usage is reported on the tool result, so session totals include it.
Pi Durable
@ferologics/pi-web/durable exposes the same two tools for Pi Durable harnesses, which run outside Pi and cannot load Pi extensions:
import { createWebTools } from "@ferologics/pi-web/durable";
registry.install(
createWebTools({
secret: async (name) => process.env[name], // EXA_API_KEY, BRAVE_API_KEY
credential: async (provider) => (await models.getAuth(provider))?.auth.apiKey, // "anthropic", "openai-codex"
}),
);
It installs a durable extension named pi-web with web_search (exa, brave, claude, codex; google needs pi-antigravity inside Pi's process) and web_fetch. Both are replay-safe, so a harness restarted mid-call runs them again. The host decides where keys come from. pi-web only imports types from @earendil-works/pi-durable (an optional peer dependency), so the Pi extension does not need it.
Install
From npm (standalone package):
pi install npm:@ferologics/pi-web
From git:
pi install git:github.com/ferologics/pi-web
Or use the bundled package:
pi install npm:@ferologics/pi-extensions
# or
pi install npm:pi-shit
Setup
Expose the API keys to Pi:
EXA_API_KEY=...
BRAVE_API_KEY=...
In the dotfiles setup, store each key in 1Password, add only its op://... reference to ~/.pi/agent/env.op, run pi-secrets-refresh, and restart Pi.
The claude, codex, and google providers reuse Pi's logins (/login anthropic, /login openai-codex, /login antigravity).
Maintenance
These constants follow upstream releases and need updating when a provider rejects them:
CLAUDE_SEARCH_MODELandCLAUDE_CODE_VERSIONinclaude.ts. Keep the version in step withpi-cc-patch.CODEX_SEARCH_MODELincodex.ts.DYNAMIC_HIGHLIGHTS_BETAinexa.ts, until Exa drops the beta header.- The pi-antigravity module path in
index.ts(src/search/index.tsinside the installed package).
Privacy
- Search queries go to the selected provider.
web_fetchrequests the page from this machine. When that fails, the URL is sent to Exa.- Returned page text becomes part of the Pi conversation and is sent to the active model provider.