{"_id":"@french-castle/jev-code","_rev":"4-4f68b4cfc11d8f37dead43f16b32dfbb","name":"@french-castle/jev-code","dist-tags":{"latest":"0.5.0"},"versions":{"0.2.1":{"name":"@french-castle/jev-code","version":"0.2.1","keywords":["jev","typesafe","system-one","classifier","mcp","model-context-protocol","claude-code","codex","opencode","pi-package","agent-skills"],"author":{"name":"François Chastel"},"license":"MIT","_id":"@french-castle/jev-code@0.2.1","maintainers":[{"name":"french-castle","email":"francois@chastel.co"}],"homepage":"https://github.com/FrancoisChastel/jev-code#readme","bugs":{"url":"https://github.com/FrancoisChastel/jev-code/issues"},"pi":{"extensions":["./integrations/pi"]},"bin":{"jev-code":"dist/cli.js"},"dist":{"shasum":"0dc3ad4832e10c01e0d80a09bc795b6eb728eac1","tarball":"https://registry.npmjs.org/@french-castle/jev-code/-/jev-code-0.2.1.tgz","fileCount":132,"integrity":"sha512-gC0Mvfg9Yj6ZH2eWaHSTYPLnTF3CAYiO36g4zh7yerRtvL0FOt8C7LNP7pGmHXGKs9h61x/vA+2Ool1L4EHipw==","signatures":[{"sig":"MEYCIQCEOy037fikuduh9oaPwnqMBg7Cb4jcj/LgFwl7ZvUXEQIhAKqHwpfgF0uobPtHINX/nLHIzPaKJhLzAj1g5gRSfwrw","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":349456},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"888df07b7d2bb885f971048c04e8b4d701c9d86b","scripts":{"lint":"biome check .","test":"vitest run","build":"tsc -p tsconfig.build.json","check":"npm run lint && npm run typecheck && npm run check:skill && npm run test:coverage && npm run smoke","clean":"rm -rf dist coverage","smoke":"node scripts/smoke.mjs","format":"biome format --write .","lint:fix":"biome check --write .","presmoke":"npm run build","test:e2e":"JEV_CODE_E2E=1 vitest run tests/e2e","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","check:skill":"node scripts/check-skill.mjs","pretypecheck":"npm run build","test:coverage":"vitest run --coverage","prepublishOnly":"npm run check"},"_npmUser":{"name":"french-castle","email":"francois@chastel.co"},"repository":{"url":"git+https://github.com/FrancoisChastel/jev-code.git","type":"git"},"_npmVersion":"11.12.1","description":"Jev, TypeSafe's System One classifier, as a tool inside Claude Code, Codex, Pi, and OpenCode: typed classify, check, score, rank, and ask, plus one-command setup.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.1.0","@modelcontextprotocol/sdk":"^1.30.1"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^5.0.0","typebox":"^1.3.0","typescript":"^7.0.2","@types/node":"^26.6.2","@biomejs/biome":"^2.5.0","@opencode-ai/plugin":"^1.18.32","@vitest/coverage-v8":"^5.0.0","@earendil-works/pi-coding-agent":"^0.87.1"},"peerDependencies":{"typebox":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jev-code_0.2.1_1790546385433_0.638353737137358","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@french-castle/jev-code","version":"0.3.0","keywords":["jev","typesafe","system-one","classifier","mcp","model-context-protocol","claude-code","codex","opencode","pi-package","agent-skills"],"author":{"name":"François Chastel"},"license":"MIT","_id":"@french-castle/jev-code@0.3.0","maintainers":[{"name":"french-castle","email":"francois@chastel.co"}],"homepage":"https://github.com/FrancoisChastel/jev-code#readme","bugs":{"url":"https://github.com/FrancoisChastel/jev-code/issues"},"pi":{"extensions":["./integrations/pi"]},"bin":{"jev-code":"dist/cli.js"},"dist":{"shasum":"7ae96d50f3fff47699d07039b98c40414ef7c88e","tarball":"https://registry.npmjs.org/@french-castle/jev-code/-/jev-code-0.3.0.tgz","fileCount":132,"integrity":"sha512-6kQCZc733aFEqLq3r62ru/n/JNHsdA/u2N+xZt9w4doRzjXOiy3zDOvBxxFhrBU19Xz14TO+PxBwMEs301TjEg==","signatures":[{"sig":"MEYCIQCYqBNEC3ECcxT/NDwcGwA9rtxCUNGwq/8WarKZE7YyNgIhALG+qm3WudkXBJWeAE44LA90DibnP8LQ3TOdIdyfQhii","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIDG249bTj3uRvcAvL49hFU8hEXd0uhRmFqgnlFOMiGOvAiEA53rE/j3wtd1KgbJv5fIJePBR63FPt22nPA54S5VVOV0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":370468},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"cee3202c0321e30e6eb1ae968ece6a79d4181f57","scripts":{"lint":"biome check .","test":"vitest run","build":"tsc -p tsconfig.build.json","check":"npm run lint && npm run typecheck && npm run check:skill && npm run test:coverage && npm run smoke","clean":"rm -rf dist coverage","smoke":"node scripts/smoke.mjs","format":"biome format --write .","version":"node scripts/sync-version.mjs","lint:fix":"biome check --write .","presmoke":"npm run build","test:e2e":"JEV_CODE_E2E=1 vitest run tests/e2e","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","check:skill":"node scripts/check-skill.mjs","pretypecheck":"npm run build","test:coverage":"vitest run --coverage","prepublishOnly":"npm run check"},"_npmUser":{"name":"french-castle","email":"francois@chastel.co"},"repository":{"url":"git+https://github.com/FrancoisChastel/jev-code.git","type":"git"},"_npmVersion":"10.9.8","description":"Jev, TypeSafe's System One classifier, as a tool inside Claude Code, Codex, Pi, and OpenCode: typed classify, check, score, rank, and ask, plus one-command setup.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^4.1.0","@modelcontextprotocol/sdk":"^1.30.1"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^5.0.0","typebox":"^1.3.0","typescript":"^7.0.2","@types/node":"^26.6.2","@biomejs/biome":"^2.5.0","@opencode-ai/plugin":"^1.18.32","@vitest/coverage-v8":"^5.0.0","@earendil-works/pi-coding-agent":"^0.87.1"},"peerDependencies":{"typebox":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jev-code_0.3.0_1790739537161_0.8789012795046456","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@french-castle/jev-code","version":"0.4.0","keywords":["jev","typesafe","system-one","classifier","mcp","model-context-protocol","claude-code","codex","opencode","pi-package","agent-skills"],"author":{"name":"François Chastel"},"license":"MIT","_id":"@french-castle/jev-code@0.4.0","maintainers":[{"name":"french-castle","email":"francois@chastel.co"}],"homepage":"https://github.com/FrancoisChastel/jev-code#readme","bugs":{"url":"https://github.com/FrancoisChastel/jev-code/issues"},"pi":{"extensions":["./integrations/pi"]},"bin":{"jev-code":"dist/cli.js"},"dist":{"shasum":"03d046ffbd9e63221ebe3aae670e39e50f3aa8f7","tarball":"https://registry.npmjs.org/@french-castle/jev-code/-/jev-code-0.4.0.tgz","fileCount":136,"integrity":"sha512-Pmyy7FEUpRRWC5Etn9UhMTRUeTopW48WvV3fNMTMYZaOQvh8U8G3tJzzoDFS0iSvJ91rz1VKDyNuDauk/HND5w==","signatures":[{"sig":"MEUCIQDmfeMte3O3eumfEH0s38cNzavcbud/kdwKw4hxiAQ0wAIgLmyuDtQeyUObAfn9z0IYDATbNGrWWjWa+66JH0QWn10=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIFpdyZTBu9SrZpJfzFu0R6ePHKRtsAOJHbQfLFUPO86TAiEAt/jqCrfP4D7UR6L8hfjag9l42aHCg9x9bx7yFO5m0aI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":405011},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"6369a00e5ae5262e5de90af09bc02f05f733dd16","scripts":{"lint":"biome check .","test":"vitest run","build":"tsc -p tsconfig.build.json","check":"npm run lint && npm run typecheck && npm run check:skill && npm run test:coverage && npm run smoke","clean":"rm -rf dist coverage","smoke":"node scripts/smoke.mjs","format":"biome format --write .","version":"node scripts/sync-version.mjs","lint:fix":"biome check --write .","presmoke":"npm run build","test:e2e":"JEV_CODE_E2E=1 vitest run tests/e2e","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","check:skill":"node scripts/check-skill.mjs","pretypecheck":"npm run build","test:coverage":"vitest run --coverage","prepublishOnly":"npm run check"},"_npmUser":{"name":"french-castle","email":"francois@chastel.co"},"repository":{"url":"git+https://github.com/FrancoisChastel/jev-code.git","type":"git"},"_npmVersion":"10.9.8","description":"Jev, TypeSafe's System One classifier, as a tool inside Claude Code, Codex, Pi, and OpenCode: typed classify, check, score, rank, and ask, plus one-command setup.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^4.1.0","@modelcontextprotocol/sdk":"^1.30.1"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^5.0.0","typebox":"^1.3.0","typescript":"^7.0.2","@types/node":"^26.6.2","@biomejs/biome":"^2.5.0","@opencode-ai/plugin":"^1.18.32","@vitest/coverage-v8":"^5.0.0","@earendil-works/pi-coding-agent":"^0.87.1"},"peerDependencies":{"typebox":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jev-code_0.4.0_1791045371093_0.8154623769575153","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"pi":{"extensions":["./integrations/pi"]},"_id":"@french-castle/jev-code@0.5.0","bin":{"jev-code":"dist/cli.js"},"bugs":{"url":"https://github.com/FrancoisChastel/jev-code/issues"},"dist":{"shasum":"a635f97e45f6ade46b71c456be8ded430f1c62ec","tarball":"https://registry.npmjs.org/@french-castle/jev-code/-/jev-code-0.5.0.tgz","fileCount":136,"integrity":"sha512-DsYOFEAQivYFbGeFmpDQ/HW3FnGqFmbyoQLYpmC2Qpu8kT0XOI4w/RH8F58jy2MpyRSH6zdlC6aZ3Ew8gzRyIw==","signatures":[{"sig":"MEYCIQDvKvFcqvuU5FrG0pABG0YNRlaOx0vmaqIW0pp0RzOFRQIhAOpPdNHigUu2w0UuGWAhLrcUoVepWRslEUe6tZPb8t+6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAYTHo++SF0ixbvxMUUoej0An8gh8HWBO8EZ3llZcwfNAiEAmc7Y1fYJYEJuFkE68Q+Ja96U6AyGwzw0VjhGnQOWmks="}],"unpackedSize":433070},"main":"./dist/index.js","name":"@french-castle/jev-code","type":"module","types":"./dist/index.d.ts","author":{"name":"François Chastel"},"engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"license":"MIT","scripts":{"lint":"biome check .","test":"vitest run","build":"tsc -p tsconfig.build.json","check":"npm run lint && npm run typecheck && npm run check:skill && npm run test:coverage && npm run smoke","clean":"rm -rf dist coverage","smoke":"node scripts/smoke.mjs","format":"biome format --write .","version":"node scripts/sync-version.mjs","lint:fix":"biome check --write .","presmoke":"npm run build","test:e2e":"JEV_CODE_E2E=1 vitest run tests/e2e","typecheck":"tsc -p tsconfig.json --noEmit","test:watch":"vitest","check:skill":"node scripts/check-skill.mjs","pretypecheck":"npm run build","test:coverage":"vitest run --coverage","prepublishOnly":"npm run check"},"version":"0.5.0","_npmUser":{"name":"french-castle","email":"francois@chastel.co"},"homepage":"https://github.com/FrancoisChastel/jev-code#readme","keywords":["jev","typesafe","system-one","classifier","mcp","model-context-protocol","claude-code","codex","opencode","pi-package","agent-skills"],"repository":{"url":"git+https://github.com/FrancoisChastel/jev-code.git","type":"git"},"_npmVersion":"10.8.2","description":"Jev, TypeSafe's System One classifier, as a tool inside Claude Code, Codex, Pi, and OpenCode: typed classify, check, score, rank, and ask, plus one-command setup.","directories":{},"maintainers":[{"name":"french-castle","email":"francois@chastel.co"}],"_nodeVersion":"20.20.2","dependencies":{"zod":"^4.1.0","@modelcontextprotocol/sdk":"^1.30.1"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^5.0.0","typebox":"^1.3.0","typescript":"^7.0.2","@types/node":"^26.6.2","@biomejs/biome":"^2.5.0","@opencode-ai/plugin":"^1.18.32","@vitest/coverage-v8":"^5.0.0","@earendil-works/pi-coding-agent":"^0.99.2"},"peerDependencies":{"typebox":"*","@earendil-works/pi-coding-agent":"*"},"peerDependenciesMeta":{"typebox":{"optional":true},"@earendil-works/pi-coding-agent":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jev-code_0.5.0_1791449470607_0.9691404958974161"}}},"time":{"created":"2026-09-27T21:59:45.289Z","modified":"2026-10-08T08:51:10.951Z","0.2.1":"2026-09-27T21:59:45.563Z","0.3.0":"2026-09-30T03:38:57.264Z","0.4.0":"2026-10-03T16:36:11.201Z","0.5.0":"2026-10-08T08:51:10.754Z"},"bugs":{"url":"https://github.com/FrancoisChastel/jev-code/issues"},"author":{"name":"François Chastel"},"license":"MIT","homepage":"https://github.com/FrancoisChastel/jev-code#readme","keywords":["jev","typesafe","system-one","classifier","mcp","model-context-protocol","claude-code","codex","opencode","pi-package","agent-skills"],"repository":{"url":"git+https://github.com/FrancoisChastel/jev-code.git","type":"git"},"description":"Jev, TypeSafe's System One classifier, as a tool inside Claude Code, Codex, Pi, and OpenCode: typed classify, check, score, rank, and ask, plus one-command setup.","maintainers":[{"name":"french-castle","email":"francois@chastel.co"}],"readme":"<h1 align=\"center\">jev-code</h1>\n\n<p align=\"center\">\n  <strong>Jev, TypeSafe's System One classifier, as a tool inside Claude Code, Codex, Pi, and OpenCode.</strong><br />\n  Typed labels, yes/no checks, scores, and rankings with calibrated probabilities, in a few hundred milliseconds.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/FrancoisChastel/jev-code/actions/workflows/ci.yml\"><img alt=\"CI\" src=\"https://github.com/FrancoisChastel/jev-code/actions/workflows/ci.yml/badge.svg\" /></a>\n  <a href=\"https://www.npmjs.com/package/@french-castle/jev-code\"><img alt=\"npm\" src=\"https://img.shields.io/npm/v/%40french-castle%2Fjev-code\" /></a>\n  <img alt=\"Node 20+\" src=\"https://img.shields.io/badge/node-%3E%3D20-brightgreen\" />\n  <a href=\"LICENSE\"><img alt=\"MIT\" src=\"https://img.shields.io/badge/license-MIT-blue\" /></a>\n</p>\n\n---\n\nCoding agents make small classification decisions all day: which of these 40 CI failures are\nreal, which files answer this question, does this PR do what its description says, how severe is\neach finding. They usually do it by eyeballing, by writing a regex, or by burning a frontier-model\ncall per item.\n\n[Jev](https://typesafe.ai) is a decision model rather than a text model: you send evidence and typed\nquestions, it returns typed answers with calibrated probabilities, never prose. **jev-code** turns\nthat into a first-class tool for four coding agents and ships a skill that teaches the agent when\nto reach for it.\n\n```\n┌──────────────┐  jev_classify / jev_check / ...  ┌───────────┐  POST /v1/systemone  ┌──────────────┐\n│ Claude Code  │ ───── MCP (stdio) ─────────────▶ │           │ ───────────────────▶ │  Jev, hosted │\n│ Codex        │ ───── MCP (stdio) ─────────────▶ │  jev-code │                      │  on TypeSafe │\n│ OpenCode     │ ───── MCP (stdio) ─────────────▶ │           │ ◀─────────────────── │  OpenRouter  │\n│ Pi           │ ───── native extension ────────▶ │           │  typed answers +     │  or Vercel   │\n│ any shell    │ ───── jev-code CLI ────────────▶ │           │  probabilities       │  AI Gateway  │\n└──────────────┘                                  └───────────┘                      └──────────────┘\n```\n\n## What you get\n\n| Piece | What it does |\n| --- | --- |\n| **Five tools** | `jev_classify`, `jev_check`, `jev_score`, `jev_rank`, `jev_ask`. Same names, same JSON, in every harness. |\n| **One skill** | [`skills/jev/SKILL.md`](skills/jev/SKILL.md) tells the agent when a task needs a classifier, how to write good classes and questions, and how to act on the answers. A reference adapted from TypeSafe's official skill covers building Jev into the user's own code. Follows the [Agent Skills](https://agentskills.io) spec. |\n| **One-command setup** | `jev-code setup` detects Claude Code, Codex, Pi, and OpenCode on your machine and wires both the skill and the tool into each. |\n| **A CLI** | The same tools from bash, so the skill still works in a harness with no tool registered. |\n\n## Quick start\n\n**1. Install into your agents** (Node.js 20+):\n\n```bash\nnpx -y @french-castle/jev-code@latest setup\n```\n\nThat detects the harnesses on your machine and, for each one, copies the skill and registers the\ntool. When no API key is in your shell, it asks for one right there (hidden input) and which host\nit belongs to: TypeSafe, OpenRouter, Vercel AI Gateway, OpenAI, or a System One gateway of your\nown, in which case it also asks for the gateway's URL. There is nothing else to configure.\n\nAdd harness names to be explicit (`setup claude codex pi opencode`), `--project` to install into\nthe current repository instead of your user profile, or `--dry-run` to see the plan first.\n\nPrefer to keep the key in your environment? Export it before running `setup`, and it is picked up\nwithout a prompt. This is also what Pi and the CLI read, so `setup` prints the line to add to your\nshell profile after you paste a key:\n\n```bash\nexport TYPESAFE_API_KEY=...           # TypeSafe direct: console.typesafe.ai/keys\nexport OPENROUTER_API_KEY=sk-or-...   # OpenRouter: already set if you use it elsewhere\nexport AI_GATEWAY_API_KEY=vck_...     # Vercel AI Gateway\n```\n\n**2. Check it works:**\n\n```bash\nnpx -y @french-castle/jev-code@latest doctor --live\n```\n\n**3. Restart your agent** (or `/reload` inside pi) and ask for something that needs a classifier:\n\n> Triage the failing tests in the last CI run: which are flaky, which are real bugs?\n\nThe agent loads the `jev` skill, calls `jev_classify` with the failures and a class set, acts on\nthe `auto` results, and tells you which ones it double-checked by hand.\n\n## What a call looks like\n\nThe agent sends raw evidence and its own classes:\n\n```json\n{\n  \"instructions\": \"Classify each test failure by its most likely root cause.\",\n  \"items\": [\n    { \"id\": \"test_login_sso\", \"text\": \"TimeoutError: SSO callback not received within 10s (attempt 3/3)\" },\n    { \"id\": \"test_price_rounding\", \"text\": \"AssertionError: expected 19.99, got 19.989999999\" }\n  ],\n  \"classes\": {\n    \"infrastructure\": \"Network, database, or runner problems unrelated to the code; likely passes on re-run\",\n    \"assertion_bug\": \"The code produced a wrong value; deterministic and reproducible\",\n    \"other\": \"Cannot tell from the excerpt\"\n  }\n}\n```\n\nand gets back a label, the full distribution, and a decision it can branch on:\n\n```json\n{\n  \"summary\": { \"items\": 2, \"auto\": 2, \"review\": 0, \"by_label\": { \"infrastructure\": 1, \"assertion_bug\": 1 } },\n  \"results\": [\n    { \"id\": \"test_login_sso\", \"label\": \"infrastructure\", \"probability\": 0.93, \"margin\": 0.88, \"confidence\": 0.9, \"decision\": \"auto\", \"probabilities\": { \"infrastructure\": 0.93, \"assertion_bug\": 0.05, \"other\": 0.02 } },\n    { \"id\": \"test_price_rounding\", \"label\": \"assertion_bug\", \"probability\": 0.97, \"margin\": 0.95, \"confidence\": 0.95, \"decision\": \"auto\", \"probabilities\": { \"infrastructure\": 0.01, \"assertion_bug\": 0.97, \"other\": 0.02 } }\n  ],\n  \"thresholds\": { \"auto_accept\": 0.85, \"min_margin\": 0.5 },\n  \"model\": \"jev-latest\",\n  \"usage\": { \"input_tokens\": 310, \"output_tokens\": 18 }\n}\n```\n\nMore payloads in [`examples/`](examples) and the full contract in\n[`skills/jev/references/tools.md`](skills/jev/references/tools.md).\n\n## The tools\n\n| Tool | Ask it when | Comes back with |\n| --- | --- | --- |\n| `jev_classify` | Many items, one label each from your classes | label, probabilities, margin, `decision: auto \\| review` |\n| `jev_check` | Yes/no questions about one piece of evidence | probability, `verdict: yes \\| no \\| uncertain` |\n| `jev_score` | Many items on one ordered scale (severity, priority) | score, nearest level, confidence, decision |\n| `jev_rank` | Which candidates answer a question | relevance per candidate, sorted, plus `any_relevant` |\n| `jev_ask` | Anything else: mixed question types over one state | the raw System One answers |\n\nEvery tool validates its input locally (shapes, duplicate ids, request size) before spending a\ncall, batches every item into one request, and returns decisions computed from thresholds you can\noverride per call. Policy stays in your hands; Jev supplies the probabilities.\n\n## Per-harness details\n\n<details>\n<summary><strong>Claude Code</strong></summary>\n\n`jev-code setup claude` copies the skill to `~/.claude/skills/jev/` and runs\n`claude mcp add --scope user jev -- npx -y @french-castle/jev-code@0.5.0 mcp`. The tools appear as\n`mcp__jev__jev_classify` and friends; the skill is `/jev`.\n\nPrefer a plugin that updates itself? This repository is also a Claude Code plugin marketplace:\n\n```bash\nclaude plugin marketplace add FrancoisChastel/jev-code\nclaude plugin install jev-code@jev-code\n```\n\nThe plugin bundles the skill (`/jev-code:jev`) and the MCP server. Manual configuration and\nproject-scope notes: [docs/harnesses/claude-code.md](docs/harnesses/claude-code.md).\n\n</details>\n\n<details>\n<summary><strong>Codex</strong></summary>\n\n`jev-code setup codex` copies the skill to `~/.agents/skills/jev/` (Codex's user-level skills\ndirectory, shared with Pi and OpenCode) and runs `codex mcp add jev -- npx -y @french-castle/jev-code@0.5.0 mcp`.\nWithout the `codex` binary it appends a `[mcp_servers.jev]` table to `~/.codex/config.toml`\ninstead. Invoke the skill with `$jev`. Details: [docs/harnesses/codex.md](docs/harnesses/codex.md).\n\n</details>\n\n<details>\n<summary><strong>Pi</strong></summary>\n\nPi has no MCP client, so jev-code is also a [pi package](https://pi.dev/docs/latest/packages) whose\nextension registers the five tools natively. `jev-code setup pi` runs\n`pi install npm:@french-castle/jev-code` and copies the skill to `~/.agents/skills/jev/`. Run\n`/reload` inside pi afterwards. Details: [docs/harnesses/pi.md](docs/harnesses/pi.md).\n\n</details>\n\n<details>\n<summary><strong>OpenCode</strong></summary>\n\n`jev-code setup opencode` adds a local MCP entry to `~/.config/opencode/opencode.json` (backing the\nfile up first) and copies the skill to `~/.agents/skills/jev/`, which OpenCode reads. A native\ncustom-tool variant lives in [`integrations/opencode/jev.ts`](integrations/opencode/jev.ts).\nDetails: [docs/harnesses/opencode.md](docs/harnesses/opencode.md).\n\n</details>\n\n<details>\n<summary><strong>Skill only, any agent</strong></summary>\n\nThe skill is a standard Agent Skills directory, so the [skills.sh](https://skills.sh) installer\nworks for the 70+ agents it supports:\n\n```bash\nnpx skills add FrancoisChastel/jev-code --skill jev\n```\n\nPair it with the MCP server (`npx -y @french-castle/jev-code@0.5.0 mcp`) in your agent's MCP config,\nor let the agent fall back to the CLI.\n\n</details>\n\n## CLI\n\n```bash\njev-code setup [claude|codex|pi|opencode ...] [--project] [--dry-run] [--no-env] [--no-prompt]\njev-code doctor [--live]                     # which host and key are in use, what is installed\njev-code classify --input payload.json      # same JSON as the tool\necho '{\"state\":\"12 passed, 0 failed\",\"checks\":{\"green\":\"Did every test pass?\"}}' | jev-code check\njev-code rank --input candidates.json --pretty\njev-code mcp                                 # what the harness configs launch\njev-code skill                               # path of the bundled skill\n```\n\nOutput is JSON on stdout. Exit code 2 means a usage or configuration problem, 1 an API failure.\n\n## Upgrading\n\nHarness configs launch a pinned command, `npx -y @french-castle/jev-code@0.5.0 mcp`, so an agent\nstarts fast and works offline once that version is cached, and nothing changes under you until\nyou decide. To upgrade, run setup again with `@latest`: it re-registers the tool with the new pin,\nreplacing the old entry (also through `claude mcp` and `codex mcp`), and refreshes the copied\nskill. `doctor` shows the pinned version of every registration and says when to re-run setup.\n\n```bash\nnpx -y @french-castle/jev-code@latest setup\n```\n\nInstalls made with 0.2.1 or earlier launch an unpinned command. npx keeps the first version it\ncached for an unpinned name and never looks for a newer one, so those installs do not see updates\non their own. Run the command above once to move them to a pinned command.\n\n## Configuration\n\nOne host is required. The first three below serve Jev behind the same System One API, so the\ntools behave identically and only the account you pay through changes; so does a gateway of your\nown that speaks that API ([below](#your-own-gateway)). The last two are other models that answer\nthe same kinds of questions: OpenAI's Decisions API, and Ollama's local decision models, which\nneed no key at all.\n\n| Host | Key variable | Default model | Get a key |\n| --- | --- | --- | --- |\n| TypeSafe (direct) | `TYPESAFE_API_KEY` | `jev-latest` | [console.typesafe.ai/keys](https://console.typesafe.ai/keys) |\n| OpenRouter | `OPENROUTER_API_KEY` | `jev-latest` | [openrouter.ai/settings/keys](https://openrouter.ai/settings/keys) |\n| Vercel AI Gateway | `AI_GATEWAY_API_KEY` | `typesafe-ai/jev` | [AI Gateway API keys](https://vercel.com/docs/ai-gateway/authentication-and-byok/api-keys) |\n| OpenAI Decisions API (public beta, opt-in) | `OPENAI_API_KEY` + `JEV_CODE_PROVIDER=openai` | `gpt-6-luna` | [platform.openai.com/api-keys](https://platform.openai.com/api-keys) |\n| Ollama (local, opt-in) | no key; `JEV_CODE_PROVIDER=ollama`, `OLLAMA_HOST` optional | `nimble` | [docs.ollama.com/capabilities/decision](https://docs.ollama.com/capabilities/decision) |\n\nHow the host is chosen:\n\n- The variable decides. A key is sent to the host of the variable it sits in, whatever it looks\n  like; key shapes change (TypeSafe issues both `ts_...` and `apikey_...` keys), so jev-code never\n  guesses from them. `doctor` adds a hint when a key looks like it belongs elsewhere.\n- `TYPESAFE_API_KEY` is the generic variable the TypeSafe SDK reads, so it follows\n  `TYPESAFE_BASE_URL` and `JEV_CODE_PROVIDER` the way the SDK does: pointing the base URL at\n  OpenRouter or Vercel AI Gateway sends it there. A host-specific variable never travels.\n- When several keys are set, the first row in the table wins. `doctor` says which one is in use.\n- `JEV_CODE_PROVIDER=openrouter` (or `typesafe`, `vercel`, `openai`, `ollama`) forces a host.\n  OpenAI is never picked up from an ambient `OPENAI_API_KEY`: that variable is set in many shells\n  for other reasons, so sending agent evidence there is a decision you make with\n  `JEV_CODE_PROVIDER=openai` (or by pasting an OpenAI key when `setup` asks, which stores both).\n  Ollama has no key to detect, so it is chosen the same way.\n- A host-specific key is only ever sent to its own host; a base URL that disagrees is refused\n  before any request. The exact rules are in [SECURITY.md](SECURITY.md).\n\n| Variable | Default | Purpose |\n| --- | --- | --- |\n| `JEV_CODE_PROVIDER` | auto | Force `typesafe`, `openrouter`, `vercel`, `openai`, or `ollama` (required for the last two). |\n| `OLLAMA_HOST` | `localhost:11434` | Ollama's server, as a URL, `host:port`, or bare host. |\n| `TYPESAFE_BASE_URL` | per host | A proxy, or a System One gateway of your own; the client appends `/v1/systemone`. TypeSafe keys only, unless `JEV_CODE_PROVIDER` is set. |\n| `TYPESAFE_DEFAULT_MODEL` | per host | Pin a Jev version: `jev-1.13` on TypeSafe or OpenRouter; Vercel uses `typesafe-ai/jev`. |\n| `JEV_CODE_TIMEOUT_MS` | `30000` | Per-attempt timeout. |\n| `JEV_CODE_MAX_RETRIES` | `2` | Retries on 429, 5xx, timeouts, and connection errors. |\n\nThe `TYPESAFE_*` names match the official TypeSafe SDKs, so one export serves everything.\n\n### OpenAI Decisions API (public beta)\n\nOpenAI's Decisions API answers the same three question shapes (yes/no, pick one, score on\nlevels) with probabilities, served by GPT-6 Luna. It opened to every developer in public beta on\nOctober 6, 2026, with general availability expected in the following weeks; see OpenAI's\n[guide](https://developers.openai.com/api/docs/guides/decisions). jev-code maps every tool onto\nit, so the payloads and results are unchanged, with these differences:\n\n- The request shape differs from System One. jev-code translates it, following OpenAI's\n  [API reference](https://developers.openai.com/api/reference/resources/decisions/methods/create).\n- Yes/no questions have no separate criteria field, so `yes` and `no` descriptions are folded\n  into the instructions. Score legends are rebuilt from your levels.\n- The model can decline a question while answering the others. That item comes back with\n  `status: \"refused\"` and a `review` decision (an `uncertain` verdict in `jev_check`), and\n  `jev_ask` lists its id under `refused`. Retrying the same input will not change it.\n- The API also takes images; the tools stay text-only, as they do on every host.\n- Pricing is OpenAI's: at launch, $0.10 per million input tokens and nothing for output. Tool\n  outputs carry `usage`.\n\nIt stays opt-in. `OPENAI_API_KEY` is set in many shells for other reasons, so sending agent\nevidence to OpenAI takes `JEV_CODE_PROVIDER=openai` (or pasting the key when `setup` asks). A\n`403` from the API is reported in plain words by `doctor --live`.\n\n### Ollama (local)\n\nOllama 0.35 and later serves decision models locally behind the very same System One API, so\nnothing leaves your machine and there is no key. Install Ollama, pull a model, and opt in:\n\n```bash\nollama pull nimble\nexport JEV_CODE_PROVIDER=ollama\nnpx -y @french-castle/jev-code@latest doctor --live\n```\n\n`nimble` is the default; `tev1`, `clef`, and `clef-flash` work too (`TYPESAFE_DEFAULT_MODEL`\npicks one). `OLLAMA_HOST` points at a server other than `localhost:11434`, in Ollama's own\nnotation. Image inputs, which `clef` supports, are not exposed by the tools. `doctor --live` says\nwhen the server is down or the model is not pulled.\n\n### Your own gateway\n\nAny server that speaks the System One API (`POST /v1/systemone`, same request and response\nshapes) works without a row in the table: it is the proxy case the TypeSafe SDK already knows.\nThe gateway's key goes in `TYPESAFE_API_KEY`, the SDK's generic variable, and its address in\n`TYPESAFE_BASE_URL`; `TYPESAFE_DEFAULT_MODEL` names the model when the gateway does not serve\n`jev-latest`:\n\n```bash\nexport TYPESAFE_API_KEY=...                            # the gateway's key\nexport TYPESAFE_BASE_URL=https://gateway.example/api  # the client appends /v1/systemone\nexport TYPESAFE_DEFAULT_MODEL=vendor/jev              # when the gateway's model id differs\n```\n\n`setup` offers the same thing when it asks which host a pasted key is for: choose \"Other System\nOne gateway\", give the URL and the model, and the three variables go where the key would have\ngone. The URL is checked before anything is sent: an absolute `http(s)` URL with no credentials,\nquery, or fragment, stopping before `/v1/systemone`. A host-specific key (`OPENROUTER_API_KEY`\nand the like) never follows `TYPESAFE_BASE_URL` to a gateway unless `JEV_CODE_PROVIDER` names\nits host; `doctor` shows where requests go.\n\n## Security notes\n\n- Only the payload you pass to a tool leaves your machine, and only to the host your key\n  belongs to. Nothing is read from your repository or session on its own.\n- Keys are read from the environment, sent only to the host that issued them, and never\n  logged. `setup` copies the key in use into harness configs so filtered environments still\n  work; `--no-env` skips that.\n- Existing config files are backed up before `setup` modifies them.\n\nHosts, the proxy rule, what `setup` executes, and how to report a vulnerability:\n[SECURITY.md](SECURITY.md).\n\n## How it works\n\n`src/tools/` holds the single definition of each tool: a zod schema, a description, and a `run`\nfunction that builds one System One request and maps the answers to decisions. The MCP server\n(`src/mcp/`), the Pi extension (`integrations/pi/`), the OpenCode custom tool\n(`integrations/opencode/`), and the CLI (`src/cli/`) are thin adapters over that layer, which is\nwhy the payloads and results are identical everywhere. `src/core/providers.ts` is the table of\nhosts that serve Jev; adding one that speaks the System One API is a row there. `src/setup/` knows\nwhere each harness reads skills and MCP configuration and prefers each harness's own CLI over\nediting files.\n\n## Development\n\n```bash\ngit clone https://github.com/FrancoisChastel/jev-code && cd jev-code\nnpm install\nnpm run check          # lint, typecheck, skill validation, tests with coverage, build, smoke\nnpm test               # unit tests, no API key needed\nTYPESAFE_API_KEY=... npm run test:e2e   # a few live calls; any provider key works\n```\n\nTry your local build against a real harness without publishing:\n\n```bash\nnpm run build\nnode dist/cli.js setup claude --command \"node $PWD/dist/cli.js mcp\"\nnode dist/cli.js setup pi --pi-source \"$PWD\"\n```\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for conventions and the release process.\n\n## Related\n\n- [typesafe-ai/skills](https://github.com/typesafe-ai/skills): TypeSafe's own skill for *building* products on Jev. jev-code is about using Jev *inside* the coding agent; its [building-with-typesafe reference](skills/jev/references/building-with-typesafe.md) adapts the official skill's guidance (MIT, TypeSafe AI) for that case.\n- [jkudish/jev-mcp](https://github.com/jkudish/jev-mcp) and [itsmostafa/typesafe-mcp](https://github.com/itsmostafa/typesafe-mcp): other MCP servers for Jev, with different tool sets.\n- [TypeSafe docs](https://docs.typesafe.ai) and the [llms.txt index](https://docs.typesafe.ai/llms.txt).\n- Jev on [OpenRouter](https://openrouter.ai/docs/guides/community/typesafe-sdk) and\n  [Vercel AI Gateway](https://vercel.com/docs/ai-gateway/sdks-and-apis/typesafe), the hosts jev-code\n  supports besides TypeSafe. [Cloudflare Workers AI](https://developers.cloudflare.com/ai/models/typesafe/jev/)\n  also serves Jev but with a different request envelope; it is not supported yet.\n\n## License\n\n[MIT](LICENSE) © François Chastel. `skills/jev/references/building-with-typesafe.md` adapts the\n[TypeSafe agent skill](https://github.com/typesafe-ai/skills), © 2026 TypeSafe AI, MIT. Jev and\nTypeSafe are trademarks of TypeSafe AI; this project is not affiliated with TypeSafe.\n","readmeFilename":"README.md"}