@joshbochu/pi-recall

Fast, native full-text search and resume for Pi sessions

Packages

Package details

extension

Install @joshbochu/pi-recall from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@joshbochu/pi-recall
Package
@joshbochu/pi-recall
Version
0.3.1
Published
Jul 27, 2026
Downloads
84/mo · 84/wk
Author
joshbochu
License
MIT
Types
extension
Size
178.3 KB
Dependencies
0 dependencies · 4 peers
Pi manifest JSON
{
  "extensions": [
    "./src/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-recall

Fast full-text search and native session resume for Pi.

pi-recall is a hybrid TypeScript/Rust Pi extension. Pi supplies session parsing, the overlay, and native ctx.switchSession() handling; a small Rust N-API addon supplies the Tantivy index and ranking engine.

Prerequisites and install

pi install npm:@joshbochu/pi-recall

Installation uses a prebuilt addon for macOS (arm64, x64), Linux (x64, arm64, glibc) and Windows (x64). On any other platform the addon is compiled during installation, which requires Rust and Cargo; the installer says so rather than failing inside cargo.

For local development or installation from a checkout:

git clone https://github.com/joshbochu/pi-recall.git
cd pi-recall
npm install
pi install /absolute/path/to/pi-recall

Or try the checkout without installing it:

pi -e /absolute/path/to/pi-recall

Use

Open the Pi-native picker:

/recall
/recall staging deploy
/recall #codebase
/recall authentication #codebase

While it is open:

  • Type to search.
  • Up/Down changes the selected session.
  • Tab switches between the current folder and all projects.
  • Enter resumes through Pi's native session switch.
  • Escape closes the picker.

The header reports displayed results against the searchable corpus, such as 50 of 120 sessions. Force a clean rebuild with /recall-reindex; ordinary use automatically reconciles new, modified, and deleted sessions.

The model also receives one recall tool with search, list, and read actions, allowing it to retrieve prior Pi work without shelling out to a separate application.

Session tags

Tags belong to the current session and survive index rebuilds:

/recall tag #codebase #rust #search
/recall tags
/recall untag #search
/recall autotag
/recall autotag --all-untagged

Because those words are command names, use /recall search tag, /recall search tags, or similar when you want to search for the literal command word.

/recall autotag generates tags for the current session. --all-untagged finds every searchable session with no manual or generated tags, then shows an overlay containing the exact session count and model before making any calls. Escape cancels the progress overlay. Manual tags are never replaced by generated tags, and an explicitly removed tag is suppressed from later generation.

Auto-tagging uses Pi's currently selected model by default. To choose a model and tag count, create ~/.pi/agent/pi-recall/config.json:

{
  "autoTags": {
    "model": "provider/model-id",
    "minimum": 3,
    "maximum": 7
  }
}

The model must exist in Pi's model registry and have configured credentials. Auto-tagging sends a bounded excerpt of each selected session to that provider, so API usage and provider privacy terms apply. PI_RECALL_DATA_DIR relocates the durable tag/config directory; PI_RECALL_CONFIG_FILE can point at a specific config file.

Search behavior

The native search engine behaves as follows:

  • One Tantivy document is indexed per normalized user/assistant message, plus one metadata document for each tagged session.
  • Consecutive messages with the same role are joined before indexing.
  • Message content and tag text are searchable; session IDs, names, and paths remain stored metadata.
  • Tantivy's default QueryParser handles ordinary terms with OR semantics. Tag-text matches receive a 4x field boost.
  • #tag is an exact session filter. Multiple hashtags use AND, and remaining words still use the normal content/tag query (for example, authentication #codebase).
  • Multi-token queries also receive a 10x exact-phrase query joined with the base query using OR.
  • Search retrieves limit * 10 documents, groups them by session ID, and keeps one representative match per session. Cwd and exact-tag constraints become a native TermSetQuery, excluding irrelevant sessions before Tantivy collects its top documents.
  • When message scores are close, later message positions are preferred by messageIndex * 0.01.
  • Final session ordering multiplies relevance by 1 + exp(-age / 7 days), giving current sessions up to a 2x boost.
  • Snippets come from Tantivy's SnippetGenerator with a 200-character target.
  • The picker requests Recall's 50-session limit.

This is lexical search, not semantic retrieval. There is deliberately no prefix search, edit-distance typo matching, stemming, synonym expansion, or embedding model layered on top of the results.

Storage and incremental refresh

The native index lives under ~/.pi/agent/cache/pi-recall-tantivy-v3/. File signatures and Pi session summaries live in ~/.pi/agent/cache/pi-recall-v3.json. Set PI_RECALL_CACHE_DIR to place both in a different directory.

Tags live separately at ~/.pi/agent/pi-recall/tags-v1.json. This file is user data, not a cache, and is intentionally preserved by /recall-reindex.

The Pi adapter uses millisecond file timestamps, cache-version validation, atomic state writes, corrupt-index recovery, and deletion reconciliation.

Only user and assistant text is indexed alongside tag metadata. Thinking blocks, tool calls, and tool output are excluded to avoid duplicated command output.

Development

npm run check
npm run check:native
npm test

npm test rebuilds the native addon incrementally before running integration tests. Both Node and Bun load the generated N-API module.

See docs/architecture.md for the component boundaries, native bridge, data flow, and operational tradeoffs.

Publishing

Every push to main publishes a new package version via GitHub Actions (publish.yml). The workflow chooses the next patch version from the greater of package.json and the latest version on npm, runs the checks, builds and publishes one prebuilt addon package per platform (@joshbochu/pi-recall-native-<target>), publishes the root package with optionalDependencies pinned to those addons, then records release: vX.Y.Z and tag vX.Y.Z on main. Release commits are skipped so the version bump does not republish.

You can also run the workflow manually with Actions → Publish to npm → Run workflow.

Before the first automated release, configure a GitHub Actions trusted publisher on npm for @joshbochu/pi-recall and for each platform package (@joshbochu/pi-recall-native-darwin-arm64, -darwin-x64, -linux-x64-gnu, -linux-arm64-gnu, -win32-x64-msvc):

  • Organization or user: joshbochu
  • Repository: pi-recall
  • Workflow filename: publish.yml
  • Allowed action: npm publish

The publish job uses OIDC trusted publishing by default (scripts/publish-npm.mjs). Do not set an empty NODE_AUTH_TOKEN; that disables OIDC. Optionally set repository secret NPM_TOKEN when you need to create brand-new platform package names (trusted publishing cannot create a package that does not exist yet). After those packages exist and have trusted publishers, you can remove the token. Until a platform package is on npm, the root publish still proceeds and postinstall falls back to a local Cargo build for that platform.

npm run pack:platform -- <target> [cargo-target] builds one platform package locally into npm/<target>/. node scripts/next-version.mjs prints the next publish version, and npm run check:release verifies that any v* tag matches the package version and that publish.yml builds exactly the platforms listed in scripts/native-targets.mjs.

optionalDependencies is not committed: a lock file cannot reference a version that has not been published, so committing it would break npm ci. The workflow publishes the platform packages first, then runs npm run stamp:prebuilt (with --published-only in CI), so the published tarball only points at addons that exist.

Manual major/minor bumps still work: raise the version in package.json (and the lockfile) above the latest npm release, merge to main, and the workflow publishes that version instead of the next patch.

License

MIT. See THIRD_PARTY_NOTICES.md for required third-party notices.