@thurstonsand/pi-librarian
Code research subagent for pi: deep-dive repos and discover across GitHub, GitLab, Bitbucket Server, and Sourcegraph; plus web search and URL-native fetch
Package details
Install @thurstonsand/pi-librarian from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@thurstonsand/pi-librarian- Package
@thurstonsand/pi-librarian- Version
0.8.0- Published
- Nov 2, 2026
- Downloads
- 629/mo · 198/wk
- Author
- thurstonsand
- License
- MIT
- Types
- extension
- Size
- 1.2 MB
- Dependencies
- 9 dependencies · 5 peers
Pi manifest JSON
{
"extensions": [
"./extensions/librarian.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-librarian
A code research subagent for the pi coding agent inspired by Amp: deep-dive questions about specific repos ("how does drizzle-orm implement prepared statements?") and discovery across the ecosystem ("compare the most popular TypeScript SQL ORMs"). It also gives your session, and every librarian run, web_search and web_fetch.


How it works
The librarian tool spawns a research subagent with purpose-built tools, built from the sources you configure. One tool per search engine, because every engine's query language and filters differ; a tool with no configured instance does not appear, and one with several takes a source argument naming which.
checkout_repo— clone into a local cache, where it can be read locally, andgit log -S/blame/diffcovers history. Takes a repository path plus asourcenaming one of your configured sources, or a full HTTPS/SSH clone URL on its own.read_file— read one file or list one directory from a code host without cloning.search_code_github— GitHub code search over public code and private repositories your token can read.search_code_grepapp— public code search via Grep, with regex.search_repos_github— GitHub repository discovery by name, topics, language, stars, and activity.search_code_gitlab,search_repos_gitlab— with a declared GitLab: exact-string code search within a project (across projects withadvancedSearch), held to GitLab's 30 code searches a minute, and project search by name, group, topic, and activity.search_code_bitbucket,search_repos_bitbucket— with a declared Bitbucket Server: whole-word code search across every repository, and repository search by the start of a name.search_code_sourcegraph,search_repos_sourcegraph,find_definition— with a declared Sourcegraph: code search across every repository it indexes, with adetailof repos, files, or matched lines and a statement of whether it covered them all; repository search by name, topic, contained path, or recent commits; and symbol definitions by exact name, leaving vendored copies out unless asked.web_search,web_fetch— the web tools, which librarian runs get as well.
Every search returns a short digest, 10 results unless the librarian asks for up to 50 (grep.app returns 10 at most), and writes the full result set to a file it can grep. A search that runs past its 15-second budget is an error that says how to narrow it, never a partial answer.
Usage
- Ask pi a question involving other repos; it asks the
librarian. - Ask follow-up questions to earlier librarian runs.
/librarianattaches the research tools directly to your session for direct tool usage.web_searchandweb_fetchare always in your session;/browser openopens the fetch browser so you can log in to sites it should reach.
Web tools
This package absorbed pi-web-tools, which is deprecated. Uninstall it: both register web_search and web_fetch, and pi reports the clash at startup.
web_search
Backed by Parallel, and registered only when a Parallel key is configured. It takes an objective and returns results with excerpts.

Parameters:
objective(required) — what you want to learn.search_queries— up to 8 specific queries.max_results— 1–8, defaults to 5.after_date—YYYY-MM-DDfreshness filter.
web_fetch

Fetch up to 10 URLs at once. Each document's body is written under <cacheDir>/fetches/<call>/ as a native artifact (markdown, patch, source file), and the tool result is a digest: title, facts, the artifact paths with sizes, and a capped excerpt. Pass an optional objective to steer extraction where supported.
Each URL goes through a chain of fetchers, github → parallel → local; the first to produce a document wins.
GitHub resolves URLs on github.com and on any github source you declare, through the same client and token as the repo tools:
- Repository READMEs, files (including
blobandrawURLs), and directories as a listing - Issues, pull requests, and Discussions with their conversations; PRs also carry the diff. An issue carries its timeline filtered to closes, reopens, and references, and says when a commit closed it, because closed as
completedalone can mean the reporter was answered rather than the bug fixed. - Issue and PR listings,
github.com/{owner}/{repo}/issuesor/pulls, optionally with?q=in GitHub search syntax, up to 100 matches, each with its state and reason - Commits with metadata, comments, and a patch; commit history, optionally scoped by ref and path, up to 100 commits
- Releases (tagged, latest, and listings), tags, and branches
- GitHub Actions runs with jobs, steps, and artifact metadata
Parallel extracts anything else, when a key is configured.
Local is a browser fallback: playwright-core driving your Chrome, with a rehype HTML-to-markdown pipeline. It reaches pages behind a login once you have logged in through /browser open, and downloads non-HTML files such as PDFs. A bot-wall challenge that does not clear headless within headlessWaitSecs briefly opens a visible window for up to headedWaitSecs, unless escalation is "never". /browser restart applies changed browser settings.
GitHub auth for private repos
Public GitHub reads work without configuration. To let the librarian search and read private GitHub repositories, provide a token in one of these ways:
- Set
GITHUB_TOKENorGH_TOKENin the environment before starting pi. - Or authenticate the GitHub CLI so
gh auth tokenreturns a token:
The token is loaded once per pi session and used for GitHub access in search_code_github, search_repos_github, read_file, and web_fetch. For private repositories, use a token with read access to the target repos. checkout_repo uses git's built-in credential helpers instead.
Configuration
In pi's global settings.json:
{
"librarian": {
"model": "openai-codex/gpt-5.5",
"thinkingLevel": "off",
"tools": { "disabled": [] },
"sources": [
{
"name": "example-gl",
"url": "https://gitlab.example.com",
"kind": "gitlab",
"tokenEnv": "EXAMPLE_GITLAB_TOKEN",
"advancedSearch": false,
"description": "Holds the services not yet migrated to example-bb."
},
{
"name": "example-bb",
"url": "https://git.example.com",
"kind": "bitbucket-server",
"disabled": ["code-search"]
},
{
"name": "example-sg",
"url": "https://search.example.com",
"kind": "sourcegraph",
"tokenCommand": "op read op://Private/Sourcegraph/credential"
}
],
"builtInSources": { "github": true, "gitlab.com": false },
"search": { "timeoutSeconds": 15, "defaultLimit": 10 },
"web": {
"parallel": { "apiKeyCommand": "op read op://Private/Parallel/credential" },
"fetch": {
"browser": {
"executablePath": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
},
"challenge": { "escalation": "headed", "headlessWaitSecs": 10, "headedWaitSecs": 20 }
}
},
"cacheDir": "/tmp/pi-librarian",
"debug": { "persistRuns": false }
}
}
| Setting | Recommended | Default |
|---|---|---|
model |
openai-codex/gpt-5.5 |
current session model |
thinkingLevel |
off |
current session thinking level |
tools.disabled |
names of tools to remove from librarian runs | [] |
sources |
code hosts and search backends | [] |
builtInSources |
switch github and gitlab.com on or off |
github on, gitlab.com off |
search.timeoutSeconds |
seconds a search may run before it is an error | 15 |
search.defaultLimit |
results a search returns unless asked for more (at most 50) | 10 |
web.parallel.apiKeyCommand |
shell command printing a Parallel key, run per call | PARALLEL_API_KEY only |
web.fetch.browser.executablePath |
the Chrome the local fetcher drives | an installed Chrome |
web.fetch.browser.profileDir |
the fetch browser's profile | ~/.pi/agent/browser-profile |
web.fetch.challenge.* |
escalation (headed or never), headlessWaitSecs, headedWaitSecs |
headed, 10, 20 |
cacheDir |
/tmp/pi-librarian |
/tmp/pi-librarian |
debug.persistRuns |
persist nested session file paths for debugging | false |
Each librarian.sources entry requires a unique name, an HTTPS url, and a kind: github, gitlab, bitbucket-server, or sourcegraph. The kind decides which roles a source can play — clone, code-search, repo-search — unless disabled. github and gitlab.com are built in and need no entry; builtInSources switches each on or off as a whole, and a switched-off source does not exist at all, though a full clone URL to its host still clones.
Search needs an API token; cloning does not, because it uses git's own credentials. A source reads its token from the environment variable named by tokenEnv, from what tokenCommand prints, or by default from its kind's usual variable: GITHUB_TOKEN/GH_TOKEN, GITLAB_ACCESS_TOKEN, BITBUCKET_TOKEN, SRC_ACCESS_TOKEN. tokenCommand runs once, the first time the source is used, and outside the search time limit; restart pi after rotating the token it prints. A source without a token keeps cloning and loses its search tools. advancedSearch: true, on a gitlab source only, says the instance has GitLab's advanced search, which lets code search span projects. description is up to 300 characters the agent cannot discover for itself, such as what a Sourcegraph does not index; it ends the description of every tool that reaches that source, so attached tools carry it too. Note that librarian.tools.disabled is a different lever: it removes a tool from the run entirely, where a source's disabled removes one source from one role.
Every key under librarian is checked, and an unknown one is an error rather than ignored. Librarian runs have read, grep, find, ls, bash, the research tools, and the web tools; never write or edit.
Development
npm run check # biome + tsc + vitest
pi -e ./extensions/librarian.ts # run pi with this extension loaded