poorjev 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. poorjev-0.1.0/.github/workflows/tests.yml +26 -0
  2. poorjev-0.1.0/.gitignore +17 -0
  3. poorjev-0.1.0/CLAUDE.md +61 -0
  4. poorjev-0.1.0/LICENSE +21 -0
  5. poorjev-0.1.0/PKG-INFO +264 -0
  6. poorjev-0.1.0/PRD.md +271 -0
  7. poorjev-0.1.0/README.md +227 -0
  8. poorjev-0.1.0/RESULTS.md +74 -0
  9. poorjev-0.1.0/calibration.json +7 -0
  10. poorjev-0.1.0/docs/reliability_before_after.png +0 -0
  11. poorjev-0.1.0/docs/reliability_raw.png +0 -0
  12. poorjev-0.1.0/docs/risk_coverage.png +0 -0
  13. poorjev-0.1.0/evalset/README.md +43 -0
  14. poorjev-0.1.0/evalset/source.py +170 -0
  15. poorjev-0.1.0/evalset/tasks.jsonl +55 -0
  16. poorjev-0.1.0/examples/demo.py +60 -0
  17. poorjev-0.1.0/examples/ticket_router.py +40 -0
  18. poorjev-0.1.0/examples/tool_gate.py +53 -0
  19. poorjev-0.1.0/pyproject.toml +45 -0
  20. poorjev-0.1.0/src/poorjev/__init__.py +33 -0
  21. poorjev-0.1.0/src/poorjev/backends/__init__.py +4 -0
  22. poorjev-0.1.0/src/poorjev/backends/local_nli.py +108 -0
  23. poorjev-0.1.0/src/poorjev/calibration.py +164 -0
  24. poorjev-0.1.0/src/poorjev/cli.py +184 -0
  25. poorjev-0.1.0/src/poorjev/client.py +96 -0
  26. poorjev-0.1.0/src/poorjev/evaluate.py +95 -0
  27. poorjev-0.1.0/src/poorjev/mcp_server.py +185 -0
  28. poorjev-0.1.0/src/poorjev/metrics.py +137 -0
  29. poorjev-0.1.0/src/poorjev/plots.py +119 -0
  30. poorjev-0.1.0/src/poorjev/primitives.py +280 -0
  31. poorjev-0.1.0/tests/test_calibration.py +89 -0
  32. poorjev-0.1.0/tests/test_client.py +112 -0
  33. poorjev-0.1.0/tests/test_evaluate.py +86 -0
  34. poorjev-0.1.0/tests/test_mcp.py +82 -0
  35. poorjev-0.1.0/tests/test_metrics.py +77 -0
  36. poorjev-0.1.0/tests/test_primitives.py +210 -0
@@ -0,0 +1,26 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.10", "3.11", "3.12"]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+ cache: pip
23
+ - run: |
24
+ python -m pip install --upgrade pip
25
+ pip install -e ".[dev]"
26
+ - run: pytest -q
@@ -0,0 +1,17 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .pytest_cache/
8
+ .coverage
9
+ htmlcov/
10
+ .venv/
11
+ venv/
12
+ env/
13
+ .DS_Store
14
+ *.png
15
+ !docs/*.png
16
+ models/
17
+ .hf_cache/
@@ -0,0 +1,61 @@
1
+ # CLAUDE.md
2
+
3
+ Guidance for Claude Code (and any agent) working in this repo.
4
+
5
+ ## What poorjev is
6
+
7
+ An open source, local-first "System One" decision layer: ask typed questions
8
+ about some state (Choice / Score / Noul), get typed answers with **calibrated**
9
+ confidence, in one pass, no API key by default. The differentiator is honest,
10
+ measured calibration. See `PRD.md` for the full spec and `README.md` for the pitch.
11
+
12
+ ## Architecture (read in this order)
13
+
14
+ - `src/poorjev/primitives.py` — the contract. `Choice` / `Score` / `Noul` and
15
+ their frozen typed answers. Schema validity is **structural**: a decided
16
+ answer's `value` is always in the declared set, even for adversarial scores.
17
+ - `src/poorjev/client.py` — `Client.ask(state, questions)`. Builds one batched
18
+ set of (state, hypothesis) pairs across all questions, calls the backend once,
19
+ applies the fitted `temperature`, and decides. Backends are a Protocol.
20
+ - `src/poorjev/backends/local_nli.py` — default keyless backend. A zero-shot NLI
21
+ model scores each hypothesis for entailment. Lazy torch/transformers import.
22
+ - `src/poorjev/calibration.py` — the moat. Temperature scaling (fit by k-fold
23
+ CV) + conformal abstention.
24
+ - `src/poorjev/metrics.py` — accuracy, ECE, Brier, risk-coverage (stdlib only).
25
+ - `src/poorjev/evaluate.py` — run the eval set through a backend, score vs gold.
26
+ - `src/poorjev/plots.py` — reliability diagram + risk-coverage plot.
27
+ - `src/poorjev/mcp_server.py` — expose poorjev as MCP tools (gate/judge/classify/
28
+ rate/decide). Logic is in plain `do_*` functions; MCP wrappers are thin.
29
+ - `src/poorjev/cli.py` — `poorjev eval | calibrate | ask | serve`.
30
+ - `evalset/source.py` -> `evalset/tasks.jsonl` — hand-labelled data.
31
+
32
+ ## Commands
33
+
34
+ ```bash
35
+ pip install -e ".[local,plots,mcp,dev]" # full dev install
36
+ pytest -q # fast suite, no model, no key
37
+ poorjev eval --set evalset/tasks.jsonl # accuracy + ECE (downloads model)
38
+ poorjev calibrate --set evalset/tasks.jsonl --plots # before/after ECE + diagrams
39
+ poorjev serve # run the MCP server (stdio)
40
+ python evalset/source.py # regenerate tasks.jsonl
41
+ ```
42
+
43
+ ## Conventions
44
+
45
+ - **Tests never need a model or a key.** Unit tests use a fake/scripted backend.
46
+ Anything that loads the real model is an example or a manual run, not a test.
47
+ - **Honesty is the product.** Every headline number must be reproducible by
48
+ `poorjev eval` / `poorjev calibrate` on the shipped set. No cherry-picking. If
49
+ a number is bad, print it. Keep the honest-limitations sections truthful.
50
+ - **No em-dashes in README / marketing copy.** Use commas, colons, short
51
+ sentences. (Source code and this file are exempt.)
52
+ - **Ask concrete questions.** The local NLI model handles "this moves money"
53
+ well and "this is dangerous" poorly. Prefer concrete hypotheses; decompose
54
+ abstract ones and apply a rule.
55
+ - **Commits:** author as the repo owner only; do not add co-author trailers.
56
+
57
+ ## Good first contributions
58
+
59
+ - More labelled decision tasks in `evalset/` (raises the eval's credibility).
60
+ - Per-question temperature in `calibration.py` (likely lowers ECE further).
61
+ - A new backend implementing `entail_probs(pairs)` (e.g. the optional LLM one).
poorjev-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rupesh Poojary
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
poorjev-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.5
2
+ Name: poorjev
3
+ Version: 0.1.0
4
+ Summary: The poor man's Jev: a local-first System One decision layer with provably calibrated confidence.
5
+ Project-URL: Homepage, https://github.com/rupeshpoojary9/poorjev
6
+ Author: Rupesh Poojary
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Keywords: calibration,classification,conformal-prediction,guardrails,llm,mcp,structured-output,system-one,zero-shot
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.10
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
22
+ Requires-Dist: pytest>=8.0; extra == 'dev'
23
+ Provides-Extra: llm
24
+ Requires-Dist: anthropic>=0.40; extra == 'llm'
25
+ Requires-Dist: openai>=1.40; extra == 'llm'
26
+ Provides-Extra: local
27
+ Requires-Dist: protobuf>=4.0; extra == 'local'
28
+ Requires-Dist: sentencepiece>=0.2; extra == 'local'
29
+ Requires-Dist: torch>=2.2; extra == 'local'
30
+ Requires-Dist: transformers>=4.40; extra == 'local'
31
+ Provides-Extra: mcp
32
+ Requires-Dist: mcp>=1.2; extra == 'mcp'
33
+ Provides-Extra: plots
34
+ Requires-Dist: matplotlib>=3.8; extra == 'plots'
35
+ Requires-Dist: numpy>=1.26; extra == 'plots'
36
+ Description-Content-Type: text/markdown
37
+
38
+ <h1 align="center">poorjev</h1>
39
+
40
+ <p align="center"><b>The poor man's Jev.</b> An open source, local-first "System One" decision layer for LLM apps: typed decisions with <b>provably calibrated confidence</b>. No API key. No waitlist.</p>
41
+
42
+ <p align="center">
43
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="MIT license">
44
+ <img src="https://img.shields.io/badge/python-3.10%2B-blue" alt="Python 3.10+">
45
+ <a href="https://github.com/rupeshpoojary9/poorjev/actions/workflows/tests.yml"><img src="https://github.com/rupeshpoojary9/poorjev/actions/workflows/tests.yml/badge.svg" alt="tests"></a>
46
+ <img src="https://img.shields.io/badge/ECE-0.170%20%E2%86%92%200.071-orange" alt="ECE 0.170 to 0.071">
47
+ <img src="https://img.shields.io/badge/API%20key-not%20required-blueviolet" alt="no API key required">
48
+ </p>
49
+
50
+ ---
51
+
52
+ **Your model's `0.9` is a vibe. poorjev's `0.9` is a measurement.**
53
+
54
+ Every LLM-in-JSON-mode hands you a confidence score and hopes you don't check it. poorjev checks it. On the shipped eval set it cuts calibration error (ECE) from **0.170 to 0.071** with zero loss of accuracy, and it runs on your laptop with no API key.
55
+
56
+ <p align="center">
57
+ <img src="https://raw.githubusercontent.com/rupeshpoojary9/poorjev/main/docs/reliability_before_after.png" alt="Reliability diagram: raw confidences are overconfident, calibrated confidences hug the diagonal" width="760">
58
+ </p>
59
+
60
+ <p align="center"><i>Left: raw confidences, overconfident. Right: calibrated, a stated 0.8 really is right about 80% of the time.</i></p>
61
+
62
+ ## Quickstart
63
+
64
+ ```bash
65
+ pip install "poorjev[local]"
66
+ ```
67
+
68
+ > PyPI publish is pending. Until then: `pip install "poorjev[local] @ git+https://github.com/rupeshpoojary9/poorjev"`
69
+
70
+ ```python
71
+ from poorjev import Client, Choice, Score, Noul
72
+
73
+ client = Client() # local model, no key, offline after one download
74
+
75
+ result = client.ask(
76
+ state="I've emailed three times and I'm STILL being double-charged. Cancel my account today.",
77
+ questions={
78
+ "topic": Choice(["billing", "technical", "account", "shipping", "other"]),
79
+ "frustration": Score(levels=["low", "medium", "high"]),
80
+ "is_urgent": Noul("The customer needs a response today."),
81
+ "wants_cancel": Noul("The customer wants to cancel their account."),
82
+ },
83
+ )
84
+
85
+ result["topic"].value # "billing" always one of your options, by construction
86
+ result["topic"].confidence # 0.86 calibrated, not a vibe
87
+ result["frustration"].value # "high"
88
+ result["is_urgent"].value # True
89
+ result["wants_cancel"].value # True
90
+ ```
91
+
92
+ One call, one model pass, four typed answers. No prompt engineering, no JSON parsing, no "the model returned prose."
93
+
94
+ ## Use it in Claude Code (MCP server)
95
+
96
+ poorjev ships an MCP server, so a Claude Code (or Claude Desktop) agent can make
97
+ fast, local, calibrated decisions as tools, with no API key and no token cost.
98
+ The obvious use: gate a risky tool call before the agent runs it.
99
+
100
+ ```bash
101
+ pip install "poorjev[local,mcp]"
102
+ claude mcp add poorjev -- poorjev serve
103
+ ```
104
+
105
+ Or add it to `.mcp.json` by hand:
106
+
107
+ ```json
108
+ {
109
+ "mcpServers": {
110
+ "poorjev": { "command": "poorjev", "args": ["serve"] }
111
+ }
112
+ }
113
+ ```
114
+
115
+ The agent then has these local tools:
116
+
117
+ | Tool | What it does |
118
+ |---|---|
119
+ | `gate(action)` | guardrail: should this action be blocked (moves money, deletes data)? |
120
+ | `judge(text, statement)` | a yes/no question, with calibrated `P(true)` |
121
+ | `classify(text, options)` | pick one option, with calibrated confidence |
122
+ | `rate(text, levels)` | an ordinal score (low / medium / high) |
123
+ | `decide(text, questions)` | several typed questions at once, one pass |
124
+
125
+ Why this beats asking an LLM to judge: it is local (private), free (no tokens),
126
+ fast, and the confidence is calibrated instead of made up.
127
+
128
+ ## Why poorjev exists
129
+
130
+ Most production AI work is not chat. It is fast structured decisions: **route** a ticket, **classify** an intent, **score** a sentiment, **extract** a field, **gate** a tool call. TypeSafe's **Jev** named this category ("System One" models) and nailed the thesis, but Jev is closed, hosted, and behind a waitlist.
131
+
132
+ poorjev gives you the same developer interface, locally and openly, and it wins on the one thing that actually matters for routing and gating: **confidence you can trust.** A model that is right 78% of the time but *honest about which 78%* is worth more in production than a smarter model that is silently overconfident.
133
+
134
+ ## poorjev vs Jev
135
+
136
+ | | **Jev** (TypeSafe) | **poorjev** |
137
+ |---|---|---|
138
+ | Interface (typed questions, one pass) | yes | yes |
139
+ | Calibrated confidence | yes (claimed) | **yes (measured, reproducible)** |
140
+ | Schema-valid output, 0 type errors | yes | **yes, by construction** |
141
+ | Runs locally, no API key | no | **yes** |
142
+ | Your data stays in your environment | no | **yes** |
143
+ | Waitlist / signup | yes | **no** |
144
+ | Open source | no | **yes (MIT)** |
145
+ | Speed | very fast (custom model) | slower, honest about it |
146
+
147
+ poorjev is not a Jev clone and makes no speed claims. It reproduces the **interface** and the **calibrated-confidence guarantee** on commodity models, and proves the calibration with numbers.
148
+
149
+ ## The three primitives
150
+
151
+ | Primitive | Use it for | Returns |
152
+ |---|---|---|
153
+ | `Choice(options)` | classification, routing | winning option, per-option probabilities, calibrated confidence |
154
+ | `Score(levels)` | ordinal rating, severity | winning level, a continuous score on the scale, confidence |
155
+ | `Noul(statement)` | yes/no gates, guardrails | `P(true)`, thresholded to a bool |
156
+
157
+ The returned `value` is **always** drawn from the set you declared. An invalid category is structurally impossible, not "usually avoided." This is tested against adversarial inputs (NaN, infinity, negatives, all-zero score vectors).
158
+
159
+ ## How it works
160
+
161
+ ```
162
+ state + typed questions
163
+ |
164
+ v
165
+ one batched pass through a local zero-shot NLI model (no API key)
166
+ |
167
+ v
168
+ raw probabilities per option
169
+ |
170
+ v
171
+ calibration: temperature scaling + conformal abstention
172
+ |
173
+ v
174
+ typed, schema-valid answers + calibrated confidence
175
+ ```
176
+
177
+ - **Local backend (default):** one small natural-language-inference model scores every option as an entailment hypothesis, in a single batched forward pass. Fully offline after a one-time ~400MB download. No key, no vendor, your text never leaves your machine.
178
+ - **Calibration (the moat):** temperature scaling fits one scalar so predicted confidence matches real accuracy; conformal thresholding turns a target risk budget into an "I don't know, escalate" signal.
179
+ - **LLM backend (optional, roadmap):** when you need more reasoning, point poorjev at an LLM and it makes that model's confidence honest too. That is the intelligence dial, not the default.
180
+
181
+ ## Benchmarks
182
+
183
+ Reproduce everything with two commands:
184
+
185
+ ```bash
186
+ poorjev eval --set evalset/tasks.jsonl # accuracy, ECE, Brier, risk-coverage
187
+ poorjev calibrate --set evalset/tasks.jsonl --plots # before/after ECE + the diagrams
188
+ ```
189
+
190
+ On the shipped eval set (55 hand-labelled items, 160 decisions), local NLI backend, keyless:
191
+
192
+ | Metric | Raw | Calibrated |
193
+ |---|---:|---:|
194
+ | Accuracy | 0.781 | 0.781 |
195
+ | **ECE (calibration error)** | **0.170** | **0.071** |
196
+ | Brier | 0.184 | lower |
197
+ | Temperature | 1.00 | 2.71 |
198
+
199
+ Temperature is fit by 5-fold cross-validation, so the "after" number is measured on held-out data, never on data it was fit on. Full tables and the honest limitations are in [RESULTS.md](RESULTS.md).
200
+
201
+ ## Selective prediction: it knows when it doesn't know
202
+
203
+ Set a risk budget and poorjev abstains on its least confident decisions instead of guessing:
204
+
205
+ <p align="center">
206
+ <img src="https://raw.githubusercontent.com/rupeshpoojary9/poorjev/main/docs/risk_coverage.png" alt="Risk-coverage curve: error rate drops as the model abstains on low-confidence decisions" width="440">
207
+ </p>
208
+
209
+ At a 10% error budget it confidently answers 55% of decisions and escalates the rest. That is the natural bridge from System One (fast automatic answer) to System Two (a human, or a bigger model).
210
+
211
+ ## Real examples
212
+
213
+ ```bash
214
+ python examples/ticket_router.py # full triage on a support ticket
215
+ python examples/tool_gate.py # gate a risky tool call before it runs
216
+ python examples/demo.py # raw vs calibrated, side by side
217
+ ```
218
+
219
+ The tool-gate example encodes a practical lesson: the local model is strong at **concrete** questions ("this action moves money", "this deletes data") and weak at **abstract** ones ("this is dangerous"). Ask concrete questions and let a one-line rule apply the policy.
220
+
221
+ ## Honest limitations
222
+
223
+ No hype. Here is what this is not.
224
+
225
+ - **Not as fast as Jev.** Jev uses a custom model. poorjev uses commodity ones. We report latency, we do not market it.
226
+ - **The eval set is small** (tens of items, one labeller, English, support flavoured). Enough to show calibration direction and schema validity, not a leaderboard.
227
+ - **After-ECE is 0.071, not below 0.05.** That is the real cross-validated number, reported as measured. Per-question temperature would likely push it lower.
228
+ - **The local model is moderately intelligent.** It does real semantic entailment, not deep reasoning. Calibration and abstention are what make that safe.
229
+
230
+ ## FAQ
231
+
232
+ **Is this a Jev clone?** No. It reproduces Jev's developer interface and its calibrated-confidence guarantee on open, local models. It does not copy Jev's architecture or its speed.
233
+
234
+ **Do I need an API key or GPU?** No. The default backend runs on CPU, offline, after one model download.
235
+
236
+ **How is this different from an LLM in JSON mode?** Two ways. Output is schema-valid by construction, not by parsing. And the confidence is calibrated and proven, not a number the model made up.
237
+
238
+ **What is a "System One" model?** A model for fast, automatic, structured decisions (classify, route, score, gate), as opposed to slow, deliberative chat. The name is from Kahneman's System 1 / System 2.
239
+
240
+ **What is ECE?** Expected Calibration Error: the average gap between a model's confidence and its actual accuracy. Lower is better. poorjev's whole job is to shrink it.
241
+
242
+ **Can I use my own model?** Yes. Backends are pluggable; a backend only implements `entail_probs(pairs)`.
243
+
244
+ ## Roadmap
245
+
246
+ - [x] Typed primitives, schema-valid by construction
247
+ - [x] Local NLI backend, single pass, keyless
248
+ - [x] Eval set + metrics (accuracy, ECE, Brier, risk-coverage)
249
+ - [x] Calibration: temperature scaling + conformal abstention
250
+ - [x] MCP server: use poorjev as local tools in Claude Code
251
+ - [ ] Optional LLM backend (the intelligence dial)
252
+ - [ ] `system-one-bench`: a standalone calibration benchmark for the category
253
+
254
+ ## Contributing
255
+
256
+ Issues and PRs welcome, especially new labelled decision tasks for the eval set. If you find a case where the confidence is not honest, that is a bug worth filing.
257
+
258
+ ## License
259
+
260
+ MIT. Use it, ship it, sell it.
261
+
262
+ ---
263
+
264
+ <p align="center"><i>poorjev: poor in price, rich in honesty. If your model's confidence is a vibe, come check it.</i></p>
poorjev-0.1.0/PRD.md ADDED
@@ -0,0 +1,271 @@
1
+ # PRD — `poorjev` (the poor man's Jev)
2
+
3
+ **An open-source, local-first "System One" decision layer.** Same developer interface as
4
+ Jev (typed questions over program state, answered in one pass with **calibrated**
5
+ probabilities) but backed by small local models or any LLM, and where the one thing we get
6
+ *provably* right is the exact thing Jev sells on: **honest confidence.**
7
+
8
+ - **Owner:** Rupesh Poojary
9
+ - **Date:** 2026-09-19
10
+ - **Package / repo:** `poorjev` → `pip install poorjev` → `github.com/rupeshpoojary9/poorjev`
11
+ - *Name is free on PyPI + GitHub as of 2026-09-19. Backups: `poormansjev`, `poorjevai`.*
12
+ - **Status:** 🔴 not started — this PRD is the build spec
13
+ - **Lane:** LLM-evals authority (pairs with `rag-eval-benchmark`, `awesome-llm-evals`). Sister project to a future `system-one-bench`.
14
+
15
+ ---
16
+
17
+ ## 0. The viral wedge (read this first)
18
+
19
+ **Name:** `poorjev`. It carries the whole story in seven characters: open, cheap, Jev-adjacent, underdog. "Poor man's X" is a badge in dev culture, not an insult, it signals resourceful-hacker "I got 90% of the expensive thing for free." Nobody needs the joke explained; it lands in zero seconds.
20
+
21
+ **The one spicy, true claim we own:** *every* "System One" project on jevusecases.com (1350+ of them) quotes speed and cost. Almost none prove their **confidence is calibrated**. Jev sells calibrated confidence but gates it behind a waitlist. So the line that spreads is:
22
+
23
+ > Everyone ships an LLM in JSON mode and calls the `0.9` a "confidence." It's a vibe.
24
+ > `poorjev` is the poor man's Jev, and it's the only one that proves its `0.9` actually means `0.9`. Runs on your laptop. No waitlist.
25
+
26
+ **The one screenshot that sells it:** a **reliability diagram**, our predicted probability vs. actual accuracy, before and after calibration (ECE ~0.17 → <0.05). That single image is the launch asset. Build toward producing it (see §7, M4).
27
+
28
+ ### Launch kit (draft copy, keep em-dash-free per house style)
29
+
30
+ **README hero (top of the repo):**
31
+ ```
32
+ poorjev
33
+ the poor man's Jev.
34
+
35
+ Poor in price. Rich in honesty.
36
+ Typed decisions with confidence that is actually calibrated, not vibes.
37
+ Runs on your laptop. No API key. No waitlist.
38
+
39
+ pip install poorjev
40
+ ```
41
+
42
+ **Launch tweet / X post:**
43
+ ```
44
+ Jev is a $40M waitlist.
45
+
46
+ poorjev is the poor man's version: same typed-question interface, runs
47
+ local with no key, and it is the ONLY one that proves its confidence is
48
+ real (ECE 0.17 -> 0.04, reliability diagram below).
49
+
50
+ Your model's 0.9 is a vibe. Mine is a measurement.
51
+
52
+ pip install poorjev
53
+ [reliability-diagram.png]
54
+ ```
55
+
56
+ **Hacker News title:**
57
+ ```
58
+ Show HN: poorjev, a local "System One" decision layer that proves its confidence is calibrated
59
+ ```
60
+
61
+ **One-line elevator (for GitHub About + resume):**
62
+ ```
63
+ Open, local alternative to Jev's System One API: typed decisions with
64
+ provably calibrated confidence. 100% schema-valid by construction.
65
+ ```
66
+
67
+ **Distribution plan (from [[github-followers-strategy]]: distribution, not more repos):**
68
+ 1. Ship the repo with the reliability diagram in the README above the fold.
69
+ 2. Submit to jevusecases.com (1350+ dir, the exact audience) as the calibration-first entry.
70
+ 3. Show HN + one X thread built around the "your 0.9 is a vibe" line + the diagram.
71
+ 4. Add to `awesome-llm-evals` under a new "calibration / selective prediction" section.
72
+ 5. Reply-guy value: whenever someone benchmarks Jev on speed, add the calibration axis nobody else measures.
73
+
74
+ ---
75
+
76
+ ## 1. Why this exists
77
+
78
+ TypeSafe launched **Jev** (Sept 15 2026, $40M DCVC): a "System One model" that takes program
79
+ state + typed questions and returns **typed answers with calibrated probabilities in one
80
+ parallel pass**, 70-500ms, output tokens free, ~0% type errors. The category thesis is
81
+ correct: **most production AI work is fast structured decisions** (route, classify, extract,
82
+ score, moderate, gate a tool call), not chat. But Jev is **gated behind a waitlist**, closed,
83
+ and hosted-only.
84
+
85
+ The gap: developers want that *interface*, "ask N typed questions about this state, get typed
86
+ answers + trustworthy confidence, cheap and local", today, without a waitlist, and without
87
+ shipping their data to a new vendor. And nobody in the ecosystem is proving the confidence
88
+ half of the promise, which is the half that actually matters for routing and gating.
89
+
90
+ **What we do NOT claim:** we are not reproducing Jev's non-autoregressive parallel
91
+ architecture or its speed. We reproduce the **interface** and the **calibrated-confidence
92
+ guarantee**, on commodity models, and we prove the calibration with numbers. That honesty is
93
+ the whole pitch, see §9.
94
+
95
+ ## 2. Goal / non-goals
96
+
97
+ **Goal.** A `pip install poorjev`-able Python library + CLI that:
98
+ 1. exposes the three System One primitives (**Choice / Score / Noul**) over arbitrary state,
99
+ 2. answers a batch of typed questions in a **single call** with typed, schema-valid outputs,
100
+ 3. attaches a **calibrated** probability/confidence to every answer,
101
+ 4. supports **abstention** (selective prediction) when confidence is low,
102
+ 5. runs **fully local with no API key** by default, and swaps to a real LLM backend with **one env var**,
103
+ 6. ships a **self-eval** that reports calibration + accuracy on a small labelled set, so the confidence claim is defensible,
104
+ 7. produces the **reliability diagram** from §0 as a committed artifact.
105
+
106
+ **Non-goals (v1).**
107
+ - Not a hosted API / not a Jev clone weights-wise.
108
+ - No multimodal state (text / JSON / arrays only, matches Jev v1).
109
+ - No training a bespoke model from scratch (we adapt existing encoders + optional LLM).
110
+ - No sub-100ms latency promise. Latency is *reported*, not marketed.
111
+
112
+ ## 3. Users
113
+
114
+ - App devs who want a cheap, local classify/route/score/gate layer with real confidence.
115
+ - Anyone building LLM-agent guardrails ("is this tool call risky?" as a Noul gate).
116
+ - **You**, in interviews: a working, measured artifact on the freshest model category, in your evals lane. Also a candidate decision layer for Vereno's live-demo loop.
117
+
118
+ ## 4. The interface (the product surface)
119
+
120
+ Mirror the LangChain/TypeSafe shape closely enough to be a genuine drop-in mental model.
121
+
122
+ ```python
123
+ from poorjev import Client, Choice, Score, Noul
124
+
125
+ client = Client() # local backend, no key, by default
126
+
127
+ result = client.ask(
128
+ state="Customer: 'I've emailed three times and STILL been double-charged. Cancel my account.'",
129
+ questions={
130
+ "topic": Choice(["billing", "technical", "account", "other"]),
131
+ "frustration": Score(levels=["low", "medium", "high"]),
132
+ "is_urgent": Noul("The customer needs a response today."),
133
+ "wants_cancel": Noul("The customer is asking to cancel."),
134
+ },
135
+ )
136
+
137
+ result["topic"].value # -> "billing"
138
+ result["topic"].probs # -> {"billing": 0.86, "account": 0.09, ...}
139
+ result["topic"].confidence # -> 0.86 (calibrated)
140
+ result["frustration"].value # -> "high"
141
+ result["frustration"].score # -> 1.72 (continuous, on the ordinal scale)
142
+ result["is_urgent"].value # -> True
143
+ result["is_urgent"].prob # -> 0.94 (calibrated P(true))
144
+ result["wants_cancel"].abstained # -> False (True if below the conformal threshold)
145
+ ```
146
+
147
+ **Primitives (must match Jev semantics):**
148
+ | Primitive | Input | Output |
149
+ |---|---|---|
150
+ | `Choice(options)` | discrete options | winning option + per-option probs + confidence |
151
+ | `Score(levels=[...])` | ordered levels | continuous score on the scale + distribution + confidence |
152
+ | `Noul(statement)` | a yes/no statement | `P(true)` (a bool once thresholded) |
153
+
154
+ **Contract guarantees (enforced, tested):**
155
+ - Output is always schema-valid, the returned `value` is *always* one of the declared options / within the scale / a bool. No parsing, no "the model returned prose." (This is Jev's "0 type errors" claim, and for us it's true by construction, not by hope, see §5.)
156
+ - All questions in one `ask()` share one state encode and are answered in one pass.
157
+ - Every answer carries a probability; `--calibrate` makes those probabilities calibrated.
158
+
159
+ ## 5. Architecture
160
+
161
+ ```
162
+ ┌──────────── backends (pluggable) ────────────┐
163
+ state + questions ─▶ ask() ┤ local (default): NLI / zero-shot encoder ├─▶ raw scores
164
+ │ llm (opt-in): constrained decode + logprobs│
165
+ └───────────────────────────────────────────────┘
166
+ │ raw scores
167
+ calibration layer ──┤ temperature scaling (fit on dev set)
168
+ │ conformal prediction (abstention sets)
169
+
170
+ typed, schema-valid answers + calibrated confidence
171
+ ```
172
+
173
+ **5.1 Local backend (default, no key), the clever bit.**
174
+ Reuse an NLI / zero-shot model as a general decision engine. One small model does all three:
175
+ - **Noul** → natural-language inference: `P(entailment)` of the statement given the state = `P(true)`.
176
+ - **Choice** → zero-shot classification: score each option as an entailment hypothesis, softmax over options.
177
+ - **Score** → run the ordered levels as hypotheses, take the expected level index as the continuous score, argmax→winning level.
178
+
179
+ Default model: a small NLI checkpoint (e.g. `MoritzLaurer/deberta-v3-base` zero-shot or `all-MiniLM` + a cross-encoder). ~single-digit hundred MB, downloads once, then fully offline. **Schema validity is structural**, options/levels are fixed sets we softmax over, so an out-of-set answer is impossible by construction.
180
+
181
+ **5.2 LLM backend (opt-in, `POORJEV_BACKEND=llm` + key).**
182
+ Any chat LLM (Anthropic default; see `claude-api` for model IDs). Use **constrained/structured output** so the raw answer is always valid, and pull token **logprobs** for the probability. LLMs are notoriously *miscalibrated* (over-confident verbalized probs), so this backend leans hardest on §5.3 to fix that, which is itself a demonstrable result.
183
+
184
+ **5.3 Calibration layer (the differentiator, backend-agnostic).**
185
+ This is what makes us more than "an LLM in JSON mode":
186
+ - **Temperature scaling**: fit one scalar T per question-type on a small labelled dev split so predicted probs match empirical accuracy. Report **before/after ECE**.
187
+ - **Conformal prediction**: turn a target risk level (e.g. 90%) into a per-question confidence threshold; below it, `abstained=True`. Gives honest "I don't know → escalate to System Two" behaviour, the natural bridge to a router.
188
+
189
+ **5.4 Single-pass batching.** Encode state once; evaluate all questions against that encoding in one batched forward pass (local) or one structured request (LLM). No per-question round-trips.
190
+
191
+ ## 6. Repo layout (matches your `rag-eval-benchmark` conventions)
192
+
193
+ ```
194
+ poorjev/
195
+ ├── README.md # the §0 hero + reliability diagram above the fold, quickstart, honest claims
196
+ ├── RESULTS.md # real calibration + accuracy tables, reliability diagrams
197
+ ├── PRD.md # this file
198
+ ├── LICENSE # MIT
199
+ ├── pyproject.toml # hatchling; extras: [llm], [plots], [dev]; script: poorjev=poorjev.cli:main
200
+ ├── src/poorjev/
201
+ │ ├── __init__.py # exports Client, Choice, Score, Noul
202
+ │ ├── primitives.py # the three question types + typed Answer objects
203
+ │ ├── client.py # ask(): orchestrates encode → backend → calibrate → type
204
+ │ ├── backends/
205
+ │ │ ├── local_nli.py # default no-key backend
206
+ │ │ └── llm.py # opt-in Anthropic/structured-output backend
207
+ │ ├── calibration.py # temperature scaling + conformal prediction
208
+ │ ├── metrics.py # ECE, Brier, accuracy, coverage/risk
209
+ │ ├── plots.py # reliability diagrams, risk-coverage curves (THE launch asset)
210
+ │ └── cli.py # poorjev ask / eval / calibrate
211
+ ├── evalset/ # small hand-labelled decision set (see §7)
212
+ │ ├── tasks.jsonl # state + questions + gold answers
213
+ │ └── README.md # how it was labelled
214
+ ├── examples/
215
+ │ ├── ticket_router.py # Choice+Score+Noul over support tickets
216
+ │ └── tool_gate.py # Noul guardrail: "is this tool call risky?" (agent middleware)
217
+ └── tests/ # schema-validity invariants, calibration math, primitives
218
+ ```
219
+
220
+ **CLI:**
221
+ ```bash
222
+ poorjev ask --state-file ticket.txt --questions questions.yaml # one-off decision, JSON out
223
+ poorjev eval --set evalset/tasks.jsonl --plots # accuracy + ECE + Brier + coverage + reliability.png
224
+ poorjev calibrate --set evalset/tasks.jsonl # fit + save temperature/conformal params
225
+ poorjev eval --backend llm --plots # same, LLM backend (needs key)
226
+ ```
227
+
228
+ ## 7. Eval set (the part that makes it credible)
229
+
230
+ Hand-label a **small, honest** decision set, the same discipline that made `rag-eval-benchmark`
231
+ defensible. ~60-100 items across a few realistic decision tasks (support-ticket triage,
232
+ content moderation flags, intent detection, tool-risk gating). Each item = state + the typed
233
+ questions + **gold answers**. This is the hard, valuable part most write-ups skip; it's what
234
+ lets us report calibration honestly and it's the seed corpus for the future `system-one-bench`.
235
+
236
+ ## 8. Success metrics / definition of done
237
+
238
+ v1 ships when, on the local backend over the eval set, `poorjev eval` reports real numbers and:
239
+
240
+ - 🎯 **Schema validity = 100%** by construction (invariant test: no `ask()` ever returns an out-of-set/wrong-type value, incl. adversarial states). This is our honest version of Jev's "0 type errors."
241
+ - 🎯 **Calibration improves measurably** post-temperature-scaling: report **ECE before → after** and **Brier**; target a clear ECE reduction (e.g. ~0.15 → <0.05), the exact number is whatever we honestly measure.
242
+ - 🎯 **The reliability diagram exists** and is committed to the repo + README (the §0 launch asset).
243
+ - 🎯 **Selective prediction works**: a risk-coverage curve showing accuracy rises as we abstain on low-confidence items.
244
+ - 🎯 **Accuracy is competitive** with an "LLM-in-JSON-mode" baseline while being local/free, and where it loses, we say so.
245
+ - 🎯 **Latency + cost reported** (not marketed) for local vs LLM backend.
246
+ - 🎯 Runs **offline, no key**, first-run downloads one small model; `pip install -e ".[dev]" && poorjev eval` reproduces the tables.
247
+ - 🎯 README + RESULTS.md written; tests green; MIT; pushed public.
248
+
249
+ ## 9. Honest-claims guardrails (non-negotiable, your no-hype rule)
250
+
251
+ - Never claim to match Jev's speed or architecture. Frame explicitly as: *interface-compatible + honestly-calibrated, on commodity models.*
252
+ - The name is playful; the numbers are not. Every headline number in README/RESULTS is one `poorjev eval` produces on the shipped eval set. No cherry-picking, no vibes.
253
+ - "Poor man's" is positioning, never an excuse for a weak result. If a number is bad, we print it.
254
+ - State the eval set is small and name what that does/doesn't prove.
255
+ - No em-dashes in any rendered marketing/README/tweet copy (commas/colons). *(This PRD is internal, so dashes here are fine.)*
256
+
257
+ ## 10. Milestones (suggested build order)
258
+
259
+ 1. **M1 — Contract & primitives.** `primitives.py`, typed `Answer` objects, schema-validity invariant tests. *(Prove the "0 type errors" claim first.)*
260
+ 2. **M2 — Local backend.** NLI/zero-shot engine for all three primitives; `ask()` single-pass. First end-to-end decision. *(Study `openjev-sglang` first, differentiate on calibration not speed.)*
261
+ 3. **M3 — Eval set + metrics.** Hand-label `tasks.jsonl`; implement ECE/Brier/accuracy/coverage; `poorjev eval` raw (uncalibrated) numbers.
262
+ 4. **M4 — Calibration + the money screenshot.** Temperature scaling + conformal abstention; before/after ECE; **reliability diagram + risk-coverage plot**. *(This is the differentiator AND the launch asset, don't skip to polish before it works.)*
263
+ 5. **M5 — LLM backend.** Opt-in Anthropic/structured-output + logprobs; show it's miscalibrated raw and fixed by M4.
264
+ 6. **M6 — Launch.** `ticket_router.py`, `tool_gate.py`, honest write-up, tests green, push public, then run the §0 distribution plan (jevusecases.com + Show HN + X thread + awesome-llm-evals).
265
+
266
+ ## 11. Stretch / follow-ons
267
+
268
+ - **`system-one-bench`**: promote `evalset/` into the standalone benchmark. Score `poorjev`, an LLM baseline, and (when access lands) Jev, on accuracy + calibration + latency/cost. You'd own the yardstick for the category.
269
+ - **System-One/System-Two router** built on conformal abstention.
270
+ - **Vereno**: wire `poorjev` as the sub-500ms decision loop in the live-demo console.
271
+ - LangChain-shim so `poorjev` drops into the `TypeSafeClassifier` call site.