# pg-jev: plain-language conditions inside a PostgreSQL query

> The jev PostgreSQL extension lets you filter, rank and classify rows with an English condition such as 'the customer is angry', evaluating each row against TypeSafe's Jev model instead of a generated answer. It suits an analyst who wants to explore unstructured columns without building a vector pipeline, and it needs a superuser, plpython3u and a TypeSafe API key, so it does not run on a managed Postgres.

**realZachi/pg-jev** — Ask your Postgres tables questions in plain language. A PostgreSQL extension powered by TypeSafe's Jev.

- Repository: https://github.com/realZachi/pg-jev
- Website: https://pgjev.com
- Stars: 1,268 · Forks: 105
- Language: Shell
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/realzachi-pg-jev

## The query shape, and what the function is

The pitch is that you write the condition the way you would say it and Postgres does the rest. The extension lets you filter, rank and classify rows with plain-language conditions, and every row is judged by TypeSafe's Jev, a System One model that returns calibrated probabilities instead of generated text, with no index, no embeddings and no vector column. The functions are ordinary SQL:

```sql
CREATE EXTENSION jev CASCADE;

SELECT * FROM people WHERE jev(people, 'the name is European');

SELECT subject, jev_prob(tickets, 'the customer is angry') AS p
FROM tickets ORDER BY p DESC LIMIT 20;
```

The property that matters most is that `jev()` is an ordinary boolean function, so it composes with everything else in SQL, meaning `AND age > 40`, joins, `GROUP BY`, `LIMIT` and `ORDER BY jev_prob(...)` all work. `jev_prob` gives a calibrated probability for ranking, and `jev_choice` picks between a set of labels:

```sql
SELECT name, jev_score(products, 'how luxurious is this product?',
                       ARRAY['budget', 'mid-range', 'premium', 'luxury']) AS luxury
FROM products ORDER BY luxury DESC;
```

The primary language is recorded as Shell, the licence is a PostgreSQL licence, the homepage is pgjev.com, and the single release is v0.2.1 on 2026-10-03 with the last push on 2026-10-06.

## How the read-ahead and batching work

The implementation is described in four steps and the details are the interesting part. `jev(table, 'condition')` receives the row as a composite value, and the first call for a table and condition starts a read-ahead that streams the table in physical order, using TID range scans and OFFSET pages for views. The `jev.max_prefetch_rows` setting limits how far it searches for a requested row and how many skipped rows it retains, and it explicitly does not limit the answer cache or the total session memory. Rows are then packed `jev.batch_size` of 20 per request into one shared state, a condition and a list of rows, with one yes or no Noul question per row. Jev evaluates all questions over one state in parallel, which amortises the request overhead, about 270 tokens for a batched request compared to about 435 tokens for one row alone, or 175 per row in batches of 20.

## Concurrency, the LIMIT short-circuit and the cache

Up to twice `jev.concurrency` requests are in flight over persistent HTTPS connections, and every row is answered as soon as its batch returns, so a `LIMIT` stops the read-ahead after the in-flight window. Rows that cheaper predicates filter out before `jev()` runs, in a `WHERE age > 60 AND jev(...)` shape, are skipped rather than judged, and that ordering is the single most important thing to get right for cost. Answers are cached per row content and question for the backend session, so re-running, changing the threshold or sorting by probability is free while those answers remain cached. The cache can grow with unique row and question pairs until `jev_cache_clear()` clears it or the backend session ends. There is a limitation here. Rows from a subquery or a CTE, which is an anonymous record type, cannot be read ahead and are judged one request at a time, so the advice is to put `jev()` on base tables or views when you can.

## Why the batch size is twenty

The batch size is not a tuning knob left to taste, and the reasoning is specific. Jev has to find `rows[i]` by position in the array, and that gets unreliable in long arrays. Against ground truth from structured columns, with job title, EU membership and a phrase in a free-text field across 400 rows each, batches of one to twenty rows were 100% correct, batches of forty were 92 to 98% and batches of eighty were 77 to 94%. Wider rows at 1,000 characters made no difference at twenty. Naming rows instead of indexing them did not help either. And batches of twenty cost 4% more tokens than batches of forty and are just as fast, because a request's latency barely depends on its size. So twenty is where the accuracy is still perfect and the latency is not yet a cost, which is a clean answer.

## The measured numbers, and the honest baseline

The README gives a measured example, on a 2,000-row table from Europe with about 190 milliseconds of API latency. The first run is about 3.5 seconds across 100 requests, using about 296k input tokens and costing about $0.012, the second run is about 50 milliseconds because the answers are cached, and a `LIMIT 3` on a new condition is about 0.6 seconds. There is one more figure that matters operationally. A new condition in a session that still holds its pooled connections, so idle for less than `jev.keepalive`, takes about 2.3 seconds, because the first request on each fresh connection is the slow one. The comparison with the previous version is also given, with version 0.1.0 needing 8.5 seconds and 338k tokens for the full query and 8.4 seconds for the LIMIT. The cost figures are the reason the ordering of predicates matters, since each row judged is a row you paid for.

## Installing it, and the hosts that cannot run it

The requirements are PostgreSQL 14 to 17 with `plpython3u`, the package `postgresql-plpython3-NN` on Debian and Ubuntu and included in the EDB and Postgres.app builds, a superuser, and a TypeSafe API key. The exclusion is stated plainly, and it is the first thing to check. Managed hosts that withhold superuser or `plpython3u`, and the list names Supabase, Neon and RDS, cannot run it. The install routes are three. The PGXN route installs a client and then the extension:

```bash
pip install pgxnclient
pgxn install jev
psql -c "CREATE EXTENSION jev CASCADE"
```

The source route is a clone and a make install, with `make install PG_CONFIG=/path/to/pg_config` when the config is not on PATH, and the superuser note is explicit that it is required because plpython3u is untrusted, and that CASCADE creates plpython3u. The Docker route builds from the Dockerfile with a PG_MAJOR build argument and runs the container with a TYPESAFE_API_KEY environment variable.

## The agent skill, and the extension packaging

The repository ships an agent skill on skills.sh, installed with `npx skills add realZachi/pg-jev`, and the pitch is that you then tell a skill-aware agent such as Claude Code, Codex or Cursor to do the work. The agent runs a preflight that checks the PostgreSQL version, the presence of plpython3u and superuser access, installs the extension with `pgxn install jev` or `make install` against the right `pg_config`, creates the extension, places the API key and runs a smoke test. After that the agent also knows how to write cost-conscious queries and how to explain what the extension can do. The documentation is machine-readable too, since you can append `.md` to any page under the docs site. The packaging is the PGXS model with nothing to compile, since it is PL/Python only, and the Makefile has a `dist` target producing a zip for PGXN, a `docker-test` target running the suite in a throwaway container, and an `installcheck` target using pg_regress against a running server.

## Conclusion

Adopt pg-jev if you want to explore free-text columns in Postgres with a condition you can write in English, and you run a database where you have superuser access and can install plpython3u. Skip it if you are on a managed host such as Supabase, Neon or RDS, because those withhold the superuser and the extension the tool needs. Before you start, note that every row judged is a network request to a model API, so the cost scales with the rows you filter, and that placing jev() after a cheap predicate in the WHERE clause is what keeps that cost down.

## FAQ

### What does the jev PostgreSQL extension do?

It lets you filter, rank and classify rows with plain-language conditions such as 'the name is European'. Every row is judged by TypeSafe's Jev, a System One model returning calibrated probabilities rather than generated text, with no index, no embeddings and no vector column.

### Can I run pg-jev on Supabase, Neon or RDS?

No. The requirements are PostgreSQL 14 to 17 with plpython3u, a superuser and a TypeSafe API key, and the documentation states that managed hosts withholding superuser or plpython3u, naming Supabase, Neon and RDS, cannot run it.

### How do I keep the cost of jev() down?

Put cheap predicates before it in the WHERE clause, since rows filtered out before jev() runs are skipped rather than judged. A LIMIT also stops the read-ahead after the in-flight window, and answers are cached per row content and question for the backend session.

### How do I install the jev extension?

With `pip install pgxnclient` then `pgxn install jev` then `CREATE EXTENSION jev CASCADE`, or from source with a clone and `make install`, optionally with PG_CONFIG pointing at your pg_config. In Docker, build the image with a PG_MAJOR build argument and run it with a TYPESAFE_API_KEY environment variable.

## Sources

- [Issues](https://github.com/realZachi/pg-jev/issues)
- [Project website](https://pgjev.com)
- [README](https://github.com/realZachi/pg-jev/blob/master/README.md)
- [realZachi/pg-jev on GitHub](https://github.com/realZachi/pg-jev)
- [Releases](https://github.com/realZachi/pg-jev/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/realzachi-pg-jev
