Skip to main content

Local cross-harness search for agent threads

Project description

Threadlens

Threadlens logo

Threadlens is a local-first search tool for coding-agent sessions. It refreshes local agent session stores into a private SQLite FTS cache so you can answer questions like:

Where did I debug the Plunk OTP issue?

It does not upload transcripts. Raw agent session stores remain the source of truth; the Threadlens index is disposable and rebuildable.

Status

v1.0 is focused on reliable local keyword, prefix, and typo-tolerant search. There are no embeddings, hosted sync, background daemon, or team features.

Project Docs

  • Architecture: source adapters, SQLite cache, ranking, and Raycast boundary.
  • Contributing: local development, tests, and adapter rules.
  • Security: local data boundary and transcript safety.
  • Evaluation: public smoke tests and private acceptance evals.
  • Launch: launch copy, checklist, and positioning.

Install

Recommended: uv (or pipx)

uv can fetch a compatible Python for you, so this is the most reliable path:

uv tool install threadlens     # global install, on your PATH
uvx threadlens search "..."    # run without installing

Prefer pipx? pipx install threadlens works the same way.

npm

If you live in npm-land, the same CLI is published there. It runs the bundled Python source with your own interpreter, so it needs Python 3.10+ on PATH:

npm install -g threadlens
npx threadlens search "..."    # run without installing

From source

uv tool install .

Then use the installed CLI:

threadlens start
threadlens search "plunk otp"

If Threadlens is already installed from this checkout, refresh the installed tool after changes:

uv tool install --reinstall .

Verify the checkout:

make verify

Build release artifacts locally:

python3 -m pip install --upgrade build
python3 -m build

Initial Scope

  • In scope: local-only search, Codex JSONL, Claude Code JSONL, Cursor local SQLite records, Pi JSONL, Oh My Pi/OMP JSONL, Amp Code prompt history, Droid JSONL, OpenCode SQLite, custom JSONL source profiles.
  • Experimental: Cursor extraction quality depends on Cursor's local storage shape. Amp Code is supported from local prompt history when ~/.local/share/amp/history.jsonl exists. OpenCode is supported when its local database contains sessions.
  • Out of scope for v0: hosted sync, full app UI, embeddings, background daemon, team sharing.

Cursor's storage format is less stable than the JSONL-backed agents. The adapter is available in the default setup path, but should be treated as best-effort until validated against more real Cursor stores.

Usage

Set up the local cache:

threadlens start

start discovers built-in sources, explains the local-only SQLite index, indexes Codex, Claude, Cursor, Pi, OMP, Amp Code, Droid, and OpenCode when local sessions or prompt history exist, then prints commands to try next.

Search works as the main entrypoint too. If the index is empty, it runs first-time indexing before searching:

threadlens search "plunk otp"

Wrappers that need fast, side-effect-free search can disable first-time indexing:

threadlens search "plunk otp" --json --no-bootstrap

Refresh the local cache manually:

threadlens refresh

Fast first pass over recent work only:

threadlens refresh --days 14

After the first run, unchanged files are skipped automatically. Use --force to reindex matching files anyway.

Search it:

threadlens search "plunk otp"
threadlens search "monorepo api split" --source codex --limit 20
threadlens search "plunk otp" --cwd /path/to/project
threadlens search "plunk otp" --json

Inspect available sources:

threadlens sources

Current built-in source names:

  • codex
  • claude
  • cursor
  • pi
  • omp
  • amp
  • droid
  • opencode

Reset and rebuild:

threadlens refresh --reset

Use another database path:

threadlens refresh --db /tmp/threadlens.sqlite
threadlens search "cursor composer" --db /tmp/threadlens.sqlite

Add custom JSONL roots:

threadlens refresh --include ~/.omp/local/research

Add a named custom agent source:

threadlens sources add aider \
  --path "~/.aider/**/*.jsonl" \
  --session-key session.id \
  --message-key message.id \
  --role-key message.role \
  --text-key message.content \
  --timestamp-key createdAt \
  --cwd-key cwd \
  --title-key title \
  --resume-template "cd {cwd} && aider --resume {session_id}"

Then refresh and search it:

threadlens refresh --source aider
threadlens search "custom agent bug" --source aider

Source profiles are stored in the user config directory by default. Built-in source names are reserved, and custom source names become first-class result prefixes such as aider:session-id.

Inspect source health:

threadlens doctor

doctor reports source readability separately from index readiness. If local sessions are found but the SQLite index has no searchable messages, it reports not_ready and points to threadlens start.

Print a compact session brief:

threadlens brief codex:019...

Print a verified resume command when the source supports one:

threadlens resume codex:019...

Bundled Codex Skill

Threadlens ships a small Codex skill with the Python package. It teaches an agent when and how to use the CLI for local session retrieval without turning Threadlens into a memory product.

After installing the CLI, print the bundled skill path:

threadlens skill
threadlens skill --json

Copy or symlink that threadlens skill folder into the agent's local skills directory when the host supports filesystem skills. The Raycast extension does not package the skill; it stays a thin UI over the CLI.

Run query-to-session evaluation:

threadlens eval .threadlens/eval-local-10.json
threadlens eval .threadlens/eval-local-10.json --timings
threadlens bench .threadlens/eval-local-10.json --max-p95-ms 250

For a real acceptance gate, create a private eval file with known local session ids and remembered queries. The target is Recall@5 >= 90% with no unrelated target sessions in the top 5.

If you are using the repo-local development index, include --db:

threadlens --db .threadlens/index.sqlite eval .threadlens/eval-local-10.json --timings
threadlens --db .threadlens/index.sqlite bench .threadlens/eval-local-10.json --max-p95-ms 250

The committed custom-source fixture can be used for a public development smoke eval without private transcripts:

mkdir -p /private/tmp/threadlens-smoke
threadlens --db /private/tmp/threadlens-smoke/index.sqlite --config /private/tmp/threadlens-smoke/sources.json sources add demoagent \
  --path eval/custom-source.example.jsonl \
  --session-key session.id \
  --message-key message.id \
  --role-key message.role \
  --text-key message.content \
  --timestamp-key createdAt \
  --cwd-key cwd \
  --title-key title
threadlens --db /private/tmp/threadlens-smoke/index.sqlite --config /private/tmp/threadlens-smoke/sources.json refresh --source demoagent --force
threadlens --db /private/tmp/threadlens-smoke/index.sqlite --config /private/tmp/threadlens-smoke/sources.json eval eval/custom-source.eval.json

Notes

  • The cache defaults to a user data directory. Pass --db for repo-local or temporary databases.
  • Custom source profiles default to a user config directory. Pass --config for repo-local or temporary profiles.
  • Refresh tracks file mtime and size, so repeat runs skip unchanged session files.
  • Only user and assistant messages are indexed for Codex and Claude by default.
  • Tool output and system/developer instructions are skipped for Codex and Claude.
  • Pi, OMP, Droid, and OpenCode adapters index user/assistant text parts and skip thinking/tool blocks.
  • Amp Code indexes local prompt history from ~/.local/share/amp/history.jsonl; the observed local store does not include assistant transcripts, timestamps, or resumable session ids.
  • Obvious credential fields are skipped in generic and Cursor extraction.
  • Search results are grouped by session and include source, timestamp, cwd, source path, line, snippets, and score.
  • Use --cwd to restrict search to sessions whose recorded cwd is that directory or a child directory.
  • For harnesses with verified local resume syntax, results include a copyable resume command.
  • Custom source resume templates support {cwd}, {session_id}, and {source} with shell-quoted values.

Current resume hints:

  • Codex: cd <cwd> && codex resume <session_id>
  • Claude Code: cd <cwd> && claude --resume <session_id>
  • Pi: cd <cwd> && pi --session <session_id>
  • OMP: cd <cwd> && omp --resume <session_id>
  • Droid: cd <cwd> && droid --resume <session_id>
  • OpenCode: cd <cwd> && opencode --session <session_id>
  • Amp Code: not emitted yet; the observed local history file does not expose resumable session ids
  • Cursor: not emitted yet; the local CLI did not expose a session resume command

Raycast

The raycast/ folder contains a thin Raycast extension. It calls the CLI JSON interface and does not implement its own parsing, indexing, or ranking.

With the CLI installed, configure extension preferences as:

  • Threadlens Command: threadlens
  • Threadlens Args: empty
  • Working Directory: empty

Run in development mode:

cd raycast
npm install
npm run dev

Then open Raycast and run Search Agent Sessions.

To install it from source instead of only running the dev process, use Raycast's Import Extension command and select:

<repo>/raycast

If Raycast asks which command to import, choose threadlens.

From the repo root, the same TypeScript check is:

npm --prefix raycast exec -- tsc --project raycast/tsconfig.json --noEmit
NPM_CONFIG_CACHE=/private/tmp/threadlens-npm-cache npm --prefix raycast run lint

If Raycast shows Missing executable, remove the old imported extension from Raycast, quit and reopen Raycast, then run npm run dev again from raycast/. That error usually means Raycast is loading a stale imported command bundle.

If Raycast shows spawn threadlens ENOENT, set the Threadlens Command preference to the full path from command -v threadlens. The extension already adds common CLI install paths such as ~/.local/bin, /opt/homebrew/bin, and /usr/local/bin before spawning the CLI.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

threadlens-1.0.0.tar.gz (43.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

threadlens-1.0.0-py3-none-any.whl (33.7 kB view details)

Uploaded Python 3

File details

Details for the file threadlens-1.0.0.tar.gz.

File metadata

  • Download URL: threadlens-1.0.0.tar.gz
  • Upload date:
  • Size: 43.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for threadlens-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f116de8ddb7f4adb312f036e267d1df21ad64c7369316f0cb446ae4b30facae3
MD5 2fd9fa4fa13d71d939fc1c930fbd5c60
BLAKE2b-256 2e164148796c552ef589456292bcceb6daaf4561de4b8c23135ffe2458cbb44f

See more details on using hashes here.

File details

Details for the file threadlens-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: threadlens-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 33.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for threadlens-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bbbded244c92ef030cca6f37f9c3631544b64ef969b32721c7f5bf5d3b7e11e7
MD5 9226aadc5157dd1a5e03619cdd8b9d7d
BLAKE2b-256 616f4270d362d60b3a65aa81795af3d18690c6993f095f60afa610f47df8e3fc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page