Jevex builds a semantic index over Convex tables using Jev, storing AI classification answers as queryable indexed data so reads never call a model.
npm install @mbilskilets/jevexJevex builds a semantic index over Convex tables by sending rows to the Jev classification API when data changes and storing typed answers in an indexed table. Queries filter and sort by those answers using normal indexed reads, with no model calls at query time. It handles batching, caching, stale state, and reactivity automatically through a Convex trigger on your mutation.
Jevex stores Jev classification answers in an indexed Convex table keyed by question, label, and value. You define questions like 'is this a bug report?' using noul, choice, or score helpers, and Jevex writes answers when rows change via a convex-helpers trigger. Reads like feedbackJudge.top(ctx, 'kind', { label: 'bug' }) hit an index range and never call a model.
Jevex lets you define a semantic index over a feedback or tickets table with questions such as category classification and churn probability. When a new message is inserted, the trigger queues it for Jev, and once answered the onJudged callback fires so you can alert on high-churn scores or route to a queue. The demo inbox sorts messages into bugs, requests, billing, questions, and praise in under one second per message.
Jevex hooks into your mutation via a convex-helpers trigger and queues rows for Jev asynchronously so your transaction is never blocked on a network call. You define spam and abusive questions as noul scores, then query postJudge.top(ctx, 'spam', { min: 0.3, max: 0.7 }) to surface uncertain posts for human review while keeping clean posts live.
Jevex is not a vector similarity search tool. It runs structured Jev questions against row content on write and stores typed answers in an indexed table. You get classification, scoring, and multi-label filtering over large tables using Convex index ranges, which scales the same way on 100 rows as on 1 million rows.
No. Jevex stores Jev answers in a Convex table with an index on (index, question, label, value). Queries like feedbackJudge.top(ctx, 'churn', { min: 0.8 }) read an index range and return immediately. Model calls happen on write, triggered once per changed row, and results are cached so identical content is never sent to Jev twice.
The trigger that Jevex registers with convex-helpers does a few indexed reads, a hash check, and one insert inside the same transaction as your mutation. No network call happens in the transaction. If the state hash is unchanged the trigger returns early. New rows are queued and processed by a dispatcher that batches up to 20 rows per Jev request with a 100 ms debounce.
Jevex requires access to the Jev model, which is available through four providers: TypeSafe (TYPESAFE_API_KEY), Vercel AI Gateway (AI_GATEWAY_API_KEY), OpenRouter (OPENROUTER_API_KEY), or the Convex AI Gateway (JEV_PROVIDER=convex, no key needed). The Convex AI Gateway option only works on cloud deployments with the gateway enabled, not on a local backend.
Jevex exposes three question helpers: noul for a 0-to-1 probability score ('the user is likely to cancel'), choice for a typed enum label ('what is this feedback about?' with options like bug, feature, or billing), and score for an ordered categorical value ('how urgent is this?'). Each answer type is reflected in the TypeScript types returned by index.get and index.top.
Each batch carries a claim token tied to the row's content at the time it was queued. If the row is edited before Jev responds, the late answer is written to the cache but dropped for that row, and the new content is queued separately. The most recent edit always wins. Jevex also runs a cron that re-queues any rows whose batch disappeared without reporting back, such as after a backend restart.