v1.12.0 is a single-package story. rpiv-web-tools already spoke
six hosted search engines after v1.8.0 — Brave, Tavily, Serper, Exa,
Jina, and Firecrawl. v1.12.0 adds the first one you can host
yourself: SearXNG. With it comes a
small but real reshaping of how providers receive their
configuration, and a clearer story about which SSRF rules apply
where.
A self-hosted seventh provider
The new searxng provider plugs into the same SearchProvider
contract as the six hosted vendors. It reuses the shared HTTP +
htmlToText pipeline that Brave and Serper already go through, so a
SearXNG result with no native extraction endpoint still comes back
as readable text rather than raw HTML.
Configure it the usual two ways: SEARXNG_URL in the environment,
or baseUrls.searxng in ~/.config/rpiv-web-tools/config.json. The
default is http://localhost:8080, which is what you get out of the
box from the official Docker image. If your instance sits behind a
Bearer-auth proxy, set SEARXNG_API_KEY or apiKeys.searxng — the
provider attaches the header without you having to think about it.
The /web-search-config picker has learned the new shape too. When
you select searxng it asks for the URL first, then offers the
optional API key as a second prompt; either submitted empty
preserves whatever you already had.
The factory grew a baseUrl slot
Six hosted providers each need exactly one secret. SearXNG needs an address, optionally a key, and nothing else. The old factory signature couldn’t carry both:
// before
createSearchProvider(name, apiKey: string)
// after
createSearchProvider(name, creds: { apiKey?: string; baseUrl?: string })
The six hosted providers still receive their key transparently via
creds.apiKey, so internal call sites all flipped over in one
mechanical pass. Direct downstream callers — if you import
createSearchProvider yourself rather than going through the
extension’s tool surface — will need the options-bag form. The
changelog calls this out under Breaking / Upgrade Notes for
anyone reading the diff.
SSRF for web_fetch, loopback for search
The interesting tension with a self-hosted provider is that
http://localhost:8080 is exactly the kind of URL the SSRF guard
in v1.8.0 was designed to refuse. v1.8.0 taught web_fetch to
reject loopback, RFC1918, link-local, and unique-local IPv6 — so a
search result that resolves to your dev server or the cloud
metadata endpoint can’t be fetched through the agent.
That guard still applies to web_fetch. It does not apply to the
search endpoint itself, because the whole point of a self-hosted
instance is that you reach it at localhost. The README now spells
this asymmetry out explicitly: search talks to a server you trust
and chose to run; fetch talks to URLs the search result hands back,
which you don’t.
Hardening the new edges
Two small fixes landed alongside the feature, both from looking at what could go wrong at the URL boundary:
- The provider now rejects non-HTTP schemes at construction time
rather than letting them propagate into the request layer, and
strips trailing slashes so
http://host:8080/andhttp://host:8080resolve identically. - A
401from the instance attaches a dedicated hint about auth-proxy rejections, the same way a403already hinted thatjsonlikely needs to be added tosearch.formatsinsettings.yml— the most common SearXNG misconfiguration when the agent first tries to query an instance that was set up for humans, not for JSON consumers.
Running SearXNG locally
The README picked up a short Docker recipe for spinning up an
instance with persistent settings. Two surprises worth knowing about
if you’re building it yourself: the upstream searxng/searxng
image uses an entrypoint that needs a writable /etc/searxng
volume, and the json format isn’t on by default. The recipe in
the README handles both, and the changelog notes them as a heads-up
for anyone copy-pasting from the official docs.
Anything else?
Every other package in the @juicesharp/rpiv-* family bumped to
1.12.0 with no user-visible changes — the standard lockstep ride.
A second commit refactored the per-provider config plumbing onto a
ProviderMeta dispatch table; that’s a code-shape change with no
behavior delta, but it’s why adding the eighth provider, whenever
it shows up, will be a much smaller diff than this one.
Grab the new version the usual way:
npm install @juicesharp/rpiv-pi@1.12.0
Or let your normal upgrade flow pick it up. The full per-package
changelog lives in each package’s CHANGELOG.md in the
monorepo.
See you at v1.13.0.