jevsearch

Site search, ranked by Jev.

A keyword pass answers on the first keystroke, thenTypeSafe's Jev model re-ranks the top twenty by what the query meant. Searching all 109 pages of theTypeSafe docs, live:

npx shadcn@latest add https://raw.githubusercontent.com/kylemclaren/jevsearch/main/public/r/jev-search.json
hit@1, questions
73%
best of the six (Lunr)
31%
re-rank, uncached
255 ms
per 1,000 searches
$0.26

benchmarks

Results against six keyword libraries

query set ↗

hit@1 · all 41 queries

jev-search83%
Lunr41%
jev-search · lexical41%
Orama39%
Fuse.js39%
MiniSearch34%
FlexSearch27%
Pagefind17%

hit@1 · the 26 plain-English queries

jev-search73%
jev-search · lexical35%
Lunr31%
Fuse.js15%
MiniSearch15%
Orama12%
Pagefind8%
FlexSearch4%
every library, same corpus, same querieshit@3 by query type · latency per query
libraryhit@1hit@3mrrkeywordtyposintentmedianp95
jev-search 0.1.083%83%0.83100%100%73%255 ms296 ms
Lunr 2.3.941%59%0.53100%33%42%0.72 ms1.85 ms
jev-search · lexical 0.1.041%59%0.5192%67%42%9.38 ms16 ms
Orama 3.1.1839%54%0.4892%100%31%5.28 ms14 ms
Fuse.js 7.5.039%46%0.4383%100%23%242 ms605 ms
MiniSearch 7.2.034%49%0.4492%67%27%2.11 ms8.53 ms
FlexSearch 0.8.21227%34%0.3092%0%12%0.16 ms0.53 ms
Pagefind 1.5.217%29%0.2483%0%8%2.81 ms8.24 ms

41 labelled queries over every page of the TypeSafe documentation: all 109 pages, split at their headings into 443 documents. Each library indexes the same documents with comparable field boosts; Pagefind gets real HTML so its own heading weighting applies. Latency is measured in process on bun 1.4.2; jev-search includes the TypeSafe round trip with the cache off, so it is the cold number. Generated 2026-09-21 with jev-latest. Rerun it with bun run bench.

Pagefind requires every query term to appear, which is the right trade for a static keyword index and the wrong one for a question: it returns nothing at all for 12 of the 41 queries, and 12 of the 26 written as questions.

the lexical pass alone41%Level with Lunr at 41%, the best keyword library here. You lose nothing on the first keystroke.
with jev on top83%On questions written the way people ask them, hit@1 goes 35% → 73%.
what it costs255 msNetwork, once per uncached query, while the visitor already reads keyword results. Then it is cached.

Queries where only jev-search puts the right page first:

install

Adding it to a project

registry json
1

Add the block

npx shadcn@latest add https://raw.githubusercontent.com/kylemclaren/jevsearch/main/public/r/jev-search.json
pnpm dlx shadcn@latest add https://raw.githubusercontent.com/kylemclaren/jevsearch/main/public/r/jev-search.json
yarn dlx shadcn@latest add https://raw.githubusercontent.com/kylemclaren/jevsearch/main/public/r/jev-search.json
bunx --bun shadcn@latest add https://raw.githubusercontent.com/kylemclaren/jevsearch/main/public/r/jev-search.json

Component, hook, keyword index, server handler and API route. Set TYPESAFE_API_KEY; it stays on the server.

2

Feed it documents

{
  "id": "pricing",
  "title": "Pricing",
  "url": "/docs/pricing",
  "description": "What it costs and how to cap it.",
  "section": "Company",
  "content": "Usage is billed per request…",
  "keywords": ["billing", "cost"]
}

Or point the bundled indexer at Markdown: npx tsx scripts/jev-search-index.ts content/docs /docs, which splits each page at its headings.

3

Render it

import { JevSearch } from "@/components/jev-search"

export function Nav() {
  return (
    <JevSearch
      placeholder="Search docs…"
      suggestions={["how do I deploy", "what does it cost"]}
    />
  )
}

⌘K opens it. Plain shadcn tokens, so it inherits your theme; set --jev-accent to brand it.

how it works

The TypeSafe request and answer

typesafe api ↗

Twenty candidates, a yes/no question each and one choice across them, in a single request. Real exchange for what do I do when I get a 429, trimmed to three candidates.

POST https://api.typesafe.ai/v1/systemone

{
  "model": "jev-latest",
  "state": {
    "query": "what do I do when I get a 429",
    "candidates": [
      { "id": "c1",  "section": "Primitives",
        "title": "When to structure a question",
        "excerpt": "When it helps with clarity. When a question has multiple parts…" },
      { "id": "c10", "section": "SDKs",
        "title": "Retries",
        "excerpt": "Configure retries with RetryPolicy — attempt count, retryable statuses…" },
      { "id": "c11", "section": "API",
        "title": "Errors",
        "excerpt": "Errors use standard HTTP status codes with a JSON body…" }
    ]
  },
  "questions": {
    "c1": {
      "type": "noul",
      "instructions": "The user typed the search query above into a site search box.
                       Is candidate c1 (\"When to structure a question\") a page they
                       would be glad to land on for that query?",
      "criteria": {
        "true":  "The page answers, covers or is clearly about what the query is asking for",
        "false": "The page is off-topic, or only shares a word or two with the query"
      }
    },
    "best": {
      "type": "choice",
      "instructions": "Which candidate page best answers the user's search query?",
      "criteria": { "c1": "When to structure a question", "c10": "Retries", "c11": "Errors" }
    },
    "answerable": {
      "type": "noul",
      "instructions": "Does at least one candidate page answer the user's search query?"
    }
  }
}
{
  "model": "jev-1.13.0",
  "answers": {
    "c1":  { "type": "noul", "noul": 0.03 },
    "c2":  { "type": "noul", "noul": 0.02 },
    "c3":  { "type": "noul", "noul": 0.06 },
    "c10": { "type": "noul", "noul": 0.86 },
    "c11": { "type": "noul", "noul": 0.60 },
    "best": {
      "type": "choice",
      "choice": "c10",
      "confidence": 0.9,
      "probabilities": { "c10": 0.91, "c11": 0.09 }
    },
    "answerable": { "type": "noul", "noul": 0.72 }
  },
  "usage": { "input_tokens": 6264, "output_tokens": 560 }
}

The page that answers, Retries, was tenth on keyword score, below three pages Jev scored at 0.06 and under. It took 0.91 of the best-answer probability and moved to first.

Limits, costs, and what gets sent

What leaves your server. Each candidate's title, description and first 320 characters, over HTTPS. Nothing else, and never your API key.

Jev re-ranks, it does not retrieve. A page outside the top twenty cannot win. That ceiling is83% here, and Jev converts all of it.

Cost. 6,163 input tokens per uncached query, about $0.26 per thousand searches. Output tokens are free.

The cache is in memory. A thousand queries per process, no expiry. Serverless will miss it often.