---
slug: "pi-vault-pi-tools"
source_type: "readme"
source_url: "https://cdn.jsdelivr.net/gh/pi-vault/pi-tools@master/README.md"
repo: "https://github.com/pi-vault/pi-tools"
source_file: "README.md"
branch: "master"
---
# @pi-vault/pi-tools

[![npm version](https://img.shields.io/npm/v/%40pi-vault%2Fpi-tools)](https://www.npmjs.com/package/@pi-vault/pi-tools)
[![Quality](https://github.com/pi-vault/pi-tools/actions/workflows/quality.yml/badge.svg?branch=master)](https://github.com/pi-vault/pi-tools/actions/workflows/quality.yml)
[![Node >= 24.15.0](https://img.shields.io/badge/node-%3E%3D24.15.0-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
[![License: MIT](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)

Web search, content extraction, documentation lookup, and deep research tools for [Pi](https://github.com/earendil-works/pi).

## What's new in 0.5.0

> **Dashboard replaces typed `/tools` subcommands.** Run `/tools` to open the interactive dashboard with three tabs: **Providers** (toggle, key, default, run tests), **Status** (budgets, session outcomes, latency), and **Activity** (recent provider events). Typed subcommands such as `/tools status`, `/tools enable`, `/tools key`, `/tools test`, `/tools default`, and `/tools monitor on|off` are no longer supported.
>
> **Provider budgets are enforceable.** Hard, managed, unlimited, and shared-pool policies replace the old `monthlyQuota` settings. Budget status is reported per provider in the Status tab.
>
> **`openai-codex` requires Pi OAuth.** The `OPENAI_API_KEY` fallback is gone. Run `/login` and select `openai-codex` before using it. To search with `OPENAI_API_KEY` instead, configure `openai-web-search`.
>
> **Usage persistence moved.** Provider usage now lives at `$PI_CODING_AGENT_DIR/cache/pi-tools/usage.json` using a version 2 UTC-period ledger.

## Install

```bash
pi install npm:@pi-vault/pi-tools
```

Reload Pi after installation:

```text
/reload
```

The extension can use keyless providers such as Jina. DuckDuckGo also works without an API key after you install the `ddgs` CLI:

```bash
uv tool install ddgs
# or: pip install ddgs
```

Run `/tools` in Pi to open the dashboard and configure more providers. The dashboard detects available environment variables and can write the global config for you.

```text
/tools
```

## Use it

Ask Pi in plain language. The extension registers up to seven tools, depending on which providers you configure:

| Tool              | Use it for                                                          |
| ----------------- | ------------------------------------------------------------------- |
| `web_search`      | Current information, releases, and live web results                 |
| `web_fetch`       | Web pages, PDFs, GitHub URLs, YouTube videos, and local video files |
| `web_read`        | Full text from a large response using its `contentId`               |
| `code_search`     | Programming examples and technical documentation through Exa        |
| `web_docs_search` | Finding a Context7 library ID                                       |
| `web_docs_fetch`  | Focused, version-aware Context7 documentation                       |
| `web_research`    | Multi-source Exa research and saved findings reports                |

### Search the web

```text
Search the web for the latest Vitest mocking documentation.
Search npm release notes after 2026-01-01, using only npmjs.com.
Search for current SQLite performance guidance and combine multiple providers.
```

`web_search` supports provider selection, domain filters, publication dates, compact results, and optional multi-provider fusion. If a provider fails, Pi Tools tries the next eligible provider unless the request was cancelled.

### Fetch pages and files

```text
Fetch https://example.com/spec and summarize the requirements.
Fetch these URLs and compare them: https://a.dev/docs, https://b.dev/docs
Fetch https://example.com/page in raw mode.
```

`web_fetch` accepts one URL or up to 20 URLs. It extracts readable HTML, PDFs, GitHub repositories and files, and some Next.js RSC pages. It can fall back to Jina, Gemini, or a configured fetch provider when direct extraction is not enough.

Large responses include a `contentId`. Ask Pi to pass that ID to `web_read` for the full text. Stored content lasts for the current session.

### Work with YouTube, video, and PDFs

```text
Fetch https://www.youtube.com/watch?v=VIDEO_ID and summarize the transcript.
Extract 4 frames from https://www.youtube.com/watch?v=VIDEO_ID between 02:00 and 03:00.
Analyze /absolute/path/to/demo.mp4 and list the main steps shown.
Fetch https://example.com/scanned-report.pdf and summarize it.
```

YouTube transcript extraction can use Gemini or Perplexity. Frame extraction uses `yt-dlp` and `ffmpeg`. Local video analysis uses Gemini. Scanned PDF OCR uses `pdftoppm` and either the active model's image support or Gemini as a fallback.

### Look up code and library documentation

```text
Find TypeScript examples for AbortSignal timeout handling.
Find the React library in Context7 for hooks documentation.
Fetch Context7 docs for /facebook/react about useState hooks.
```

Use `web_docs_search` before `web_docs_fetch`. Include a focused question, and pin a version in the library ID when reproducibility matters, such as `/vercel/next.js@v15.1.8`.

### Run deep research

```text
Research the trade-offs between PostgreSQL logical replication and CDC. Save a findings report to docs/replication.md.
```

`web_research` supports `lite`, `standard`, and `full` modes. It requires `EXA_API_KEY`. Pass `outputPath` to save a report and `rawOutputPath` to keep the source metadata.

## Manage providers

Run `/tools` to open the interactive dashboard. The dashboard has three tabs:

- **Providers** — toggle a provider on or off, set a credential, change the default provider, and run a test in place.
- **Status** — per-provider budget state, session outcomes (success/failure), and average latency.
- **Activity** — recent provider events streamed live.

Switch between **global** and **project** scope inside the dashboard. Project scope requires the project to be trusted or to already have a `.pi/tools.json`.

Provider configuration refreshes automatically every 30 seconds. The dashboard's reload action triggers an immediate refresh.

### Available providers

| Provider          | Capabilities                  | Setup                              |
| ----------------- | ----------------------------- | ---------------------------------- |
| Brave             | Search                        | `BRAVE_API_KEY`                    |
| Brave LLM         | Search                        | `BRAVE_API_KEY`                    |
| Context7          | Docs                          | `CONTEXT7_API_KEY`                 |
| DuckDuckGo        | Search                        | `ddgs` CLI                         |
| Exa               | Search, fetch, code, research | `EXA_API_KEY`                      |
| fastCRW           | Search                        | `FASTCRW_API_KEY`                  |
| Firecrawl         | Search, fetch                 | API key optional                   |
| Jina              | Search, fetch                 | API key optional                   |
| LangSearch        | Search                        | `LANGSEARCH_API_KEY`               |
| Linkup            | Search                        | `LINKUP_API_KEY`                   |
| Marginalia        | Search                        | No API key                         |
| Ollama            | Search, fetch                 | Local Ollama server                |
| OpenAI Codex      | Search                        | Pi `/login` OAuth                  |
| OpenAI web search | Search                        | `OPENAI_API_KEY`                   |
| Parallel          | Search, fetch                 | `PARALLEL_API_KEY`                 |
| Perplexity        | Search, YouTube fallback      | `PERPLEXITY_API_KEY`               |
| SearXNG           | Search                        | SearXNG instance, API key optional |
| Serper            | Search                        | `SERPER_API_KEY`                   |
| Sofya             | Search, fetch                 | `SOFYA_API_KEY`                    |
| Tavily            | Search, fetch                 | `TAVILY_API_KEY`                   |
| WebSearchAPI      | Search                        | `WEBSEARCHAPI_API_KEY`             |
| You.com           | Search                        | `YOUCOM_API_KEY`                   |

Pi Tools ranks providers by tier and availability, and optionally by recent session performance. Automatic selection skips exhausted hard budgets. Provider-specific date and domain filters depend on the upstream API; unsupported filters are applied locally where possible.

`openai-codex` uses the active Pi OAuth session. Run `/login` and select `openai-codex` before using it; the provider no longer accepts `OPENAI_API_KEY` as a fallback. To search with `OPENAI_API_KEY` instead, configure `openai-web-search`.

## Configure files and credentials

The global config is `$PI_CODING_AGENT_DIR/extensions/tools.json`; when the variable is unset, Pi supplies its agent directory. A project `.pi/tools.json` overrides it. Pi Tools deep-merges project settings, global settings, and built-in defaults in that order.

### Minimal config

A starter configuration with one keyed search provider and a few keyless defaults:

```json
{
  "defaultProvider": "auto",
  "providers": {
    "exa": {
      "enabled": true,
      "apiKey": "EXA_API_KEY"
    },
    "duckduckgo": { "enabled": true },
    "firecrawl": { "enabled": true },
    "jina": { "enabled": true },
    "marginalia": { "enabled": true },
    "openai-codex": { "enabled": true }
  }
}
```

A provider `apiKey` can be:

- an environment-variable name, such as `"EXA_API_KEY"`
- a literal key
- a shell command prefixed with `!`, such as `"!op read op://pi/exa/api-key"`

Shell-command credentials are cached until the next config refresh. Sensitive fields in project config are ignored until Pi marks the project as trusted.

### Full configuration reference

The complete shape of the merged configuration. Every field shown here is honored by the extension; omit any section to use the built-in default.

```json
{
  "defaultProvider": "auto",
  "selectionStrategy": "auto",
  "providers": {
    "brave": {
      "enabled": false,
      "apiKey": "BRAVE_API_KEY"
    },
    "brave-llm": {
      "enabled": false,
      "apiKey": "BRAVE_API_KEY",
      "tokenBudget": 4096
    },
    "context7": {
      "enabled": false,
      "apiKey": "CONTEXT7_API_KEY"
    },
    "duckduckgo": {
      "enabled": true,
      "ddgsBackend": "api",
      "ddgsRegion": "us-en"
    },
    "exa": {
      "enabled": false,
      "apiKey": "EXA_API_KEY"
    },
    "fastcrw": {
      "enabled": false,
      "apiKey": "FASTCRW_API_KEY",
      "baseUrl": "https://api.fastcrw.com"
    },
    "firecrawl": {
      "enabled": true
    },
    "jina": {
      "enabled": true
    },
    "langsearch": {
      "enabled": false,
      "apiKey": "LANGSEARCH_API_KEY"
    },
    "linkup": {
      "enabled": false,
      "apiKey": "LINKUP_API_KEY",
      "depth": "standard"
    },
    "marginalia": {
      "enabled": true
    },
    "ollama": {
      "enabled": false,
      "baseUrl": "http://localhost:11434"
    },
    "openai-codex": {
      "enabled": true
    },
    "openai-web-search": {
      "enabled": false,
      "apiKey": "OPENAI_API_KEY",
      "model": "gpt-4.1-mini"
    },
    "parallel": {
      "enabled": false,
      "apiKey": "PARALLEL_API_KEY"
    },
    "perplexity": {
      "enabled": false,
      "apiKey": "PERPLEXITY_API_KEY",
      "model": "sonar"
    },
    "searxng": {
      "enabled": false,
      "instanceUrl": "http://localhost:8080"
    },
    "serper": {
      "enabled": false,
      "apiKey": "SERPER_API_KEY"
    },
    "sofya": {
      "enabled": false,
      "apiKey": "SOFYA_API_KEY",
      "searchDepth": "basic",
      "topic": "general"
    },
    "tavily": {
      "enabled": false,
      "apiKey": "TAVILY_API_KEY"
    },
    "websearchapi": {
      "enabled": false,
      "apiKey": "WEBSEARCHAPI_API_KEY"
    },
    "youcom": {
      "enabled": false,
      "apiKey": "YOUCOM_API_KEY"
    }
  },
  "github": {
    "enabled": true,
    "maxRepoSizeMB": 350,
    "cloneTimeoutSeconds": 30
  },
  "combine": {
    "enabled": false,
    "mode": "targeted",
    "targetBackends": 3,
    "k": 60
  },
  "gemini": {
    "apiKey": "GEMINI_API_KEY",
    "baseUrl": "https://generativelanguage.googleapis.com",
    "cloudflareApiKey": "CLOUDFLARE_API_KEY",
    "allowBrowserCookies": false,
    "chromeProfile": "Default"
  },
  "youtube": {
    "enabled": true,
    "preferredModel": "gemini-3-flash-preview"
  },
  "video": {
    "enabled": true,
    "preferredModel": "gemini-3-flash-preview",
    "maxSizeMB": 50
  },
  "pdf": {
    "ocrEnabled": true,
    "ocrMaxPages": 5,
    "ocrDpi": 150
  },
  "deepResearch": {
    "enabled": true,
    "modeDefaults": {
      "lite": {
        "type": "deep-lite",
        "numResults": 15,
        "textMaxCharacters": 10000,
        "timeoutSeconds": 300,
        "highlightsMaxCharacters": 600,
        "highlightNumSentences": 3,
        "highlightsPerUrl": 1
      },
      "standard": {
        "type": "deep-reasoning",
        "numResults": 50,
        "textMaxCharacters": 16000,
        "timeoutSeconds": 600,
        "highlightsMaxCharacters": 900,
        "highlightNumSentences": 4,
        "highlightsPerUrl": 2
      },
      "full": {
        "type": "deep-reasoning",
        "numResults": 100,
        "textMaxCharacters": 24000,
        "timeoutSeconds": 1800,
        "highlightsMaxCharacters": 1200,
        "highlightNumSentences": 5,
        "highlightsPerUrl": 3
      }
    },
    "outputSchema": null,
    "guidance": {}
  },
  "guidance": {
    "web_search": {},
    "web_fetch": {},
    "web_read": {},
    "code_search": {},
    "web_docs_search": {},
    "web_docs_fetch": {}
  },
  "ssrf": {
    "allowRanges": []
  }
}
```

### Provider budgets

Every built-in provider has a default `budget`. Omit it to keep that default, or replace the complete object for one provider:

```json
{
  "providers": {
    "exa": {
      "budget": {
        "mode": "hard",
        "limit": 10,
        "period": "month",
        "unit": "usd",
        "pool": "exa"
      }
    },
    "jina": { "budget": { "mode": "managed" } },
    "duckduckgo": { "budget": { "mode": "unlimited" } }
  }
}
```

Hard budgets accept `day`, `month`, or `lifetime` periods and `request`, `credit`, or `usd` units. Day and month boundaries use UTC calendar time. A `pool` shares one counter across providers; every provider in that pool must use the same limit, period, and unit. Invalid or conflicting overrides are ignored as a group.

`managed` delegates limits to the provider or plan. `unlimited` means Pi Tools does not meter the provider. Local reservations are saved before requests to `$PI_CODING_AGENT_DIR/cache/pi-tools/usage.json`. Version 2 keeps compatible current-month legacy request counts for non-shared monthly budgets; `monthlyQuota` settings are not migrated.

Enforcement is atomic within one Pi process. Separate concurrent Pi processes can briefly exceed the same local ceiling; interprocess locking is intentionally deferred until that becomes an observed need.

Useful advanced settings:

- `selectionStrategy`: `auto` or `best-performing`
- `combine`: optional reciprocal-rank fusion across eligible providers
- `github`: GitHub repository size and clone timeout limits
- `gemini`: API key, custom base URL, Cloudflare AI Gateway key, and browser-cookie access
- `youtube` and `video`: enablement, preferred Gemini model, and local video size limit
- `pdf`: OCR enablement, page limit, and rasterization DPI
- `deepResearch`: mode defaults, structured output schema, and report guidance
- `guidance`: prompt overrides for individual tools
- `ssrf.allowRanges`: explicit CIDR exceptions for trusted private networks

To use Gemini browser cookies, set `PI_ALLOW_BROWSER_COOKIES=1` or enable `gemini.allowBrowserCookies` in the global config. Project config cannot enable sensitive cookie or network access unless the project is trusted.

### Optional command-line tools

| Tool                    | Enables                                                 |
| ----------------------- | ------------------------------------------------------- |
| `ddgs`                  | Keyless DuckDuckGo search                               |
| `gh`                    | Richer GitHub repository access when Pi chooses the CLI |
| `yt-dlp`                | YouTube stream lookup and frame extraction              |
| `ffmpeg`                | YouTube and local video frame extraction                |
| `pdftoppm` from Poppler | Scanned PDF rasterization for OCR                       |

## Development

```bash
pnpm install
pnpm check
pnpm release:check
```

## Changelog

See [`CHANGELOG.md`](https://github.com/pi-vault/pi-tools/blob/HEAD/CHANGELOG.md) for release notes.

## License

MIT. See [`LICENSE`](https://github.com/pi-vault/pi-tools/tree/HEAD/LICENSE).
