Local Search CLI
lsearchis an open-source Rust CLI that lets a shell agent search the web, read pages and act on sites through a Chrome profile the user chooses, with no hosted browser and no search API key.
Facts
- Site: https://localsearch.kevinliu.studio returned 200 on 2026-10-30, served by Vercel as a static Next.js export.
/docsalso returned 200.lsearch.kevinliu.studioandlocal.kevinliu.studioreturn 301 to it. Kevin choselocalsearchas the primary hostname on 2026-10-08. Source: curl -sI, 2026-10-30; site/next.config.ts; ~/repos/outputs/cost-domain-20261008/recovered-conversation.md - Old domain: https://lsearch.dev and www.lsearch.dev return 308 to the site. Kevin turned off its auto-renew on 2026-10-08. The registration expires 2027-08-01, and old links stop redirecting after that. Source: curl -sI, 2026-10-30; ~/repos/outputs/cost-domain-20261008/audit.md
- Repo: https://github.com/Kevin-Liu-01/Local-Search, public, 16 stars, 1 fork. The GitHub homepage field still says lsearch.dev. Source: gh repo view, 2026-10-30
- License: MIT. Source: LICENSE; gh repo view, 2026-10-30
- Packages: crates.io
local-search0.3.0 and npm@kevinliu01/localsearch0.3.0, both published 2026-10-14. The npm package runs apostinstallscript that installs the pinned crate into a package-local Cargo root, so it needs Rust as well as Node 18+. npm adds a fourth alias,localsearch. Source: docs/releases/0.3.0.md; AGENTS.md; npm/localsearch/package.json - Stack: Rust 2024 edition with Clap, Tokio, tokio-tungstenite and serde.
src/browser/cdp.rsis a minimal hand-written Chrome DevTools Protocol client.unsafecode is forbidden, Clippyallandperflints deny, and the release profile optimizes for size. The arm64 macOS binary is 1,355,744 bytes. CI pins Rust 1.98.1. The site uses Next.js 16.4, React 19.3, Tailwind 4 and Paper shaders. Source: Cargo.toml; AGENTS.md; .github/workflows/ci.yml; site/package.json; docs/releases/0.3.0.md - Hosting: Vercel project
local-searchwith rootsite. The 2026-10-08 audit found no environment variables on it. An Ignored Build Step skips builds unlesssite/,docs/or the rootSKILL.mdchanged. Source: ~/repos/outputs/cost-domain-20261008/audit.md - History: first commit 2026-07-19, last commit on main 2026-10-16, 76 commits on origin/main. Source: git log, 2026-10-30
- Versions in Cargo.toml: 0.1.0 (2026-07-19), 0.1.1 (07-20), 0.1.2 (07-30), 0.1.3 (08-02), 0.1.4 (08-04, tag
v0.1.4, the only git tag), 0.2.0 (09-25), 0.2.1 (10-08), 0.3.0 (10-14). Source: git log of Cargo.toml; git tag - Status: live. 0.3.0 is the current release. Kevin posted about the project on X on 2026-10-14. Source: docs/releases/0.3.0.md; raw/x-bookmarks/enriched/2110466508598260182.json
What it does
lsearch connects an agent's shell command to a real Chrome or Chromium profile on the user's machine. The browser loads the site and keeps its own cookies. The agent gets compact JSON or readable text back. Source: SKILL.md; README.md
The user picks one of two connections, and the choice is saved: Source: README.md; AGENTS.md
lsearch connect --existingattaches to everyday Chrome (version 144+) after Chrome's own approval prompt. On macOS and Linux a helper keeps that one approved connection and leases it to later commands over private Unix sockets.lsearch connect --manageduses a separate persistent profile. The user signs into the sites the agent needs there.
A lost connection is an error. lsearch never switches to another browser or launches one on its own. lsearch disconnect ends access without closing Chrome. Safari signed-in control is not supported. Source: README.md; AGENTS.md; SKILL.md
The command surface: Source: src/cli.rs; README.md
| Need | Commands |
|---|---|
| Search Google, Bing, Brave or DuckDuckGo | lsearch "query" --engine bing --json |
| Read a page as Markdown, text or JSON | read |
| Pull repeated fields, map links | extract, map |
| Navigate and act on a page | open, back, forward, reload, snapshot, then click, fill, type, press, hover, select, scroll, wait; eval as an escape hatch |
| Request with the browser's cookies | request (runs fetch in a temporary tab at the target origin) |
| Capture | screenshot, pdf, mhtml, html, record (HAR-shaped CDP events, capped at 4,096 events or 8 MiB) |
| Session control | connect, disconnect, launch, tabs, cookies (values redacted by default), profile, policy |
| Health | doctor, cleanup, update-check |
Search takes an engine (default Google), a result limit (default 10), a snippet cap (default 120 characters), a cache TTL (default 300 seconds) and --with-content to read each result page. It has no domain, time-window or output-schema options. lsearch is the preferred binary, and local-search and local-browser are compatibility aliases. Source: src/cli.rs; Cargo.toml
Output contract. Success prints {"ok":true,...} on stdout. Failure prints {"ok":false,"error":{"code","message"}} on stderr and exits nonzero. Piped output and --json are compact JSON. Progress stays on stderr. Search results carry rank, title, url, domain, snippet, engine metadata and a blocked flag. Source: AGENTS.md
Search cache. Cache entries are local and keyed to the connected browser, the engine and the exact query. Every cache hit still checks that the browser is connected. Source: AGENTS.md
Agent boundaries (0.3.0). Named profiles separate logins: everyday is existing Chrome, agent is the managed profile, and profile create adds more. Each profile keeps site block and allow lists. Rules are checked before navigation, after redirects and before any read of the current page, and a blocked site returns site_blocked. policy tabs own limits an agent to tabs lsearch opened or the user granted. chrome:// and other browser pages are always off limits. These rules are guardrails for a trusted agent. A separate profile is the isolation boundary. Source: docs/releases/0.3.0.md; README.md; SECURITY.md
Cleanup. lsearch cleanup inspects by default. --kill stops managed browser listeners and clears stale markers but keeps profile cookies and history. Normal shutdown calls Browser.close. SIGKILL needs --force. Source: AGENTS.md; src/cli.rs
Benchmarks. The July 21, 2026 run (12 queries at 3 and 10 results, 24 requests per provider) recorded a 148.7 ms overall median for lsearch (384.5 ms cold, 6.5 ms cached) against Exa 501.9 ms, Brave Search 322.0 ms, Tavily 1,184.4 ms and Firecrawl 1,520.8 ms. lsearch used 53.4 median tokens per result, but providers returned different snippet lengths. The repo says the run is neither an uncached speed ranking nor a quality comparison. The September 29 run capped every provider's snippet at 120 characters: lsearch 0.2.0 on Bing used 54.7 tokens per result against 68.5 to 73.5 for the hosted APIs. Source: README.md; benchmarks/search-2026-09-29.md
How it changed from the first spec
The origin was a Discord note on 2026-07-18: "local search cli that connects to a local browser like chrome. no need for exa or firebase etc. then same structured results and queries." On 2026-07-20 Kevin added: put it on Cargo, mention it in the README, and make it clean up after itself and its instances. Source: Private Discord "Straight Fats", 2026-07-18 and 2026-07-20
The wiki spec of 2026-07-21 planned retrieval over browser history, bookmarks and open tabs, merged with qmd and ripgrep through weighted reciprocal-rank fusion, with query, history, bookmarks, index and mcp commands. The shipped CLI has none of those commands. It searches the live web through public engines inside the chosen profile, then reads and acts on pages. The spec's privacy and cleanup demands carried over as explicit browser choice, loopback-bound managed endpoints, redacted cookies, site policies and the cleanup command. Source: Kevin-Wiki local-search-cli page, 2026-07-21 spec revision; src/cli.rs at 0.3.0
Ownership against nearby tools:
- QMD - Local Wiki Search Engine stays the route for compiled-wiki retrieval.
lsearchdoes not index the wiki. - Exa Agent, Brave Search, Tavily and Firecrawl are hosted, keyed search APIs.
lsearchreturns the same kind of ranked result from a local browser with no key and no metered bill. - Firebase Ecosystem plays no part.
lsearchstores nothing remotely. - Agent Browser -- Browser Automation for Agents is Kevin's default browser automation surface.
lsearchoverlaps on page actions. Its own ground is compact search and read output and reuse of a signed-in profile under site policies.
Source: README.md; AGENTS.md; Capability Routing Map
Kevin's rules and decisions
The repo's AGENTS.md lists these as non-negotiable: Source: Local-Search AGENTS.md
- The local browser is the product boundary. Do not add a hosted browser or a paid search API.
- Output stays compact and stable. A JSON shape change is a public API change.
- Use the least browser authority. Redact cookie values. Never put credentials, signed-in content or private screenshots into fixtures, logs or commits.
- Browser choice is explicit and sticky. Disconnection is never permission to find or launch another browser.
- Automation must not steal focus. Searches and reads run in background tabs.
- Stay native and small. Avoid dependencies added for convenience.
- Performance, token, size and provider claims must match committed benchmark output with its date and method.
- Do not bypass CAPTCHAs, engine checks or access controls. Report
blockedhonestly. - Publishing to crates.io, pushing a branch, changing production DNS or deploying the site needs Kevin's explicit approval.
Decisions recorded on 2026-10-14: any-tab access stays the default, any command may loosen a rule, and there is no interactive confirmation for policy changes. Kevin rejected grid lines and spacers in the social card, which is now drawn from the hero in site/lib/social-scene.ts. Commits use Kevin's personal git identity with a Co-Authored-By line, PRs are rebase-merged, and pushes need Kevin's OK in chat. Source: Claude memory personal-repos-domains-ci-20261014
Wiki-side rules: new work extends this repo instead of building a second wiki-local search CLI. Results that enter source.capture keep URL, title, excerpt, capture time, query and connector provenance. Every process, page, port, profile and temp directory gets deterministic teardown, and Agent Broom is the cleanup fallback and doctor. Source: Kevin-Wiki local-search-cli page, 2026-08-10 and 2026-08-12 The shipped CLI has its own cleanup command and does not call Agent Broom, which the Agent-Broom Standalone CLI spec had planned. Source: git grep of Local-Search, 2026-10-30
Working state
- Repo:
~/repos/Local-Search. Localmainis three commits behind origin/main (the 2026-10-14 social card fix and the 2026-10-16 GA4 and icon commits). The local branchescodex/consolidate-studio-domains,feat/agent-boundaries,fix/social-card-cache,release/0.3.0andrelease/0.3.0-recordwere all rebase-merged as PRs #11 and #14 to #17.codex/consolidate-studio-domainsis still checked out in~/repos/outputs/cost-domain-20261008/Local-Search. Dependabot PRs #18 and #20 are open. Source: git branch, git worktree list and git cherry, 2026-10-30; gh api pulls, 2026-10-30 - Agent guides:
AGENTS.mdat the root and nestedSKILL.mdfiles insrc/,src/bin/,src/browser/,tests/and thesite/folders. The rootSKILL.mdis the end-user command reference for agents and the only agent contract. No local-search skill is installed in Kevin-Wiki,~/.claude/skillsor~/.agents/skills. Source: AGENTS.md; ls of skill folders, 2026-10-30 - Release evidence:
docs/releases/anddocs/verification.md. Launch media and post drafts:docs/launch/. Benchmarks:benchmarks/. Source: AGENTS.md; docs/launch/README.md - Releasing: Cargo credentials work.
npm publishneeds Kevin's web 2FA, so the publish runs in his terminal. A card redesign must also touchapp/opengraph-image.tsxandapp/twitter-image.tsx, or cached previews stay old. Force-pushing a PR branch breaks the Vercel preview skip step with "bad object". Source: Claude memory personal-repos-domains-ci-20261014 - Memory and records: the claude-of-tanks project memory
personal-repos-domains-ci-20261014.mdholds the 2026-10-14 domain, CI and release notes.~/repos/outputs/cost-domain-20261008/holds the domain move audit. No RESUME or handoff file mentions the project. Source: search of ~/.claude/projects//memory and ~/gt/RESUME.md, 2026-10-30 - Installed copy:
~/.cargo/bin/lsearchreportslsearch 0.1.4. It was installed from the local checkout withcargo install --pathand is dated 2026-09-25. Source: lsearch --version; ~/.cargo/.crates.toml, 2026-10-30
Related projects
- private page: on 2026-10-08 Kevin moved Local Search and Sigil UI from their own domains to kevinliu.studio subdomains, kept the PortfolioMon Showdown portfolio at www.kevinliu.studio, and turned off auto-renew for lsearch.dev, sigil-ui.dev and kevinliu.biz. He kept loooop.dev for Loop. Source: ~/repos/outputs/cost-domain-20261008/audit.md and recovered-conversation.md
- PortfolioMon Showdown: on 2026-10-30 Kevin put Local Search in the 18-project roster of "my kevinliu.studio domain projects" for the portfolio redesign. The portfolio's
llms.txtlinks the site. Source: Claude memory portfolio-redesign-bar, 2026-10-30; PortfolioMon-Showdown public/llms.txt - private page reused the Local Search site's token system (Manrope, framed sections, hatch bands, reticles, one teal accent) on 2026-09-25. Source: private page
- Loop's refresh worker searches with the hosted Brave Search API, the kind of keyed API
lsearchavoids. Both sites got GA4 with Consent Mode defaults on 2026-10-16, the same day as 14 other repos of Kevin's. Source: Loop README.md; git log of each repo, 2026-10-30 - Wiki Brain Operating Model lists Local Search CLI as one of its Agent OS projects. private page lists the
search.local-browserworkflow, which this page owns, as proposed. Source: Wiki Brain Operating Model; private page
Open items
- The wiki integration still lacks a live Source Compile receipt showing
lsearchkeeps provenance and leaves its managed browser clean. Thesearch.local-browserworkflow was written for the history and bookmark retriever, so it needs restating aroundsearchandread. Source: Kevin-Wiki local-search-cli page, 2026-08-12; src/cli.rs - The GitHub homepage field points at lsearch.dev, which stops redirecting after 2027-08-01. Source: gh repo view, 2026-10-30; ~/repos/outputs/cost-domain-20261008/audit.md
- The installed binary on Kevin's Mac is 0.1.4, two releases behind.
- A reply in the 2026-10-14 launch thread says Safari works out of the box. SKILL.md and the code say Safari signed-in control is unsupported. Source: raw/x-bookmarks/enriched/2110466508598260182.json; SKILL.md
- npm 11.19 warned that the bridge's
postinstallscript is not inallowScripts. A future npm that blocks it would leave the npm install without its binary. Source: docs/releases/0.3.0.md
Timeline
- 2026-11-03 | Rechecked: localsearch.kevinliu.studio answered 200; lsearch.kevinliu.studio and local.kevinliu.studio answered 301 and lsearch.dev 308 to it. The repo had 16 stars and no commits since 2026-10-16. Source: curl -sI, gh repo view and git log origin/main, 2026-11-03
- 2026-10-30 | Rewrote the page from the repo, release notes, memories and live checks. The shipped product is a local browser API for agents (web search through Chrome, page reads, page actions, site policies), not the history and bookmark retriever the 2026-07-21 spec described; the spec commands
query,history,bookmarks,indexandmcpdo not exist in 0.3.0. The wiki's earlier note that the agent contract lives atskills/productivity/local-search/SKILL.mdin the product repo is wrong: no such path exists in the repo's history, and the contract is the repo-rootSKILL.md. Site https://localsearch.kevinliu.studio returned 200; lsearch.dev returns 308 to it. Source: src/cli.rs; git log; README.md; curl -sI, 2026-10-30 - 2026-10-16 | GA4 with Consent Mode defaults and favicon, apple-touch and manifest icons added to the site. Source: Local-Search commits
bcddd53,46756a0 - 2026-10-14 | Released 0.3.0 on crates.io and npm: named profiles, per-profile site block and allow lists, and own-tab mode. 108 Rust tests and strict Clippy passed. The URL move merged as PR #11, the 0.2.1 release commits were rebased and pushed, and agent boundaries merged as PR #14. Kevin posted about the project on X with the Chrome demo video and a three-post self-thread (16 likes, 10 replies and 9 bookmarks by 2026-10-18). Source: docs/releases/0.3.0.md; gh api pulls; Claude memory personal-repos-domains-ci-20261014; X/@kevskgs, 2026-10-14
- 2026-10-08 | Released 0.2.1 (readiness and transport fixes, 87 Rust tests). Attached localsearch.kevinliu.studio as the primary hostname, with lsearch.kevinliu.studio and local.kevinliu.studio as 301 aliases and lsearch.dev as a 308 redirect, and turned off lsearch.dev auto-renew. Added an Ignored Build Step to the Vercel project. Source: docs/releases/0.2.1.md; commit
6b304a1; ~/repos/outputs/cost-domain-20261008/audit.md - 2026-09-29 | Published the September benchmark with a shared 120-character snippet cap and a new Chrome demo launch kit. No posts were published from the kit. Source: benchmarks/search-2026-09-29.md; docs/launch/README.md
- 2026-09-25 | Released 0.2.0: explicit choice of existing Chrome with approval or a managed profile, one approved connection reused across commands, and session-scoped search caches. Source: docs/releases/0.2.0.md
- 2026-08-12 | Re-verified the shipped checkout at
8fbafc35: 31 tests pass, strict all-target/all-feature clippy passes, and the binary reportslsearch 0.1.4. The remaining source-compile live-browser receipt is still an integration proof, not a product-build gap. Source: local verification - 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-08-10 | Reconciled the canonical owner with the standalone product: v0.1.4 is published on crates.io and npm; 31 tests and strict clippy pass; the binary reports the expected version. Removed the stale “not implemented” claim. Source: Local-Search commit
8fbafc35; local verification - 2026-08-10 | Promoted the repeated Discord instructions into one project owner and bound it to the source, project, and cleanup loops. Source: Private Discord capture, 2026-07-18 and 2026-07-20
- 2026-07-27 | A Twitterbot audit of local-search-xi.vercel.app found that robots already allowed the crawler and production still served old metadata, so the stale card came from deployment or social cache. Versioned image URLs became the fix. Source: SEO + GEO, 2026-07-27
- 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-browserworkflow 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-20 | Added packaging and self-cleanup requirements. Source: Private Discord capture, 2026-07-20
- 2026-07-19 | First commit: "feat: build local browser search cli". Source: Local-Search commit
a6cf609 - 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
- 2026-07-18 | Origin instruction: local browser-connected search with structured queries and results, without requiring Exa or Firebase. Source: Private Discord capture, 2026-07-18