Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/binary-file-guard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ conversion + `pdftotext` for Office documents.

## What is blocked

PDFs, archives (ZIP, tar, gzip, 7z, RAR, etc.), executables (ELF, PE), databases
(SQLite), audio, video, and more; all detected via magic bytes.
PDFs, archives (ZIP, tar, gzip, bzip2, xz, zstd, LZ4, 7z, RAR, RPM, CPIO),
executables (ELF, PE, Java serialized objects), databases (SQLite), audio,
video, and more. Known formats are matched by magic-byte signatures; files
that match no signature but still look binary (high null-byte or invalid-UTF-8
ratio) are blocked too.

Supported image formats (PNG, JPEG, GIF, WebP) are not blocked; the LLM can view them directly.
Unsupported image formats (AVIF, HEIC, BMP, ICO) are blocked with conversion hints.
Expand Down
2 changes: 1 addition & 1 deletion packages/binary-file-guard/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@m4ss/pi-binary-file-guard",
"version": "0.1.0",
"description": "Block read tool from reading binary files (PDF, archives, executables) by detecting magic bytes",
"description": "Block Pi's read tool from loading binary files (PDFs, archives, executables, databases) and suggest the right CLI tool to extract their contents instead",
"license": "MIT",
"author": "Paolo Barbolini <paolo.barbolini@m4ss.net>",
"repository": {
Expand Down
15 changes: 5 additions & 10 deletions packages/llms-txt/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
# @m4ss/pi-llms-txt

We built this to let the model discover a site's structure before diving into
individual pages. It fetches and caches `llms.txt` from documentation sites
using a cache-first strategy.

The [`llms.txt`](https://llmstxt.org) standard is a curated, LLM-friendly map of a
website's most important content. Not many sites publish one yet, but when they do,
this extension gives the model a site map before it starts fetching pages. For sites
that don't publish `llms.txt`, the tool reports it and moves on.
Fetch and cache a site's [`llms.txt`](https://llmstxt.org), a curated LLM-friendly
map of a website's most important content, so the model can survey a documentation
site's structure before deep-fetching individual pages. Few sites publish one yet;
when a site doesn't, the tool reports that and moves on. Cache-first, so repeat
lookups are cheap.

## Notes

Expand All @@ -23,8 +20,6 @@ pi install npm:@m4ss/pi-llms-txt

## Usage

The LLM calls `llms_txt` on its own. You can also invoke it directly:

```
llms_txt("www.postgresql.org")
llms_txt("redis.io", forceRefresh=true)
Expand Down
2 changes: 1 addition & 1 deletion packages/llms-txt/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@m4ss/pi-llms-txt",
"version": "0.1.0",
"description": "llms.txt cache-first tool — fetch and cache llms.txt from any domain, inject guidance so the model uses it before deep-fetching docs",
"description": "Cache-first llms.txt tool for Pi: fetches and caches a site's llms.txt map so the model can survey important pages before deep-fetching individual docs",
"license": "MIT",
"author": "Paolo Barbolini <paolo.barbolini@m4ss.net>",
"repository": {
Expand Down
6 changes: 3 additions & 3 deletions packages/llms-txt/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ export default function (pi: ExtensionAPI) {
name: "llms_txt",
label: "llms.txt",
description:
"Fetch a domain's llms.txt a curated map of the site's documentation. " +
"Fetch a domain's llms.txt, a curated map of the site's documentation. " +
"Use before deep-fetching docs sites. Skip for blogs, news, or single-page lookups.",
promptSnippet:
"Fetch and cache llms.txt from any domain for LLM-friendly documentation maps",
promptGuidelines: [
"Use llms_txt(domain) to fetch a domain's llms.txta curated map of its documentation before deep-fetching individual pages.",
"Use llms_txt(domain) to fetch a domain's llms.txt, a curated map of its documentation, before deep-fetching individual pages.",
"Skip llms_txt for blogs, news, or single-page lookups; use web_fetch directly.",
"Use llms_txt forceRefresh sparingly only when the cached map may be stale.",
"Use llms_txt forceRefresh sparingly, only when the cached map may be stale.",
],
parameters: LlmsTxtParams,

Expand Down
7 changes: 4 additions & 3 deletions packages/search-delegator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,16 @@ Config file: `~/.pi/agent/search-delegator.json` (missing fields fall back to de
| `blocked_tools` | `["staan_search", "web_fetch", "llms_txt"]` | Tool names removed from the main model and granted to the searcher |
| `searcher_subagent_name` | `"searcher"` | Subagent name (must match the `.md`) |
| `searcher_model` | `""` | Model for the searcher (`provider/model`). Empty = inherit parent's default. Set a cheap model to keep web research inexpensive |
| `orchestrator_prompt` | _(built-in web-research guidance)_ | Text sent to the main model at session start, telling it how to delegate to the searcher |

The `searcher.md` template is regenerated whenever the config changes. If you edit
`searcher.md` by hand, your version is detected and left untouched.

### Tightening the searcher

`searcher.md` restricts the child to the tools listed in `blocked_tools` (by default
`tools: staan_search, web_fetch, llms_txt`). To narrow it further, edit
`~/.pi/agent/agents/searcher.md`, but keep whatever extensions provide those tools loaded.
`~/.pi/agent/agents/searcher.md` restricts the child to the tools listed in `blocked_tools` (by default
`tools: staan_search, web_fetch, llms_txt`). To narrow it further, edit that file,
but keep whatever extensions provide those tools loaded.

## License

Expand Down
2 changes: 1 addition & 1 deletion packages/search-delegator/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@m4ss/pi-search-delegator",
"version": "0.1.0",
"description": "Block web search/fetch/llms_txt tools on the main pi model and force delegation to a searcher subagent",
"description": "Keep Pi's main context clean: remove web search, fetch, and llms_txt tools from the main model and force delegation to a focused, cheaper searcher subagent",
"license": "MIT",
"author": "Paolo Barbolini <paolo.barbolini@m4ss.net>",
"repository": {
Expand Down
7 changes: 4 additions & 3 deletions packages/search-delegator/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ const DEFAULT_ORCHESTRATOR_PROMPT = [
"",
' subagent({ agent: "searcher", task: "<concrete request>" })',
"",
'Write specific tasks — e.g. "Find latest stable Diesel version; return version,',
'date, source URL." The searcher returns compact findings with URLs. Cite those',
"URLs. Batch related lookups into one delegation.",
'Write specific tasks. For example: "Research how SvelteKit load functions',
"interact with caching and invalidation: cover fetch caching, depends(), and",
'invalidate(). Return a summary with source URLs." The searcher returns compact',
"findings with URLs. Cite those URLs. Batch related lookups into one delegation.",
].join("\n");

export const DEFAULT_CONFIG: Config = {
Expand Down
8 changes: 4 additions & 4 deletions packages/search-delegator/src/searcher-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function renderTemplate(config: Config): string {
const front = [
"---",
`name: ${config.searcher_subagent_name}`,
"description: Web research specialist searches the web, fetches pages, and explores docs sites; returns compact findings with source URLs",
"description: Web research specialist: searches the web, fetches pages, and explores docs sites; returns compact findings with source URLs",
`tools: ${grantedTools.join(", ")}`,
];
if (config.searcher_model.trim()) {
Expand All @@ -75,9 +75,9 @@ function renderTemplate(config: Config): string {
"You are a focused web research agent. Return compact, sourced answers.",
"",
"## Tools",
"- `staan_search` discover information, find URLs. Use `site:domain` or `-domain` to narrow. For known URLs, use `web_fetch` directly.",
"- `web_fetch` retrieve a known URL's content as Markdown. Prefer raw/API endpoints over HTML. To discover URLs, use `staan_search` first.",
"- `llms_txt` map a docs site's structure before fetching individual pages. Skip for blogs/news.",
"- `staan_search`: discover information, find URLs. Use `site:domain` or `-domain` to narrow. For known URLs, use `web_fetch` directly.",
"- `web_fetch`: retrieve a known URL's content as Markdown. Prefer raw/API endpoints over HTML. To discover URLs, use `staan_search` first.",
"- `llms_txt`: map a docs site's structure before fetching individual pages. Skip for blogs/news.",
"",
"## Rules",
"- Prefer official docs, registries, and primary sources.",
Expand Down
29 changes: 10 additions & 19 deletions packages/staan-search/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ model can search the web and get enriched result chunks.

## Features

- Web and news search with semantic enrichment (extra snippets for RAG-style usage)
- Web and news search, with semantic enrichment (extra snippets for RAG-style usage)
- Domain filters via `site:domain` or `-domain.tld` in the query
- Market selection for language/region-aware results (default: `fr-fr`)
- Full-content requests that ask Staan for page bodies and reranking
Expand All @@ -19,40 +19,31 @@ pi install npm:@m4ss/pi-staan-search

## Usage

Set your API key:
Requires `STAAN_API_KEY`:

```bash
export STAAN_API_KEY='your_staan_api_key'
```

The LLM will automatically see `staan_search` as an available tool. Example calls:

- `staan_search("GDPR NIS2 Europe")` – Web Search for AI using the default `fr-fr` market
- `staan_search("AI Act", type="news")` – plain news search
- `staan_search("site:redis.io transactions")` – narrow to a specific domain
- `staan_search("PostgreSQL performance", minScore=0.2, maxSnippets=5)` – RAG-ready chunks
```
staan_search("GDPR NIS2 Europe")
staan_search("AI Act", type="news")
staan_search("site:redis.io transactions")
staan_search("PostgreSQL performance", minScore=0.2, maxSnippets=5)
```

## API Key

Get a key at [staan.ai](https://staan.ai) → Developer Console.
Get a key at the [Staan console](https://staan.ai/console).

- Free tier: 1,000 requests/month
- Web Search: €1 / 1,000 requests
- Web Search for AI: €2 / 1,000 requests

## Routing, privacy, and fallback behavior

- `fr-fr` (default) prefers the European/Staan-backed route.
- `en-us` may use fallback/non-EU infrastructure and domain filters (`site:`) may not work on fallback-routed markets.
- For compliance-sensitive use, verify Staan's DPA/subprocessors and request EU-only routing.

## Limits

- Queries are capped at 400 characters (API limit). A note is added if truncated.
- Domain filters via `site:` syntax may not work when Staan routes through its fallback provider; use `market="fr-fr"` for reliable filtering.
- Pagination supports offsets of 0, 10, 20, or 30 (10 results per page).
- Web searches use semantic enrichment by default. Set `extraSnippets=false` for plain Web Search.
- All API calls use a 10s timeout.
- Domain filters via `site:` syntax may not work when Staan routes through its fallback provider; `market="fr-fr"` filters reliably.

## Related packages

Expand Down
2 changes: 1 addition & 1 deletion packages/staan-search/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@m4ss/pi-staan-search",
"version": "0.1.0",
"description": "Staan AI European search extension for pi-coding-agent",
"description": "Web-search tool for Pi powered by Staan AI's European search API, with semantically enriched snippets for RAG-style usage, news search, and domain filtering",
"license": "MIT",
"author": "Paolo Barbolini <paolo.barbolini@m4ss.net>",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/staan-search/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export default function (pi: ExtensionAPI) {
"Use site:domain or -domain in the query to narrow results to or from specific sites.",
'Keep the default market="fr-fr" for the European route; use market="en-us" only for US-specific needs.',
"Treat snippets as pointers, not proof: verify claims against the enriched chunks or a web_fetch of the page before relying on them.",
"To look up a known package or repo, fetch its registry/API endpoint instead of searching (bare names collide); search only to disambiguate.",
"When you already know the URL or identifier, fetch it directly. Search to discover unknowns or disambiguate colliding names (e.g. bare package names).",
],

parameters: SearchParams,
Expand Down
6 changes: 3 additions & 3 deletions packages/web-fetch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ caps response size to keep things manageable.
## Features

- Fetches any HTTP/HTTPS URL and converts HTML to clean Markdown (JSON is pretty-printed)
- Blocks private network addresses (localhost, RFC 1918, link-local); every redirect hop is validated, so a redirect can't bounce into an internal address
- Blocks private network addresses (localhost, RFC 1918, link-local, CGNAT, IPv6 ULA); every redirect hop is validated, so a redirect can't bounce into an internal address
- Follows instant meta-refresh redirects (the stub pages static site generators emit)
- 10s default timeout, overrideable per call; large responses capped at 5MB

Expand All @@ -28,10 +28,10 @@ web_fetch(url="https://example.com/slow", timeoutMs=20000)

## Private networks

Blocks private/internal addresses (localhost, RFC 1918, link-local) on all redirect hops (max 5, each validated).
Blocks private/internal addresses (localhost, RFC 1918, link-local, CGNAT, IPv6 ULA) on all redirect hops (max 5, each validated).

The check runs on the URL's hostname, so it does not defend against DNS
rebinding a hostile public hostname that resolves to a private address gets
rebinding: a hostile public hostname that resolves to a private address gets
through (that would require a pinned resolver). Treat the guard as protection
against accidental internal access, not as a hard security boundary; don't
rely on it to isolate a machine that can reach sensitive internal services.
Expand Down
2 changes: 1 addition & 1 deletion packages/web-fetch/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@m4ss/pi-web-fetch",
"version": "0.1.0",
"description": "Web fetch (HTML→Markdown) tool for pi-coding-agent",
"description": "Web-fetch tool for Pi: fetches HTTP(S) URLs, converts HTML to clean Markdown, and pretty-prints JSON responses",
"license": "MIT",
"author": "Paolo Barbolini <paolo.barbolini@m4ss.net>",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/web-fetch/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default function (pi: ExtensionAPI) {
"Prefer raw/API endpoints over rendered HTML. To discover URLs, use staan_search first.",
promptSnippet: "Fetch and convert a web page to Markdown",
promptGuidelines: [
"Use web_fetch to retrieve any HTTP/HTTPS URLwhether the user gave it, you already know it, or staan_search returned it and cite the fetched URL in your answer.",
"Use web_fetch to retrieve any HTTP/HTTPS URL, whether the user gave it, you already know it, or staan_search returned it, and cite the fetched URL in your answer.",
"Prefer official structured APIs, raw file URLs, or export endpoints over rendered HTML when they carry the same content; for GitHub use raw.githubusercontent.com (file contents) and the GitHub API (repo metadata).",
"When you know a package or repo name, fetch its registry/API endpoint directly (crates.io, npm, PyPI, GitHub API), choosing the most specific resource to avoid pulling unneeded data.",
"Fetch rendered HTML only when presentation matters or no structured/raw endpoint exists; keep the default format=markdown and use html only when you need raw markup.",
Expand Down