Surfaces
A library has to work for a person at a shell and for a model inside an agent host. Writing each surface separately is how you end up with six slightly different answers to the same question. So every package keeps one set of tool executors and wires the surfaces onto it.
Library
The ESM package with .d.mts declarations. This is the source of truth, everything else is a thin caller.
import { fetchPackageFromPURL } from "@agntn/registries";
const pkg = await fetchPackageFromPURL("pkg:npm/lodash");
CLI
Same calls from a shell, --json for scripts. The binary is the package name without the scope.
registries info pkg:npm/lodash --json
web search "typescript 7 native" --provider brave
chains validate 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
AI SDK
Packages with a /ai subpath export Vercel AI SDK tools with Zod schemas. The host abort signal goes straight through to the provider request. Right now that's web, registries, urls, nfts, storages, maps, lyrics and books. The others expose the same executors through MCP and the extensions.
import { generateText } from "ai";
import { searchTool } from "@agntn/web/ai";
await generateText({ model, tools: { search: searchTool }, prompt: "…" });
MCP
<name> mcp serves the same tools over stdio. Register it once in any MCP host and every tool of that library is there.
{
"mcpServers": {
"web": { "command": "web", "args": ["mcp"] }
}
}
Pi and OMP
The extension sources ship inside the npm package under packages/pi and packages/omp. They load the library from the package itself, source tree in a checkout, dist once installed. No second copy of the logic to keep in sync.
Which surfaces each library actually ships is on its page in the catalogue.