Local Search CLI

local-search is a Rust/cargo CLI that answers structured queries over authorized local browser state and local indexes — Chrome history/bookmarks/open tabs plus qmd, ripgrep, and file indexes — returning the same structured result schema an agent would get from a hosted search API, with no dependency on hosted Exa, Firebase, or any external search service, and a hard requirement that every process and browser instance it spawns cleans up after itself.

This page owns the shipped search.local-browser workflow: "Query an authorized local browser and local indexes through structured, privacy-bounded results without requiring paid search services." It keeps the implementation connected to its original product and cleanup constraints without duplicating qmd, Exa, or Firebase. Source: Private Discord "Straight Fats", 2026-07-18 and 2026-07-20; Local Search v0.1.4 verification, 2026-08-10

Shipped State

Local Search is released as lsearch v0.1.4. The implementation lives in Kevin-Liu-01/Local-Search, the documentation site is lsearch.dev, and the same native Rust implementation is distributed through crates.io and npm.

Verification on 2026-08-10 against commit 8fbafc35 passed 31 locked Rust tests, Clippy across all targets and features with warnings denied, and the version smoke test (lsearch 0.1.4). The portable invocation contract lives at skills/productivity/local-search/SKILL.md in the product repository. The remaining wiki-side proof is a live Source Compile receipt showing that lsearch preserves provenance and leaves its managed browser clean.

Product Boundary

Local Search owns structured retrieval over the user's own local machine state: what the browser knows (history, bookmarks, open tabs, reading list, downloads) and what the local corpus knows (files, code, the wiki). It is the local, key-free, exfiltration-free substitute for hosted search when the answer already lives on the machine.

It does not own compiled-brain synthesis, live-web research, or cloud data. Ownership stays clean against the adjacent tools:

Adjacent owner Owns Local Search does NOT do
QMD - Local Wiki Search Engine Hybrid BM25 + vector + rerank over the compiled wiki corpus Re-implement qmd; it calls qmd as one retriever
Exa Agent Async structured public-web research, enrichment, outputSchema Fetch the live internet or spend on API calls
Firebase Ecosystem Hosted backend, auth, and cloud datastore Store or sync anything in the cloud
Browser Testing Skills Agent-driven browser automation (navigate, click, screenshot, scrape) Drive or automate a page; it reads authorized state only
Agent-Broom Standalone CLI / DevClean Portable agent process/artifact hygiene Own general dev cleanup; it reuses that model for its own instances

The Discord signal is explicit: "no need for exa or firebase etc. then same structured results and queries." The design goal is result-schema compatibility with hosted search so agents can swap the retriever without rewriting downstream code, while the data never leaves the machine. Source: Private Discord, 2026-07-18

Why This Is Not A Duplicate

  • vs qmd — qmd searches the compiled wiki and needs an embedding index it owns. Local Search searches volatile browser and filesystem state qmd never indexes (your open tabs, this morning's history, an un-indexed repo), and federates qmd in as one source rather than replacing it. Cost ladder in Capability Routing Map keeps qmd first for Kevin/wiki knowledge; Local Search is a new family: "authorized local machine state."
  • vs Exa — Exa is remote, paid, and public-web. Local Search is local, free, and private-corpus. Same structured results[] shape, opposite data boundary.
  • vs Firebase — Firebase is a cloud backend. Local Search stores nothing remotely; its only persistence is a local index cache and a process ledger.
  • vs agent-browser — agent-browser acts on pages; Local Search reads authorized browser state at rest (SQLite history/bookmarks, DevTools tab enumeration) and never mutates the page.

Architecture

The retrieval ensemble mirrors the Brain Source Fabric contract: ACL and privacy filters run before any candidate retrieval and cannot be widened by the planner, independent retrievers produce candidates, weighted reciprocal-rank fusion (Σ weight / (60 + rank)) combines them, source dedupe and per-source caps prevent one source dominating, then a reranker selects a bounded set with context expansion. Local Search is a local retriever adapter into that fabric, not a second brain. Source: Brain Source Fabric Retrieval And Context Compilation

Browser bridge modes

The browser connection is the novel part ("connects to a local browser like chrome"). Two modes, both read-only:

  1. Live-instance mode — attach to a running Chrome/Chromium over the DevTools Protocol (CDP) to enumerate open tabs, titles, URLs, and (with authorization) visible/selected text. Preferred when Chrome is already open; never launches a login flow. Reuses the Computer Use and Browser Automation Patterns / Browser Testing Skills connection posture (attach to existing profile), but only reads — no navigation, no clicks.
  2. Snapshot mode — read the browser's on-disk state (History, Bookmarks, Top Sites SQLite/JSON) from a copied profile snapshot so the live DB lock is never touched and nothing is written back. Works when Chrome is closed.

Engine-agnostic: Chrome is the default target, but the bridge is a trait so Chromium, Brave, Arc, and Firefox back ends can be added. Falls back to snapshot mode when no CDP endpoint is reachable.

Commands

# core query — structured results over all authorized local sources
local-search query "rust async cancellation" --json -n 10

# scope to specific sources
local-search query "onboarding flow" --source browser,tabs
local-search query "reticle border" --source wiki        # delegates to qmd
local-search query "TODO cleanup" --source files --path ~/repos/Kevin-Wiki

# browser-state primitives
local-search tabs                     # enumerate authorized open tabs (live mode)
local-search history --since 24h      # authorized history window
local-search bookmarks --tag design

# index management (local cache only)
local-search index build              # build/refresh the local index cache
local-search index status

# lifecycle / hygiene (ties to agent-broom)
local-search doctor                   # prove installed/configured/authorized/healthy
local-search ps                       # list local-search-spawned instances from the ledger
local-search clean                    # dry-run: orphaned instances/temp snapshots to reap
local-search clean --apply            # actually reap; explicit mutation gate

# MCP surface for agents
local-search mcp                      # expose query/get/status as MCP tools

Everything destructive is dry-run first. clean --apply and index rebuild --force are the explicit mutation gates, matching the Agent-Broom Standalone CLI safety model (dry-run unless --apply).

Structured Query And Result Schema

The contract is schema parity with hosted structured search so an agent can point the same code at Local Search or Exa. Queries and results are typed.

Query envelope

query: "rust async cancellation"
sources: [browser, tabs, history, bookmarks, wiki, files]   # default: all authorized
scope:
  paths: ["~/repos/Kevin-Wiki"]        # file/wiki scoping
  since: "24h"                          # temporal window for history/tabs
  profile: "Default"                   # browser profile (authorized only)
limit: 10
mode: hybrid                           # lexical | semantic | hybrid
rerank: true
output_schema: null                    # optional caller-supplied field projection
acl: authorized-local-only             # cannot be widened by the planner

Result envelope

query_id: ls_<stable-id>
results:
  - id: res_<stable-id>
    source: browser-history            # tabs | history | bookmarks | wiki | files
    title: "Cancellation - Tokio docs"
    url: "https://docs.rs/tokio/..."   # or file:// / qmd:// path
    snippet: "select! drops the other futures..."
    score: 0.83                        # fused score
    retriever_scores: {lexical: 0.7, semantic: 0.6, recency: 0.9}
    matched_terms: ["cancellation", "async"]
    accessed_at: 2026-07-21T09:12:00Z
    provenance: {retriever: browser, acl: authorized, private: true}
fusion: {method: weighted-rrf, k: 60, source_caps: {browser: 4, wiki: 4, files: 4}}
truncated: false
privacy: {excluded_sources: [], redactions: 0}
timing_ms: {plan: 3, retrieve: 41, fuse: 2, rerank: 18}

Every result carries source, score breakdown, provenance, and a privacy class — the same "source, date, confidence, privacy, why it was loaded" packet the brain fabric requires. --json emits this verbatim; the default human view is a compact table.

Rust / Cargo Packaging

Discord directive: "put local search on cargo and mention in readme." Source: Private Discord, 2026-07-20

  • Published as a crate on crates.io and installable with cargo install local-search; ship a prebuilt binary path too.
  • Workspace layout: local-search (bin/CLI) + local-search-core (retrieval, fusion, schema) + local-search-browser (CDP + snapshot bridge). Keep the browser bridge a separate crate so non-browser use compiles without it.
  • Minimal dependency surface by design — the whole point is no hosted search, so avoid pulling heavy cloud SDKs. Follow the low-dependency, zero-AI, high-star reference posture noted for port-whisperer (2,467 LOC, 3 deps, 864 stars) as the packaging bar to compare against. Source: raw/discord/straight-fats/tasks-signals-2026-07-21.md, item A4
  • README is a hard deliverable, not optional. It must document: install (cargo install), the authorization/consent model, every command, the query/result schema, the self-cleanup guarantee, the privacy boundary, and the doctor. The Discord instruction to "mention in readme" specifically covers the cleanup behavior.
  • Add the crate/repo to Project Inventory Ledger and, once healthy and bound, to Active Stack (What to Actually Use).

Instance And Process Self-Cleanup

Discord directive, repeated twice: "make sure local search cleans up after itself and instances." This is a first-class requirement, tied directly to Agent-Broom Standalone CLI / DevClean / Agent Operations Skills. Source: Private Discord, 2026-07-20

  • Any spawned child (a CDP session, a temporary profile snapshot copy, an index build worker, an MCP server) is recorded in a local instance ledger — same shape as Agent Broom's ~/.cache/agent-processes/ledger.tsv: repo root, cwd, PID, PGID, kind, port, purpose, command.
  • Cleanup on exit is guaranteed, not best-effort: RAII guards / Drop impls and a signal handler (SIGINT/SIGTERM) close CDP sessions, delete temp profile snapshots, and remove any port bindings on normal and abnormal exit.
  • Never kill a browser it did not launch. If it attached to the user's running Chrome, it detaches; it must never terminate the user's Chrome, editor, shell, or a shared MCP server. It only reaps its own ledgered instances.
  • local-search clean finds orphaned prior instances (stale ledger rows, dangling snapshot dirs) and reaps them — dry-run by default, --apply to act. It should be invokable by an agent, matching the request to make cleanup callable like Agent-Broom / port-whisperer.
  • Prefer SIGTERM before SIGKILL; delete only known-regenerable artifacts (snapshots, index cache). This reuses the conservative ownership-aware model rather than reinventing it. Source: Agent-Broom Standalone CLI Safety Model

Privacy Boundary

Local Search touches personal browser data, so the privacy contract is strict and non-negotiable.

  • Authorized local state only. It reads Chrome history/bookmarks/tabs only from profiles the user has explicitly authorized; first run requires an explicit consent step recorded locally. No implicit access to every profile.
  • ACL-first. Privacy and ACL filters run before retrieval and cannot be widened by the query planner — a query can only narrow scope, never escalate it. Source: Brain Source Fabric Privacy And Public Compilation
  • Never exfiltrate. No result, URL, snippet, or query is ever sent to any remote host. The crate makes no outbound network calls for search; the only network activity is the local CDP loopback socket to an already-running browser.
  • No secrets in flight. URLs and query strings stay local and are never placed in remote logs. Personal browser data is private: true by default in the result envelope and excluded from any public surface, matching Capture Ingest Protocol handling of private sources.
  • Read-only. Snapshot mode copies the DB rather than opening the live lock; live mode never navigates, clicks, or writes. The browser state is evidence, not a target.
  • Deletion/retention. The local index cache and instance ledger have a defined retention and a local-search index clear / clean --apply reset path.

Brain Retrieval Integration

Local Search plugs into the Brain Source Fabric as a local retriever adapter, not a standalone brain:

  • It participates in the ensemble alongside qmd (wiki), ripgrep (exact text), and recency/rarity retrievers; its output is fused by weighted RRF, deduped, source-capped, reranked, and context-expanded before reaching an agent.
  • Browser history/tabs become a recency + saved-curation signal the compiled brain otherwise lacks — "what was I just reading" — feeding the source taxonomy's saved curation and work-system state families.
  • In Capability Routing Map it is a new capability family: "authorized local machine state," routed after qmd for compiled-wiki knowledge and after rg for exact repo text, but before any hosted search when the answer is on the machine. Add a resolver row and a routing-map row on adoption.
  • It can register as an MCP server (local-search mcp) exposing query/get/status, exactly like qmd's MCP surface, so any harness can call it.

Capability State

Per the independent state axes in Full Corpus Workflow and Capability Program — these must never collapse into one boolean:

Axis Target end state Notes
Decision adopt Shipped at v0.1.4; keep the wiki integration behind a live receipt
Presence (installed) distributed crates.io, npm, and prebuilt/native paths documented at lsearch.dev
Configuration configured Authorized profile(s) selected; index cache location set
Authentication authorized Explicit local consent to read named browser profiles; no external auth
Health healthy via local-search doctor CDP reachable or snapshot readable; qmd/rg present; ledger writable
Binding workflow-bound to search.local-browser Source Compile live-query receipt remains the final wiki integration proof
Authority read-only + private-data + local-write (cache/ledger only) No external-write, no spend, no destructive default
Freshness current Version pin; recheck on Chrome schema or CDP changes
Version / rollback pinned crate version; cargo install --version downgrade path README documents pin + rollback + uninstall + cache clear

Proof And Doctor Requirements

local-search doctor and the test suite must prove, before the tool is called active:

  • Doctor checks: CDP endpoint reachable (live mode) or profile snapshot readable (snapshot mode); qmd and ripgrep present on PATH; index cache writable; instance ledger writable; a canned query returns a well-formed result envelope.
  • Fixtures: a known browser snapshot (fixed history/bookmarks) with a query whose expected top results are asserted; a wiki query that must delegate to qmd; a file query that must match rg output; a private-source query that must be excluded from any public projection.
  • Cleanup proof: spawn an instance, kill it abnormally (SIGKILL the parent), and assert the ledger shows no orphan after clean --apply and that no temp snapshot dir survives. This is the load-bearing test for the twice-stated cleanup requirement.
  • Privacy proof: assert zero outbound network requests during a query (network sandbox / request recorder); assert a non-authorized profile is never read; assert query strings never appear in any remote sink.
  • Schema proof: golden-file test that the JSON result envelope matches the documented schema and stays Exa-swap-compatible.
  • Rollback proof: install a pinned version, downgrade, and confirm the index cache is version-tolerant or cleanly rebuilt.

Original Phased Build Record

  1. Schema + core (no browser). Define the query/result envelope, the retriever trait, and fusion (weighted RRF + dedupe + source caps). Wire the file/rg retriever and delegate the wiki source to qmd. Ship query --source files,wiki end to end. Prove schema golden files.
  2. Browser bridge — snapshot mode. Read a copied Chrome profile snapshot (History/Bookmarks) read-only. Add history, bookmarks, and --source browser. Prove the browser fixture query.
  3. Browser bridge — live mode. Attach to a running Chrome over CDP; enumerate tabs; add tabs and live history. Attach-only, read-only, detach cleanly. Prove no navigation/mutation.
  4. Self-cleanup + ledger. Add the instance ledger, RAII/Drop + signal-handler cleanup, ps, and clean [--apply]. Prove abnormal-exit cleanup. This gates any wider use.
  5. Privacy + ACL hardening. Enforce consent gate, ACL-before-retrieval, zero-exfiltration test, and private-source exclusion. Prove privacy fixtures.
  6. Cargo publish + README. Workspace crates, cargo install, prebuilt binary, and the required README (install, consent, commands, schema, cleanup, privacy, doctor). Add to Project Inventory Ledger.
  7. Doctor + MCP + routing. Ship doctor, local-search mcp, register the retriever in Brain Source Fabric, and add the capability-routing-map + resolver rows. Bind to search.local-browser, then move toward active in Active Stack (What to Actually Use).

This sequence records the original implementation contract. The v0.1.4 release has completed the product build; future work should extend the product repository and use this list only to audit cleanup, privacy, and integration regressions.


Timeline

  • 2026-08-10 | Verified the shipped v0.1.4 release at commit 8fbafc35: 31 locked Rust tests, Clippy with warnings denied, and the version smoke test passed. Recorded the GitHub, lsearch.dev, crates.io, and npm distribution surfaces and narrowed the remaining work to one live Source Compile integration receipt. Source: Local Search repository and release surfaces, 2026-08-10
  • 2026-07-21 | Created the implementation-ready spec for the local-search CLI: authorized-local-only structured retrieval over Chrome/browser state + qmd/ripgrep/file indexes as a key-free replacement for hosted Exa/Firebase, Rust/cargo packaging with a required README, guaranteed instance self-cleanup tied to Agent-Broom Standalone CLI, ACL-first privacy boundary, brain-fabric retriever integration, capability-state and doctor requirements, and a seven-phase build order. Owner for the search.local-browser workflow candidate. Source: raw/discord/straight-fats/tasks-signals-2026-07-21.md; Private Discord "Straight Fats", 2026-07-18 and 2026-07-20
  • 2026-07-20 | Discord: "put local search on cargo and mention in readme, make sure local search cleans up after itself and instances." Established cargo publishing, README, and instance self-cleanup as hard requirements; cleanup ties the project to Agent-Broom/DevClean process hygiene. Source: Private Discord "Straight Fats", 2026-07-20
  • 2026-07-18 | Discord: "new project: local search cli that connects to a local browser like chrome. no need for exa or firebase etc. then same structured results and queries." Original project signal; edit on 07-18 23:47 added "structured results and queries, no exa/firebase," strengthening the local-search owner. Source: Private Discord "Straight Fats", 2026-07-18