A UserPromptSubmit hook that routes every prompt you send. It asks
TypeSafe Jev a few typed questions about the prompt, then
tells Claude where the work should run: on Claude, or on an open-model lane
(ClinePass or Codex). The answers go back as additionalContext, and one line tells
you which model got the job.
Jev never writes text. It returns calibrated probabilities. This hook turns those numbers into routing; all the wording and every threshold live in the scripts, not in the model.
This section is for someone who does not write code. Follow the steps in order. Each step is one action. Copy and paste the commands exactly.
A "terminal" below means the Terminal app on your Mac. "Claude Code" means the Claude Code program you already use.
Tick each one off. Only the first group is required. Everything else switches on a feature, and the "Without it" column says what you lose.
Required
| Tick | What | What it is for | Where to get it | Where it is stored |
|---|---|---|---|---|
| [ ] | Claude Code | The program this plugin runs inside. | Your existing Claude Code install. | Nothing to store. |
| [ ] | git | Downloads this repo. | Already on most Macs (/usr/bin/git). |
Nothing to store. |
| [ ] | Python 3.10 or newer | Every script here is Python. No extra packages needed. | python.org, or any Python 3 you already have. | Nothing to store. |
| [ ] | A TypeSafe API key | Lets Jev judge each prompt. | https://console.typesafe.ai/keys | TYPESAFE_API_KEY in the env block of ~/.claude/settings.json (Step 4). |
Without a TypeSafe key, and without an OpenRouter key, the hook does nothing and your prompt goes through untouched. With an OpenRouter key but no TypeSafe key, Jev is asked through OpenRouter instead.
Optional
| Tick | What | What it is for | Without it | Where to get it | Where it is stored |
|---|---|---|---|---|---|
| [ ] | jev command (the TypeSafe command-line tool) |
Skill ranking, and the spend log (jev usage). |
Triage still works by a direct request. Skill ranking is skipped. | Not included in this repo (Step 4). | Your key: jev auth set paste-your-key-here saves it to ~/.config/typesafe/api_key. Or it reads TYPESAFE_API_KEY. |
| [ ] | Node and npm (install Node with nvm) |
pi is a Node program. The scripts look for pi inside ~/.nvm/versions/node/*/bin. |
No ClinePass lane. | nvm: https://github.com/nvm-sh/nvm | Nothing to store. |
| [ ] | pi agent command |
Runs the jobs on ClinePass. | No ClinePass lane. Work stays on Claude or Codex. | npm (Step 5). | Its login is saved in ~/.pi/agent/auth.json. |
| [ ] | ClinePass subscription (a Cline account at app.cline.bot) | The flat-fee lane for Kimi K3, DeepSeek and others. | The ClinePass lane stays off. | app.cline.bot | Log in once with pi /login. |
| [ ] | Codex command and a ChatGPT plan | The Codex lane (GPT-6-Luna) and the image tool. | No Codex lane, no image route. | OpenAI Codex: https://github.com/openai/codex, with your ChatGPT login | Log in with codex login. The login lives in ~/.codex/auth.json. |
| [ ] | Cline credits key | Pay-as-you-go backup 1, used only while ClinePass is at its limit. | No Cline-credits backup. | app.cline.bot, then Settings, then API Keys | python3 set-backup-key.py cline saves it in ~/.pi/agent/auth.json. Or set CLINE_CREDITS_API_KEY. |
| [ ] | OpenRouter key | Pay-as-you-go backup 2. Also asks Jev when TypeSafe is down, and powers the "Claude ran out" prompt. | No second backup. No fallback if TypeSafe is down. | openrouter.ai, then Settings, then Keys | python3 set-backup-key.py openrouter saves it in ~/.pi/agent/auth.json. Or set OPENROUTER_API_KEY. |
Notes:
- Python is "standard library only", so there is nothing to
pip install. - You do not need all lanes. One lane is enough. Skipped lanes are skipped automatically.
uuidgenandperlare used bycheck-tools.sh. Both come with macOS.
This repo lists every Jev piece of the original Mac in setup/manifest.json, and one command installs them all: the router, the skills, the plugins (with their settings), the MCP servers, the browser tool, the ClinePass tools and the routing rules. It asks for your TypeSafe key (hidden as you paste it) and saves it only in ~/.claude/settings.json. Re-run it any time; finished steps are skipped.
mkdir -p ~/.claude/skills
git clone https://github.com/rayopavri/jev-setup.git ~/.claude/skills/jev-interceptor
~/.claude/skills/jev-interceptor/setup.sh install
It ends with the few things it can't do for you: logging in to ClinePass and Codex, the optional pay-as-you-go keys, and restarting Claude Code. Add --dry-run to see what it would do without changing anything. Other commands:
setup.sh check: what is installed and what is missing.setup.sh sync: on the original Mac, copy its live skills and hooks back into this repo so the backup stays current. Then commit and push.setup.sh publish: build the public copy (without the private pieces) and push it.
The jev command, the jev skill and the rule guard from the original Mac are not included (they have no licence that allows sharing), and setup.sh skips them. Alternatives: TypeSafe's official plugin typesafe@typesafe-ai (installed by setup.sh) teaches Claude to call Jev, and Abide or Toolgate can take the rule guard's place.
Step 1. Download the repo to the right place. It must go inside ~/.claude/skills.
mkdir -p ~/.claude/skills
git clone https://github.com/rayopavri/jev-setup.git ~/.claude/skills/jev-interceptor
Step 2. Switch the hooks on. There is nothing to type. The folder has a .claude-plugin/plugin.json file, so Claude Code treats it as a plugin, and its hooks/hooks.json wires two hooks: one on every prompt (UserPromptSubmit) and one for when Claude hits its usage limit (StopFailure). Quit Claude Code fully and open it again. (To test without restarting your normal setup, you can start it once with claude --plugin-dir ~/.claude/skills/jev-interceptor.)
Step 3. Put your Jev key in Claude Code's settings. Open ~/.claude/settings.json in a text editor:
open -e ~/.claude/settings.json
Find the "env" block, or add one. Add the key inside it. Replace the placeholder with your real key:
"env": {
"TYPESAFE_API_KEY": "paste-your-key-here"
}
If the file already has an "env" block, add a comma and put the new line inside it. Do not make a second "env". Never share this file.
Step 4. The jev command (optional, not included). If you have a jev command on your PATH, the hook uses it to record spend and to rank skills. Without it the hook still works: it asks Jev directly, and ranks skills through OpenRouter when you have that key. For TypeSafe's official agent skill, see https://github.com/typesafe-ai/skills.
Step 5. Set up ClinePass (skip if you have no ClinePass plan).
- Install Node with nvm (https://github.com/nvm-sh/nvm), then run
nvm install --lts. The scripts only look forpiinside nvm's folder. - Install
piand its ClinePass add-on:
npm install -g @earendil-works/pi-coding-agent
pi install npm:pi-clinepass-provider
- Log in:
pi /login
- If you ever get a "ClinePass login expired" message, repeat the login, then run:
python3 ~/.claude/skills/jev-interceptor/scripts/cline_pause.py clear
Step 6. Set up Codex (skip if you have no ChatGPT plan with Codex). Install Codex from https://github.com/openai/codex, then log in:
codex login
Step 7. Add the pay-as-you-go backups (optional). Each command asks you to paste a key. The key does not show on screen. The script checks the key, saves it, then runs a small tool test that costs roughly 30 cents. Run only the ones you want.
cd ~/.claude/skills/jev-interceptor/scripts
python3 set-backup-key.py cline
python3 set-backup-key.py openrouter
To turn one off later:
python3 cline_pause.py backup off cline
(Use openrouter instead of cline for the other one.)
Step 8. Tell Claude to follow Jev's note. This adds a ready-made section, Jev routing (all projects), to your personal Claude rules file. Run it once only:
cat ~/.claude/skills/jev-interceptor/claude-md-snippet.md >> ~/.claude/CLAUDE.md
Step 9. Install smart compaction (fast-jev-compaction). Optional. This is a copy of tamaratran/fast-jev-compaction (MIT).
- Copy the folder:
cp -R ~/.claude/skills/jev-interceptor/jev-pack ~/.claude/jev-pack
- It needs Claude Code's early-access "function hooks". Add this line to the same
"env"block as Step 3:
"CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1"
- Then run these two commands:
claude plugin marketplace add ~/.claude/jev-pack/plugins/fast-jev-compaction
claude plugin install fast-jev-compaction@fast-jev-compaction
It reads TYPESAFE_API_KEY from the same env block. If anything goes wrong it falls back to Claude's normal compaction.
Step 10. Install the companion skills (optional). The companions/ folder holds copies of two related skills. Copy the ones you want:
cp -R ~/.claude/skills/jev-interceptor/companions/jev-browser ~/.claude/skills/jev-browser
cp -R ~/.claude/skills/jev-interceptor/companions/jev-skill-suggestion ~/.claude/skills/jev-skill-suggestion
-
jev-browser: how to use Ying-Kai Liao's jev-browser (MIT). This copy is only the instructions. Install the browser tool itself like this:git clone https://github.com/Ying-Kai-Liao/jev-browser ~/.local/share/jev-browser cd ~/.local/share/jev-browser && npm install claude mcp add --scope user jev-browser -- node ~/.local/share/jev-browser/bin/jev-browser-mcp.mjs -
jev-skill-suggestion: lets Jev pick one skill per prompt. NeedsCLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1(same line as in Step 9). It takes its own key as a plugin option,typesafeApiKey, or a Vercel AI Gateway key,gatewayApiKey. With neither it uses Claude's built-in classifier.
Step 11. Install the community Jev plugins (optional). These are other people's projects (all MIT), used alongside this one. Install them from their own repos:
| Plugin | What it does | Install |
|---|---|---|
| Jev Belay | A Stop hook that blocks an unverified "done": it reads the transcript for evidence first. | claude plugin marketplace add valentynkit/jev-belay then claude plugin install jev-belay@jev-belay |
| Jev Steer or Queue | Decides whether a message you send mid-turn should steer, queue or interrupt. | claude plugin marketplace add Larkspur-Wang/Jev_steer_or_queue then claude plugin install jev-steer-or-queue@jev-steer-or-queue |
| Compact Adviser | Suggests /compact when work looks finished, to save tokens. |
claude plugin marketplace add kunchenguid/compact-adviser then claude plugin install compact-adviser@compact-adviser |
TypeSafe's official plugin, typesafe@typesafe-ai, teaches Claude to call Jev well: claude plugin marketplace add typesafe-ai/skills then claude plugin install typesafe@typesafe-ai.
The jev MCP server, jev-use (MIT), hands steps that need no text output to Jev: claude mcp add -s user jev -- npx -y jev-use@0.7.1 serve.
The browser tool, jev-browser, is covered in Step 10.
Step 12. Restart Claude Code once more so everything loads.
Run these in order. You can ask Claude to run each one for you.
1. The health check.
sh ~/.claude/skills/jev-interceptor/scripts/check-setup.sh
Success: every line starts with a tick, and the last line says All good. A cross means something needs attention, and the last line says so.
Things to know:
- It reads your Jev key from the session, so run it from inside Claude Code. In a plain terminal it will say the key is missing unless you export
TYPESAFE_API_KEYthere. - It also checks for the CLAUDE.md section from Step 8.
- If you skipped ClinePass, the ClinePass lines show a cross. That is fine.
- The last Jev decision line only turns green after you have sent at least one prompt.
2. Is ClinePass paused?
python3 ~/.claude/skills/jev-interceptor/scripts/cline_pause.py status
Success: it prints ClinePass is open.
If it says paused, it also says why and until when. After you fix the cause (for example, you logged in again), run python3 ~/.claude/skills/jev-interceptor/scripts/cline_pause.py clear.
3. Can the models really use tools? (ClinePass only.)
sh ~/.claude/skills/jev-interceptor/scripts/check-tools.sh
Each model must read a file, run a command and write a file. Success: one PASS line per model. A FAIL line gives the path of a log to read. This can take a few minutes.
4. Did it route a real prompt? Send Claude a normal sentence of a few words (short prompts and slash commands are skipped on purpose). You should see one line like Jev → ... naming the model. After a few prompts, run:
python3 ~/.claude/skills/jev-interceptor/scripts/jev-routing-report.py
Success: it prints Prompts judged: followed by a number that goes up as you work.
For a picture of everything, run python3 ~/.claude/skills/jev-interceptor/scripts/jev-dashboard.py --open.
Set these in the "env" block of ~/.claude/settings.json (same place as the key), then restart Claude Code. Remove the line to turn it back on.
| Setting | What it does |
|---|---|
"JEV_CLINE": "0" |
Turns off all lane routing. Jobs stay on Claude. |
"JEV_PLAN_DELEGATE": "0" |
Turns off the "Claude plans, a lane builds" route. |
"JEV_LANES": "shadow" |
Logs which lane it would pick, but always uses the default lane. |
"JEV_LANES": "off" |
Skips the lane pick entirely. |
"JEV_ROUTER": "0" |
Turns off Claude model-size suggestions. |
"JEV_CODEX": "0" |
Takes the Codex lane out. |
"JEV_RANK_SKILLS": "0" |
Turns off skill ranking. |
To remove it completely, delete the ~/.claude/skills/jev-interceptor folder and restart Claude Code. The hook never blocks a prompt: if anything fails it passes your prompt through untouched.
- Triage: what kind of task this is, whether it needs the repo, whether it is vague, whether it is risky (hard to undo, or reaches outside this machine).
- Routing: picks one route (below) and names the model.
- Skill ranking: grades every installed skill, slash command and agent against the
prompt with
jev rankand lists the ones that fit. - Catalog: notices newly installed or changed skills, commands and agents and asks
Claude to review them (
scripts/jev_catalog.py).
Triage and ranking run at the same time, so the hook costs one round trip of wall time. Expect roughly 1 s per prompt with ranking on and 0.5 s with it off.
You see one line per prompt, for example:
Jev → Claude opus (Opus 5.5) plans it; builds on DeepSeek V4.1 Flash on ClinePass, then DeepSeek V4 Pro if it falls short
The first route that fits wins.
| Route | When | What happens |
|---|---|---|
| Image | The job is to make an image | Codex's image tool on the ChatGPT plan (codex-image.py); OpenRouter's image tool if Codex refuses |
| Lane | Light or standard, offload ≥ 0.70, risk < 0.50 | Claude writes a self-contained task and runs cline-worker.sh; Claude reviews the diff |
| Plan then delegate | Build work ≥ 0.60, risk < 0.50, not a pure explanation | Claude plans and writes work orders; delegate.py builds each one on a lane |
| Claude | Everything else, and all design work | A Claude subagent at the tier Jev sizes |
Jev sizes the job: light → Haiku 4.5, standard → Sonnet 5.5, deep → Opus 5.5. Risk ≥ 0.70 raises it to Opus; vagueness ≥ 0.70 raises it to at least Sonnet.
| Task kind | Lane model |
|---|---|
| UI component | Kimi K3 (ClinePass) |
| Full UI page | Kimi K3 (ClinePass) |
| Logic and code | GPT-6-Luna (Codex, the ChatGPT plan) |
| Long session | Kimi K3 (ClinePass) |
| Design (taste, look and feel, critique) | Always Claude |
| Image | Codex image tool |
| Other, or Jev under 60% sure | DeepSeek V4 Pro (ClinePass) |
The lanes were re-pointed on 2026-10-05 after a benchmark and price review. Kimi K3 led the non-Claude models on UI and websites; the Qwen Max models trailed.
Every job starts on the smallest model likely to do it well, and moves up only when the result falls short. A failed attempt still costs tokens, so "small" means small within the right family, not the cheapest model overall.
- ClinePass: a lane model's smaller ClinePass sibling runs first.
DeepSeek V4 Pro jobs start on DeepSeek V4.1 Flash. Kimi K3 has no smaller sibling
there, so Kimi jobs start on K3. (
CLINE_SMALLincline_pause.py.) This is only for ClinePass, where every model costs the same flat plan. Pay-as-you-go picks the small model by price instead, so its ladder can differ (next section). - Codex: GPT-6-Luna is already the small model. A redo asks it for more reasoning effort.
- Claude: starts at Jev's tier and goes one tier up only if the result falls short. Risky jobs start at Jev's tier, never smaller.
The job runs pay-as-you-go: Cline credits first, then OpenRouter. It stays in the same model family. Here each job is billed per token, so the first try is the model that costs least per job, not always the smallest one. That is why DeepSeek uses V4 Pro only here, while on ClinePass it tries V4.1 Flash first. Some families have one step only.
| Lane model | Pay-as-you-go ladder |
|---|---|
| Kimi K3 | K3 only. Never K2.7 Code: a quarter of the context and weaker scores. |
| DeepSeek V4 Pro | V4 Pro only. On 2026-10-05 Pro cost less per job than V4 Flash on OpenRouter. |
| GPT-6-Luna | Luna, then GPT-6-Sol on a redo |
| Qwen3.8 Max / Qwen3.7 Max | Flash first, then Max (no lane uses Qwen by default) |
The ladders live in BACKUP_TIERS in cline_pause.py. If nothing can take a job, it
stays with Claude. When Claude itself runs out, claude-limit.py asks before any
spend on Claude through OpenRouter.
A lane result is a draft until it is checked. For work orders:
delegate.py run <order.md>builds it on the matched lane, small model first.delegate.py check <id> <result-file>has Jev score the real result against the order's "Done when". Claude also checks the real output.- Short of the bar:
run --escalateredoes it on the full model with sharper feedback. - Still short:
run --upnames the next Claude tier up.
Three attempts at most. delegate.py review <id> pass|redo|fail records the verdict,
so the dashboard can show how each model holds up.
Any failure (no key, no network, a timeout, bad JSON, an unexpected shape) exits 0
with empty stdout. Your prompt reaches Claude untouched, so the session can never be
broken or stalled by this hook. If TypeSafe is down, Jev is asked through OpenRouter
instead (jev_openrouter.py).
All scripts are in scripts/.
| Command | What it does |
|---|---|
python3 jev-dashboard.py --open |
Every routing decision, attempt, check and review on one local page |
python3 jev-routing-report.py |
Scorecard summary of the routing log |
sh check-setup.sh |
Plain-English health check |
check-tools.sh [model ...] |
Verifies models can read, run and write with tools before they carry work |
python3 cline_pause.py status|clear |
ClinePass pause state |
python3 cline_pause.py where <model> |
Where a job for that lane model would run right now |
python3 set-backup-key.py cline|openrouter |
Switches on a pay-as-you-go backup |
All are environment variables. All are optional.
| Variable | Default | What it does |
|---|---|---|
TYPESAFE_API_KEY |
(none) | Jev key. Without it, and without an OpenRouter key, the prompt passes through. |
JEV_ROUTER |
1 |
0 turns Claude tier routing off |
JEV_ROUTER_BASELINE |
opus |
The model you are assumed to be on |
JEV_ROUTER_FLOOR |
haiku |
Never route below this tier |
JEV_CLINE |
1 |
0 turns all lane routing off |
JEV_CLINE_OFFLOAD_MIN |
0.70 |
Offload score a prompt needs to go straight to a lane |
JEV_PLAN_DELEGATE |
1 |
0 turns the plan-then-delegate route off |
JEV_PLAN_BUILD_MIN |
0.60 |
Build-work score that triggers plan-then-delegate |
JEV_LANES |
live |
shadow logs the lane pick but always uses the default; off skips it |
JEV_LANE_MIN |
0.60 |
Below this task-kind confidence, use the default lane |
JEV_CODEX |
1 |
0 takes the Codex lane out |
JEV_CODEX_MODEL |
gpt-6-luna |
The Codex lane's model |
CLINE_DEFAULT_MODEL |
cline-pass/deepseek-v4-pro |
The worker's model when none is given |
CLINE_FALLBACK_MODEL |
cline-pass/kimi-k3 |
The ClinePass stand-in when a lane fails |
CLINE_TIMEOUT |
1200 light / 3600 standard |
Seconds a worker may run |
JEV_RANK_SKILLS |
1 |
0 turns skill ranking off |
JEV_RANK_MIN |
0.75 |
Lowest score a skill needs to be listed |
JEV_RANK_TOP |
4 |
How many skills to list at most |
JEV_MODEL |
jev-latest |
Pin a Jev version |
JEV_TIMEOUT |
8 |
Seconds to wait for triage |
JEV_ROUTING_LOG |
~/.config/typesafe/jev-routing.jsonl |
The routing log |
JEV_QUIET |
(unset) | Any value stops the terminal status line |
A UserPromptSubmit hook cannot switch the main model, and the hook payload does not
say which model is active. JEV_ROUTER_BASELINE is a setting for that reason. If you
switch models mid-session, the router will not notice.
See Install on a new Mac: it lists every account, key and program, which ones are required, and where each key is stored.
scripts/jev-refine.py: the hook. Triage, routes, lane table (LANE_MODEL).scripts/jev_catalog.py: finds every skill, command and agent (personal, project, installed plugins, claude.ai-synced plugins) and tracks which ones were reviewed, in~/.config/typesafe/jev-catalog.json.status,pending,review <name> --line "...",review <name> --keep,scan --baseline. Notices are throttled withJEV_CATALOG_NOTICE_HOURS(default 6);JEV_CATALOG_NOTICE=0turns them off.skill-routing.json: hand-written routing lines for competing design skills (stage, project fit, tools, model fit, tie-breakers). Jev ranks against these instead of the skills' own descriptions, sonpx skills updatecan't undo them.scripts/cline_pause.py: lane state, small-first siblings, pay-as-you-go ladders.scripts/lane-worker.py(viacline-worker.sh): runs one task on a lane.scripts/delegate.py: work orders, Jev's quality check, reviews.scripts/claude-limit.py: theStopFailurehook for when Claude runs out.hooks/hooks.json: wires the two hooks.setup.shandsetup/: the one-command installer (setup/jev_setup.py) and the list of every piece it installs (setup/manifest.json).companions/: copies of the related skillsjev-browserandjev-skill-suggestion. They are snapshots, so copy them again after changing the originals.jev-skill-suggestioncomes from davila7/claude-code-templates (MIT).claude-md-snippet.md: theJev routing (all projects)rules for~/.claude/CLAUDE.md(Install, Step 8).jev-pack/plugins/fast-jev-compaction: a copy of tamaratran/fast-jev-compaction (MIT). It replaces the compaction summary: Jev scores old tool calls and results, stale ones are dropped or truncated, and user and assistant text stays word for word.
MIT, see LICENSE. The two third-party copies keep their own MIT licences:
companions/jev-skill-suggestion/LICENSE and jev-pack/plugins/fast-jev-compaction/LICENSE.