Jev Inside the Database: pg_typesafe and duckdb-jev
Two extensions push typed Jev judgments into SQL itself, for Postgres and DuckDB. Batching cuts one benchmark 27x — but both are pre-1.0 and send row data to an external API.
Calling an external model from inside a database query sounds like an anti-pattern, and in most cases it is. But a narrow version of it — asking a typed decision model to classify, score or judge a row's text as part of a SELECT — turns SQL into a place where semantic filtering can live next to ordinary predicates. Two projects on the Awesome Jev radar build exactly that: a Postgres C extension and a DuckDB extension, both wrapping Jev, TypeSafe AI's typed decision model, in native database functions instead of a client-side library.
Both are early. pg_typesafe calls itself pre-alpha. duckdb-jev ships no installation instructions in its README at all. Read them as working prototypes with real, documented tradeoffs — not production database features.
Key Takeaways
- pg_typesafe batches requests and reports a 27x speedup: classifying 1,000 NYC 311 complaint strings one at a time took 23 seconds; batched, 0.86 seconds.
- Both extensions return typed SQL values, not text. pg_typesafe wraps Jev's Noul (probability), Choice (category) and Score (rubric) primitives as SQL functions; duckdb-jev maps them to ENUM, numeric and STRUCT types.
- Neither is production-ready by its own author's description. pg_typesafe is explicitly pre-alpha; duckdb-jev caps at 255 options and requires criteria to be constant at query-plan time.
- Every row's text leaves the database to reach TypeSafe's API — this is not a private, on-premise feature.
- Both cache identical requests within a session or process lifetime, so reruns and threshold tuning are far cheaper than the first pass.
pg_typesafe: SQL functions over Jev's three primitives
pg_typesafe (listing) is a PostgreSQL C extension, explicitly marked pre-alpha, that wraps TypeSafe's three decision primitives — Noul (yes/no probability), Choice (category selection) and Score (rubric-based evaluation) — as native SQL functions. It batches multiple text values into a single HTTP request rather than issuing one call per row.
The README's own benchmark is specific: classifying 38 unique resolution strings drawn from 1,000 NYC 311 complaints, calling typesafe_detect once per distinct text took 23 seconds; the batched typesafe_detect_many took 0.86 seconds — about a 27x improvement from batching alone, not from a faster model. Default batch size is 32 texts per request, with 4 concurrent HTTP requests, an 8 MB response cap, and retry logic with exponential backoff for HTTP 429/529 errors. It's tested against PostgreSQL 16–17 with libcurl 7.61+, keeps API keys out of SQL (environment variable or file-based config only), and revokes execute permissions from public users by default. Installation is make && make install followed by CREATE EXTENSION typesafe. It has 82 stars as of September 2026 and is MIT-licensed.
Read the benchmark for what it measures: HTTP round-trip savings from batching, not model accuracy or latency floor. It's the author's own single test, not independently reproduced.
duckdb-jev: typed by construction, not by validation
duckdb-jev (listing) takes a related but distinct approach for DuckDB. Rather than generating free text and then validating it against a schema, it constructs the correct SQL type from the start: jev_choice() returns an enum value from an option mapping, jev_score() returns an ordered rubric score as a double, jev_noul() returns a probability for yes/no questions, and jev_ask() combines multiple questions into a single struct result. The README frames this as "typed by construction, not by validation" — the distinction the whole Jev ecosystem is built around, covered in more depth in Typed Decisions vs Free Text.
Its worked example analyzes support tickets, extracting intent, severity and urgency fields as proper SQL types in the same query that reads the ticket text. The extension batches 16 rows per request and caches identical queries for the life of the process; a built-in usage function tracks request counts, cache hits and token consumption. Limits are concrete: a maximum of 255 options per jev_choice() call, and criteria must be constant, evaluated at query-planning time rather than per-row. Errors can be configured to return NULL instead of failing the whole query. It has 23 stars as of September 2026, is MIT-licensed, and — notably — its README gives no explicit installation instructions, which is worth flagging to anyone trying to adopt it today.
What neither one solves
Both extensions inherit the same structural limits any external-API-in-SQL approach has. Filtering on a Jev-derived value can't use a database index, so the underlying data still gets a full scan before or during the Jev call — pushing ordinary indexed predicates first, to shrink the candidate set, matters more here than in application code. Row content, whatever it is, travels to TypeSafe's servers, so neither is a fit for regulated or sensitive data without a compliance review. And because both are young, single- or small-team projects, expect breaking changes between versions; pin to a specific commit or release if you build on either.
Similar tradeoffs show up in pg-jev and llama-index-jev, an earlier article in this series covering a different Postgres extension and a LlamaIndex reranker — worth reading alongside this one if you're evaluating more than one database-adjacent Jev tool, since the ecosystem now has several similarly-named but independently-built options.
What to do next
- Reproduce pg_typesafe's batching benchmark on your own table shape before assuming 27x holds outside the NYC 311 dataset it was measured on.
- Check duckdb-jev's constant-criteria requirement against your query pattern — it won't work for per-row-varying questions, only fixed ones evaluated at plan time.
- Filter with ordinary indexed predicates before either extension sees a row, since Jev-based conditions bypass indexes entirely.
- Confirm your data-residency requirements allow sending row text externally before adopting either extension for anything beyond a local experiment.