Second half of the purge (the first covered the persona, AGENTS.md, README.md, and the distillation of the per-host pages). Every remaining identifier is gone: hostname, both LAN addresses, and the Wi-Fi SSID. 34 count-checked substitutions across 22 files — indexes, tool/research pages, the inventory census, the changelog, one generated HTML report, and five managed skills. Facts kept, names dropped: a history entry keeps its four-page listing as a nameless summary, the syslog excerpts keep every timestamp and line, and the census keeps the .zcompdump rows (the zsh version stamps are the useful part, the hostname was not). Deliberately unchanged: install.sh's --host case list and the packages/<hostname>.pkgs filename, where the hostname is the lookup key. Left out of scope by Frank's call: agent/memories/** — past-session records the learn pipeline rewrites. kb-lint: 0 violations. Residual grep for the hostname, its two IPs, and the SSID across omp-docs/ and agent/managed-skills/: no hits.
142 lines
4.6 KiB
Markdown
142 lines
4.6 KiB
Markdown
---
|
|
type: reference
|
|
title: Pi Web Access
|
|
description: Web search, URL fetching, GitHub cloning, PDF extraction, and video understanding for Pi. Zero-config with Exa MCP.
|
|
tags:
|
|
- pi
|
|
- package
|
|
- web-search
|
|
- fetch
|
|
- youtube
|
|
- unverified
|
|
timestamp: 2026-08-28
|
|
---
|
|
|
|
# Pi Web Access
|
|
|
|
**Package:** `pi-web-access`
|
|
**Version:** 0.22.0
|
|
**Author:** Nico Bailon
|
|
|
|
Web search, content extraction, and video understanding for Pi. It calls your self-hosted SearXNG first when one is configured, and falls through to other providers.
|
|
|
|
> **Pi-era setup:** `~/.pi/web-search.json` locked search to SearXNG at `http://192.168.0.143:8081` (dankclaw), permitted LAN fetches via `ssrf.allowRanges`, and set `maxInlineContentChars` to 50000. The config file is cached in memory per process — a changed file takes effect on the next Pi session.
|
|
|
|
---
|
|
|
|
## Install
|
|
|
|
```bash
|
|
pi install npm:pi-web-access
|
|
```
|
|
|
|
## Search Providers
|
|
|
|
Provider chain (in priority order, v0.22):
|
|
|
|
1. **SearXNG** (if configured) — Self-hosted, private search
|
|
2. **OpenAI** — Codex subscription or API key
|
|
3. **Exa** — Zero-config via MCP, or API key
|
|
4. **Brave** — API key
|
|
5. **Parallel** — API key
|
|
6. **TinyFish** — API key
|
|
7. **Search1API** — API key
|
|
8. **Searchinfinity** — API key
|
|
9. **Querit** — API key
|
|
10. **Tavily** — API key
|
|
11. **Jina** — API key
|
|
12. **SERPdive** — API key
|
|
13. **Kagi** — API key
|
|
14. **Bocha** — API key
|
|
15. **Ollama** — API key
|
|
16. **Perplexity** — API key
|
|
17. **Gemini API** — API key
|
|
18. **Gemini Web** — Browser-cookie access
|
|
|
|
A single-provider field (`provider` or `searchProvider`) pins the default and takes precedence over `searchRouting`. `searchRouting.providers` plus `fallbackOn` define an explicit ordered fallback over typed failures (`transient`, `quota`, `network`, `invalid-response`).
|
|
|
|
## Configuration
|
|
|
|
**Location:** `~/.pi/web-search.json`
|
|
|
|
```json
|
|
{
|
|
"searxngBaseUrl": "http://192.168.0.143:8081",
|
|
"searchProvider": "searxng",
|
|
"maxInlineContentChars": 50000,
|
|
"workflow": "none",
|
|
"ssrf": {
|
|
"allowRanges": ["192.168.0.0/24"]
|
|
},
|
|
"openaiApiKey": "sk-...",
|
|
"braveApiKey": "BSA_...",
|
|
"exaApiKey": "exa-...",
|
|
"perplexityApiKey": "pplx-...",
|
|
"geminiApiKey": "AIza..."
|
|
}
|
|
```
|
|
|
|
Key fields:
|
|
|
|
- `searxngBaseUrl` — the SearXNG instance to call. Env `SEARXNG_BASE_URL` wins over this file. The client calls `GET {base}/search?q=...&format=json` with a 30 s timeout; the base URL and its redirects stay subject to the SSRF guard.
|
|
- `searchProvider` — `searxng` locks the primary provider. `auto` picks the first available. A single-provider field wins over `searchRouting`.
|
|
- `maxInlineContentChars` — size of each `fetch_content` / `get_search_content` content slice. Default 30000, cap 200000. Full fetched content stays stored for later retrieval.
|
|
- `ssrf.allowRanges` — LAN CIDR ranges allowed through `fetch_content`. This blocks private IPs by default.
|
|
- `workflow` — `none` (raw results, no browser), `summary-review` (curator window with summary draft), or `auto-summary`.
|
|
|
|
## Capabilities
|
|
|
|
### Web Search
|
|
|
|
```typescript
|
|
web_search({ query: "TypeScript best practices 2025" })
|
|
```
|
|
|
|
### URL Fetching
|
|
|
|
```typescript
|
|
fetch_content({ url: "https://docs.example.com/guide" })
|
|
```
|
|
|
|
### GitHub Cloning
|
|
|
|
GitHub URLs are cloned locally. The agent gets real file contents, not rendered HTML.
|
|
|
|
```typescript
|
|
fetch_content({ url: "https://github.com/owner/repo" })
|
|
```
|
|
|
|
### Video Understanding
|
|
|
|
Point at a YouTube video or local screen recording and ask questions about visual content.
|
|
|
|
```typescript
|
|
// YouTube
|
|
fetch_content({ url: "https://youtube.com/watch?v=...", prompt: "What book is shown?" })
|
|
|
|
// Local video
|
|
fetch_content({ url: "/path/to/recording.mp4" })
|
|
```
|
|
|
|
### PDF Extraction
|
|
|
|
```typescript
|
|
fetch_content({ url: "https://example.com/paper.pdf" })
|
|
```
|
|
|
|
## Optional Dependencies
|
|
|
|
```bash
|
|
# Video frame extraction
|
|
sudo pacman -S ffmpeg yt-dlp
|
|
```
|
|
|
|
Without these, video analysis (transcripts, visual descriptions via Gemini) still works. Frame extraction requires ffmpeg and yt-dlp. Both are installed on the workstation (verified 2026-08-28: ffmpeg n9.0.1, yt-dlp 2026.08.19).
|
|
|
|
GitHub URLs get special handling: `fetch_content` clones the repo locally instead of scraping HTML (root URL returns tree + README, `/blob/` returns file contents). Repos over 350 MB get an API-based view; `forceClone: true` overrides. Clones cache per session under `/tmp/pi-github-repos` and wipe on session change. Private repos need the `gh` CLI. Disable with `githubClone.enabled: false`.
|
|
|
|
## See Also
|
|
|
|
- [Pi Packages](index.md) — Package overview
|
|
- [Pi Configuration](../index.md) — Pi configuration
|