pi-lynx

July 12, 2026 · View on GitHub

npm version License: MIT Pi package Requires lynx

Give Pi agents context-safe plain-text web search, GitHub/Wikipedia search, Reddit search/thread fetch, and page fetch with no API keys. Body text first; links are opt-in and capped.

Capabilities | Install | Quick start | Demo | Tools | Failure modes

Early v1.x. Search uses public HTML search surfaces (DDG Lite/site-filtered search and optional Brave Search HTML) that may throttle, block, or change without notice. Requires lynx on PATH. JS-heavy pages are not supported.

Capabilities

NeedTool
Current web searchlynx_web_search
Alternative web indexlynx_brave_search
GitHub searchlynx_web_search_github
Wikipedia/reference searchlynx_web_search_wikipedia
Reddit discussion searchlynx_reddit_search
Reddit post + top commentslynx_reddit_fetch
Plain-text page fetchlynx_web_fetch
  • Agent-readable Markdown/text by default; no raw API dumps.
  • Capped outputs to avoid flooding context.
  • No API keys or accounts for DDG Lite, Brave Search HTML, page fetch, old Reddit search, or Reddit thread JSON.

Demo

pi-lynx in action

Animated terminal demo:

pi-lynx terminal demo

Recorded terminal demo source: docs/demo/pi-lynx.cast

Play locally:

asciinema play docs/demo/pi-lynx.cast

The demo shows:

  • pi install npm:pi-lynx
  • lynx available on PATH
  • Pi using pi-lynx for web search/page fetch
  • bounded, body-text-first output
  • links as opt-in context

Install

pi install npm:pi-lynx

Then reload or restart pi:

/reload

Requirements

  • lynx installed and on PATH
  • Pi coding agent

Installing lynx

OSCommand
macOSbrew install lynx
Debian/Ubuntusudo apt install lynx
Fedora/RHELsudo dnf install lynx
Archsudo pacman -S lynx
WindowsUse WSL (wsl --install), then sudo apt install lynx inside it. Native Windows lynx builds are unmaintained; pi-lynx shells out to a Unix lynx binary.

Verify:

lynx -version

Quick start

Search:

lynx_web_search: rust language

Alternative index (when DDG throttles):

lynx_brave_search: rust language

Reddit discussion search:

lynx_reddit_search: pi coding agent

Subreddit-scoped Reddit search:

lynx_reddit_search: extensions {"subreddit": "PiCodingAgent"}

Reddit thread fetch:

lynx_reddit_fetch: https://www.reddit.com/r/PiCodingAgent/comments/...

Fetch page text only:

lynx_web_fetch: https://example.com

Fetch with links:

lynx_web_fetch: https://example.com {"include_links": true, "link_limit": 20}

Search engine behavior

  • lynx_web_search uses the configured search-engine chain (PI_LYNX_SEARCH_ENGINES, defaulting to DDG-style public HTML search).
  • lynx_brave_search queries Brave Search HTML directly as an alternate no-key search surface.
  • GitHub and Wikipedia helpers are site-filtered convenience wrappers over the default web-search path.
  • These are best-effort HTML parsers, not search APIs; public search pages may throttle, block, or change markup.

Alternative: install from git

pi install git:github.com/dabito/pi-lynx

Alternative: install from source

git clone https://github.com/dabito/pi-lynx.git
cd pi-lynx
npm install
pi -e .

Tools

Tool composition

Tools are composed in a layered hierarchy to avoid duplication:

lynx_web_fetch            ← base layer (lynx -dump + parse)
  ↑ used by
lynx_web_search           ← DDG Lite URL construction + result parsing
  ↑ used by
lynx_web_search_github    ← convenience wrapper (pre-set site:github.com)
lynx_web_search_wikipedia ← convenience wrapper (pre-set site:wikipedia.org)

lynx_brave_search         ← Brave Search (native fetch + HTML parse; alt index)
lynx_reddit_search        ← old.reddit.com search (lynx -dump + parse)
lynx_reddit_fetch         ← reddit thread .json API (native fetch)

Brave search fetches Brave's server-rendered HTML directly (with a browser User-Agent) and parses data-type="web" blocks — a different index than DDG, useful when DDG Lite throttles or returns poor results. It needs no API key.

Reddit search uses old.reddit.com first because Reddit's JSON search endpoint usually blocks bot-like traffic. Reddit thread fetch still uses the public .json thread endpoint because it returns cleaner post/comment data when available.

lynx_web_fetch

Fetch a web page and extract its text content using lynx. Links are opt-in and capped by default.

NameTypeRequiredDefaultDescription
urlstringURL to fetch
max_linesnumber300Max lines of body text (50–2000)
include_linksbooleanfalseInclude extracted links section
link_limitnumber20Max links when include_links=true

Search the web using DuckDuckGo Lite. Returns structured results with titles, snippets, domains, and URLs.

NameTypeRequiredDefaultDescription
querystringSearch query; supports !gh and !w shortcuts
max_resultsnumber8Max results to return (1–20)
sitestringRestrict to "github" or "wikipedia"
enginestring"ddg""ddg", "brave", or "auto" (runs the PI_LYNX_SEARCH_ENGINES chain with fallback)

Shortcuts:

  • !gh <query> or site: "github" → restricts to GitHub
  • !w <query> or site: "wikipedia" → restricts to Wikipedia

If both a bang shortcut and an explicit site filter are provided, the explicit filter wins. For example, query: "!gh rust", site: "wikipedia" searches Wikipedia for rust.

engine defaults to "ddg" so existing behavior is unchanged. Set engine: "brave" to search Brave directly, or engine: "auto" to run the ordered engine chain configured by PI_LYNX_SEARCH_ENGINES, falling back to the next engine on error or (by default) on an empty result set.

lynx_web_search_github

Search GitHub using DuckDuckGo Lite. Convenience wrapper around lynx_web_search with site:github.com pre-set.

NameTypeRequiredDefaultDescription
querystringSearch query
max_resultsnumber8Max results to return

lynx_web_search_wikipedia

Search Wikipedia using DuckDuckGo Lite. Convenience wrapper around lynx_web_search with site:wikipedia.org pre-set.

NameTypeRequiredDefaultDescription
querystringSearch query
max_resultsnumber8Max results to return
max_resultsnumber8Max results to return

Search the web via Brave Search and return structured results: titles, snippets, domains, and URLs. No API key required. Use as an alternative to lynx_web_search when DDG Lite throttles or returns poor results — it is a different index and ranking.

NameTypeRequiredDefaultDescription
querystringSearch query
max_resultsnumber8Max results to return (1–20)

lynx_reddit_fetch

Fetch a Reddit thread and return compact agent-readable text: post title/body plus top comments sorted by score. Uses Reddit's public .json endpoint internally; no lynx or API key required.

NameTypeRequiredDefaultDescription
urlstringReddit thread/comments URL
max_commentsnumber10Max top-level comments to include (1–50), sorted by score

Search Reddit threads via old.reddit.com and return compact agent-readable results: titles, subreddits, authors, scores, comment counts, and permalinks. No API key required.

NameTypeRequiredDefaultDescription
querystringSearch query
subredditstringRestrict search to this subreddit (no r/ prefix)
max_resultsnumber10Max results to return (1–25)

Behavior notes

  • lynx_web_fetch returns body text only by default.
  • Links are explicit opt-in: set include_links: true.
  • When links are included, they are capped by link_limit.
  • max_lines caps body text only.
  • DDG Lite site-filtered searches may throttle; PI_LYNX_SITE_SEARCH_INTERVAL_MS spaces them out. If DDG still throttles, try lynx_brave_search (different index).
  • lynx_web_search defaults to DDG-only (engine: "ddg"); pass engine: "auto" to run the PI_LYNX_SEARCH_ENGINES chain with fallback on error or empty results.
  • lynx_brave_search uses native fetch (not lynx) against Brave's server-rendered HTML; it does not need lynx on PATH.
  • lynx_reddit_search uses old.reddit.com and returns compact Markdown/text, not raw HTML.
  • lynx_reddit_search uses old.reddit.com and returns compact Markdown/text, not raw HTML.

Failure modes

  • Missing lynx: install it and ensure it is on PATH.
  • Site-filtered search throttled: wait, raise PI_LYNX_SITE_SEARCH_INTERVAL_MS, or switch to lynx_brave_search.
  • Brave bot check: lynx_brave_search may receive no organic results from data-center IPs; retry later or from a different network.
  • JS-heavy / browser-required pages: Lynx may not capture the interactive content.
  • Reddit bot check: lynx_reddit_search uses old.reddit.com because Reddit JSON search is often blocked. lynx_reddit_fetch still uses Reddit's .json thread endpoint and can receive an HTML bot-check page instead of JSON; there is no bypass, so retry later or from a different network.

Configuration catalog

VariableDefaultMinDescription
PI_LYNX_SITE_SEARCH_INTERVAL_MS30001000Minimum spacing between DDG Lite site: searches. Use 4000 or higher if DuckDuckGo throttles repeated GitHub/Wikipedia searches.
PI_LYNX_SEARCH_ENGINESddgComma list of engines for lynx_web_search's engine: "auto" chain, e.g. ddg,brave. Unknown/empty values fall back to ddg. Only takes effect when engine: "auto" is passed.
PI_LYNX_SEARCH_FALLBACK_ON_EMPTYtrueWhen true (default), an engine that returns zero results and no instant answer is skipped in favor of the next engine in the chain. Set to 0/false/no/off to disable.

Command catalog

CommandPurpose
npm testRun fixture-based unit tests. Live DDG search stays skipped by default.
PI_LYNX_INTEGRATION=1 npm testRun live DDG Lite integration tests. May throttle repeated site: searches.
npm run typecheckRun strict TypeScript checking.
npm run lintRun ESLint.
npm pack --dry-runPreview publish tarball contents.

Notes on DuckDuckGo Lite

Raw DDG bangs such as !gh and !w redirect away from DDG Lite, so pi-lynx converts them to site: filters before searching.

DuckDuckGo Lite can temporarily rate-limit repeated site: searches. pi-lynx spaces site-filtered searches by at least 3 seconds by default; tune with PI_LYNX_SITE_SEARCH_INTERVAL_MS.

How it works

  1. lynx_web_fetch runs lynx -dump on a URL to get plain text.
  2. The References section is parsed to build a [N] → URL mapping.
  3. DDG redirect URLs (duckduckgo.com/l/?uddg=...) are resolved to real target URLs.
  4. [N] markers are stripped from body text for clean output.
  5. lynx_web_search constructs a DDG Lite URL and parses search results.
  6. Site-specific tools call lynx_web_search with the appropriate site: filter.
  7. lynx_reddit_search runs lynx -dump on old.reddit.com search and parses compact result metadata.
  8. lynx_reddit_fetch calls Reddit's .json thread endpoint, parses the payload, and returns compact Markdown/text.

Development

npm test
npm run typecheck

Unit tests use committed DuckDuckGo Lite fixtures in test/fixtures.

The live DDG Lite integration test is opt-in because repeated site: searches can be rate-limited:

PI_LYNX_INTEGRATION=1 npm test
  • hledit for stable, hash-anchored file editing.
  • pi-hledit for Pi integration with hledit.