pi-codebase-router
Index-first routing for Pi: prefer the opencode-codebase-index semantic index over grep/shell, with guardrails, cb* prompts, a workflow skill, and optional session-start / after-write auto-indexing.
Package details
Install pi-codebase-router from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-codebase-router- Package
pi-codebase-router- Version
0.3.0- Published
- Jul 23, 2026
- Downloads
- 131/mo · 131/wk
- Author
- josephjohncox
- License
- MIT
- Types
- extension, skill, prompt
- Size
- 44.9 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./extensions"
],
"skills": [
"./skills"
],
"prompts": [
"./prompts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-codebase-router
Index-first routing for Pi. It makes the agent reach for the
opencode-codebase-index
semantic tools (codebase_peek, codebase_search, implementation_lookup,
call_graph) before falling back to exploratory grep and shell — which
saves tokens and keeps context focused — and keeps file access/mutation on the
built-in read / edit / write tools.
It bundles three things:
- An extension that injects index-first guidance, guards discouraged discovery, and can auto-index on session start / after writes.
- A skill (
indexed-codebase-workflow) documenting the discovery loop. cb*prompt templates — thin, safe wrappers over the index tools.
Requires the companion package
opencode-codebase-index, which provides thecodebase_*/index_*tools this package routes toward. It is a separate install (see below for why). Without it, this extension degrades gracefully and showsindex tools unavailablein the status bar.
Install
# 1. the companion that provides the actual index tools (~235 MB native)
pi install npm:opencode-codebase-index
# 2. this router (extension + skill + cb* prompts)
pi install npm:pi-codebase-router
# …or straight from git:
pi install git:github.com/josephjohncox/pi-codebase-router
Use pi install ... -l to write to project settings (.pi/settings.json)
instead of global (~/.pi/agent/settings.json).
Why two installs (and not one)?
This package intentionally does not bundle or auto-install
opencode-codebase-index:
- It ships ~235 MB of per-platform native binaries (tree-sitter + usearch,
5 platforms). Vendoring that into a ~12 KB routing package via
bundledDependencies— the only way Pi reliably loads a sibling pi-package, since it hoists normal deps into one flatnode_modules— would be absurd. - Pi has no supported "install this other package into settings" hook, and a
postinstallshelling out topi installis fragile and invasive.
So they stay decoupled: install the companion once, globally, and every project reuses it. This package is declared an optional peer of it (documents the relationship without triggering a 235 MB auto-download).
Configuring the companion (opencode-codebase-index)
The router points at whatever opencode-codebase-index is configured to do; it
does not have its own indexing config. Under Pi, that package runs in host
pi, which uses the neutral .codebase-index/ layout:
| Scope | Config | Index storage |
|---|---|---|
| Global | ~/.config/codebase-index/config.json |
~/.codebase-index/global-index |
| Project | <repo>/.codebase-index/config.json |
<repo>/.codebase-index/index |
Project config overrides global. The router's background indexer launches the
companion with --host pi, so it writes the same directory the in-process
codebase_search reads — no split-brain index.
Example config (local Ollama embeddings)
The reference setup uses a local Ollama server via its OpenAI-compatible API
(/v1), so nothing leaves the machine and there are no embedding-API costs:
// ~/.config/codebase-index/config.json
{
"embeddingProvider": "custom",
"customProvider": {
"baseUrl": "http://127.0.0.1:11434/v1",
"model": "qwen3-embedding:8b",
"dimensions": 4096,
"apiKey": "ollama"
}
}
Ollama setup (recommended: local + free + private)
# 1. install Ollama — https://ollama.com (macOS: brew install ollama)
# 2. start the server (the desktop app does this too)
ollama serve
# 3. pull an embedding model (see the table below)
ollama pull qwen3-embedding:8b
Then point the companion at it. Two ways:
- Custom
/v1(recommended for any model / larger models) — the example above.baseUrlmust end in/v1(the companion appends/embeddings);apiKeycan be any placeholder ("ollama"). - Built-in Ollama provider (simplest) —
{ "embeddingProvider": "ollama" }. Uses Ollama's native API withnomic-embed-text, but budgets input to ~2048 tokens, so prefer the custom/v1route for larger-context models.
Remote Ollama? Set OLLAMA_HOST=http://host:11434 (built-in provider) or the
full baseUrl (custom provider).
Which embedding model?
All run locally via Ollama. Pick by the RAM/VRAM you can spare; bigger = better retrieval but slower indexing.
ollama pull … |
dimensions |
Footprint | Use when |
|---|---|---|---|
qwen3-embedding:8b |
4096 |
~8B (needs real RAM/VRAM) | Best quality. Workstations/servers. (the reference config) |
qwen3-embedding:4b |
2560 |
~4B | Strong quality, lighter than 8B |
qwen3-embedding:0.6b |
1024 |
~0.6B | Best quality-for-size on laptops |
mxbai-embed-large |
1024 |
~335M | Strong English retrieval, low resource |
bge-m3 |
1024 |
~567M | Multilingual / longer context |
nomic-embed-text |
768 |
~137M | Fast, tiny default; fine for most repos |
Rules of thumb
- Laptop / low memory →
nomic-embed-text(orqwen3-embedding:0.6bfor better recall). - Plenty of memory and you want the best hits →
qwen3-embedding:8b. - Set
dimensionsto the value in the table (the model's native output width). Ollama does not reliably honor a requested smaller dimension, so don't guess — if unsure, check the model card on ollama.com. A wrongdimensionsyields a dimension-mismatch error and a forced rebuild. - Changing model or
dimensionsinvalidates the index: run/cbindex forceonce after the change.
Provider options (if not using Ollama)
embeddingProvider accepts auto (default; detects Copilot → OpenAI → Google →
Ollama), ollama, openai, google, github-copilot, or custom (any
OpenAI-compatible /v1/embeddings endpoint). Hosted providers read their key
from the usual env vars (e.g. OPENAI_API_KEY, GOOGLE_API_KEY); GitHub
Copilot reuses existing OpenCode auth. See the
companion README for
the full schema (chunking, hybrid weights, reranker, knowledge bases, etc.).
Verifying / building the index
/cbstatus # provider, model, chunk count, readiness
/cbindex # incremental build/update
/cbindex force # full rebuild (after changing provider/model/dimensions)
What it does
1. Index-first guidance (before_agent_start)
On code/repository-flavored prompts it appends a short routing block to the
system prompt: peek → look up the definition → read exact lines; reserve grep
for exact identifiers; keep edits on read/edit/write; use /cbindex when
the index is missing or stale.
2. Discovery guard (tool_call)
| Attempt | Verdict |
|---|---|
grep / shell rg for a concept ("where is auth handled?") |
blocked → use codebase_peek |
grep for an exact identifier/literal (validateToken, -F fixed strings) |
allowed |
Shell source read (cat/head/tail/sed/less/more a file) |
blocked → use read |
Shell source write (>/>> to a file, tee <file>, sed -i, perl -i) |
blocked → use edit/write |
Toolchain commands (git, npm, pytest, …) and 2>/dev/null / 2>&1 |
allowed |
The guard is deliberately conservative: single-token identifier-shaped patterns,
fd redirects (2>/dev/null, 2>&1), and normal toolchain commands are never
blocked.
3. Optional background auto-indexing
Off by default. When enabled, indexing runs in the background — a detached
opencode-codebase-index MCP subprocess does the work. There is no agent
turn and no LLM cost, and Pi is never blocked: you keep typing while the index
refreshes into the same .codebase-index/ directory Pi's codebase_search
reads (host pi).
| Env var | Effect |
|---|---|
PI_CODEBASE_AUTO_INDEX=1 |
Background index on session start / resume / new / fork when the cwd looks like a project. |
PI_CODEBASE_AUTO_INDEX_AFTER_WRITE=1 |
After a settled turn that used write/edit, background index once. |
PI_CODEBASE_INDEX_BIN=/abs/path/dist/cli.js |
Point at the opencode-codebase-index CLI explicitly (otherwise auto-located under ~/.pi/agent/npm, the project's .pi/npm, or npx). |
PI_CODEBASE_AUTO_INDEX_VIA_TURN=1 |
Revert to the legacy behavior: queue /cbindex as a follow-up agent turn instead of a background subprocess. |
Always an incremental index (never force), only in project directories
(detected via .git, package.json, pyproject.toml, Cargo.toml, go.mod,
pom.xml, build.gradle). At most one index runs at a time; writes that land
during a run coalesce into a single follow-up index. The subprocess is killed on
session shutdown (indexing is incremental and resumes next time). If the CLI
can't be located or spawned, it automatically falls back to the follow-up-turn
path.
Configuration
Settings resolve with precedence env var > project router.json > global
router.json > built-in default. Nothing is required; the defaults are safe
(enforce mode, no auto-indexing).
Config file — router.json
| Scope | Path |
|---|---|
| Global | ~/.config/codebase-index/router.json (respects $XDG_CONFIG_HOME) |
| Project | <repo>/.codebase-index/router.json (overrides global) |
It sits next to the companion's config.json, so one dotfiles sync covers both.
Re-read on /reload and on each new session. Example (all keys optional):
{
"mode": "enforce",
"autoIndex": false,
"autoIndexAfterWrite": true,
"autoIndexViaTurn": false,
"indexTimeoutMs": 900000
}
Keys and env overrides
router.json key |
Env override | Values | Default | Meaning |
|---|---|---|---|---|
mode |
PI_CODEBASE_ROUTER_MODE |
enforce | warn | off |
enforce |
enforce blocks discouraged calls; warn allows but shows a hint and still injects guidance; off disables everything. |
autoIndex |
PI_CODEBASE_AUTO_INDEX |
bool | false |
Background index on session start / resume / new / fork. |
autoIndexAfterWrite |
PI_CODEBASE_AUTO_INDEX_AFTER_WRITE |
bool | false |
Background index after a settled turn that used write/edit. |
autoIndexViaTurn |
PI_CODEBASE_AUTO_INDEX_VIA_TURN |
bool | false |
Use a follow-up agent turn instead of a background subprocess. |
indexBin |
PI_CODEBASE_INDEX_BIN |
path | auto | Explicit path to opencode-codebase-index's dist/cli.js. |
indexTimeoutMs |
PI_CODEBASE_INDEX_TIMEOUT_MS |
int (ms) | 900000 |
Background-index kill timeout. |
Env booleans accept 1/true/yes/on and 0/false/no/off. An env
value always wins over the files — set PI_CODEBASE_AUTO_INDEX_AFTER_WRITE=0 to
switch off a file true for one session.
Commands (prompt templates)
| Command | Tool | Purpose |
|---|---|---|
/cbindex [estimate|force|verbose] |
index_codebase |
Build/update the index (incremental by default). |
/cbstatus |
index_status |
Show index status and provider/model. |
/cbreindex |
index_codebase force |
Full rebuild. |
/cbpeek <query> |
codebase_peek |
Metadata-only locations (cheapest). |
/cbsearch <query> |
codebase_search |
Semantic search with content. |
/cbfind <query> |
peek → lookup/search → grep | Token-efficient hybrid discovery. |
/cbdef <symbol> |
implementation_lookup |
Authoritative definition site. |
/cbcallgraph <name> [callers|callees] |
call_graph |
Callers/callees. |
/cbpath <from> <to> |
call_graph_path |
Shortest call path. |
/cbimpact [branch|PR#] |
pr_impact |
Change blast radius. |
/cbhealth |
index_health_check |
GC and health report. |
Skill
indexed-codebase-workflow documents the loop:
codebase_peek → implementation_lookup/codebase_search → read exact lines
→ edit/write → tests/diagnostics → inspect the diff. Load it with
/skill:indexed-codebase-workflow.
Compatibility
- Pi loads the extension as TypeScript via jiti — no build step required.
- Requires Node ≥ 18.
- Peers (both optional/informational):
@earendil-works/pi-coding-agent(provided by the Pi runtime) andopencode-codebase-index(install separately — see above; declared optional so it is not auto-downloaded).
Migrating from a local copy
If you previously hand-placed codebase-routing.ts in
~/.pi/agent/extensions/ (plus the skill/prompts), remove those local copies
after installing this package so the extension doesn't load twice:
rm -f ~/.pi/agent/extensions/codebase-routing.ts
rm -rf ~/.pi/agent/skills/indexed-codebase-workflow
rm -f ~/.pi/agent/prompts/cb*.md
Continuous integration & publishing
- CI (
.github/workflows/ci.yml): typechecks on every push/PR. - Publish (
.github/workflows/publish.yml): on a published GitHub Release it runsnpm publish --provenance --access public. Manual runs (workflow_dispatch) support a--dry-run.
One-time setup: add an npm Automation token as the NPM_TOKEN repository
secret (gh secret set NPM_TOKEN). Release flow:
npm version patch # or minor / major — bumps package.json + tags
git push --follow-tags
gh release create "v$(node -p 'require("./package.json").version')" --generate-notes
The workflow verifies the release tag matches package.json. First release can
also be published locally with npm publish --access public.
License
MIT © Joseph Cox