you type
Ask your database a real question.
PutWHERE jev(people, 'could work from home')in a query: Postgres runs the SQL, Jev judges the rows, you get the table. From the CLI, from Go, TypeScript or Python, or from an agent over MCP. Works on any Postgres you can already connect to, no extension required.
examples · people
you get
Rows, plus what it cost
install
Install it, then type jevql
First launch asks for a database URL and a TypeSafe key and saves them to ~/.config/jevql/env. Or set DATABASE_URL and TYPESAFE_API_KEY like any psql user.
functions
One family of functions
jev(p, 'condition' [, 0.7])A calibrated probability against a threshold. Works in WHERE, also as
NOT jev().jev_prob(p, 'condition') → 0..1jev_score(p, 'q', ARRAY['lo','mid','hi']) → weighted leveljev_choice(t, 'which team?', ARRAY['billing','technical'])Works with GROUP BY and count(*).
Send fewer columns with jev((name, bio), '…'). Anything without jev_* passes straight through, so it doubles as a plain psql.
sdks
The same engine, from your code
client, _ := jevql.New(ctx, jevql.Options{DatabaseURL: os.Getenv("DATABASE_URL")})
defer client.Close(ctx)
rows, err := client.QueryMaps(ctx, `
SELECT name, jev_prob(people, 'could work from home') AS p
FROM people WHERE country = 'PT'
ORDER BY p DESC LIMIT 5`)In process: go get github.com/kylemclaren/jevql/sdk/go. Same parser, cache and client as the CLI.
import { Jevql } from "jevql"
const db = new Jevql() // bundled engine, reads DATABASE_URL and TYPESAFE_API_KEY
const tickets = await db.queryObjects(`
SELECT id, subject FROM tickets
WHERE jev(tickets, 'is about billing') AND status = 'open'`)npm i jevql. The engine ships inside the package; nothing else to install. Point it at a shared jevql serve with { url }.
from jevql import Jevql
with Jevql() as db: # bundled engine; Jevql(url=...) for a shared one
for row in db.query_dicts("""
SELECT title FROM movies
WHERE jev(movies, 'a safe pick for a first date')"""):
print(row["title"])pip install jevql. Standard library only, engine included. Same embedded-or-remote choice.
mcp
Agents get the same superpower
jevql mcp is a Model Context Protocol server. Claude, Cursor or any MCP client can ask your database real questions: the query tool runs SQL with jev() in it, explain prices a query before it runs,judge scores rows the agent already holds, and list_tables / describe_table let it find its way around. Read-only by default.
# local, on stdio
claude mcp add jevql -- jevql mcp
# a shared node over HTTP
claude mcp add --transport http jevql https://your-node.fly.dev/mcp \
--header "Authorization: Bearer $JEVQL_TOKEN"Reads DATABASE_URL and TYPESAFE_API_KEY from your shell, like the CLI.
# Codex CLI
codex mcp add jevql -- jevql mcp
# ChatGPT: Settings → Connectors → add an MCP server
# URL https://your-node.fly.dev/mcp
# Auth Bearer <your JEVQL_TOKEN>ChatGPT only speaks to remote servers, so point it at a node. Codex runs the local one.
// .cursor/mcp.json (project) or ~/.cursor/mcp.json (global)
{
"mcpServers": {
"jevql": { "command": "jevql", "args": ["mcp"] }
}
}Enable it under Settings → MCP. Ask Cursor to "list the tables and find open tickets that sound angry".
// opencode.json
{
"mcp": {
"jevql": { "type": "local", "command": ["jevql", "mcp"], "enabled": true }
}
}Restart OpenCode; the five tools show up under jevql_*.
WHERE jev(t, '…') and comes back as rows.Read before pointing it at real data
Row contents go to TypeSafe. Every column of the judged alias is sent over HTTPS. Narrow it with jev((name, bio), …) or --columns.
It scans everything your SQL filters let through. Put cheap predicates first. --explain shows the collect SQL, row count and cost with no API call; --max-rows aborts before HTTP.
Not an extension. jev() exists only inside this CLI and its SDKs. Apps sending it straight through JDBC or psycopg will get "function does not exist".
The cache is a local sqlite file. Keyed by model, question and canonical row JSON. Mode 0600, no expiry. \cache clear or --no-cache.