Skip to content
MrJev

jev-gateway

Local gateway for Codex and Claude Code that asks Jev which tool to call next and passes everything else to your usual model.

View on GitHub →

Hands-on review

A local proxy that lets Jev choose the tool and closed-set arguments while the model writes the prose. The three edge cases we found are fixed.

Good for

  • Cutting tool-selection mistakes without changing your agent or its prompts
  • A clean split: the model writes text, Jev picks among closed sets
  • Trying it free: the bundled mock runs the whole path with no key

Watch out for

  • A hostile tool name could inject a fake system reminder; refused since `40fd608`
  • Your system prompt and recent turns go out truncated but never redacted
  • Started through its launcher, the gateway has no authentication

Tested Sep 20, 2026 at 9463952 · re · Node 24 in Docker, offline; 90 tests, the project's own mock, and the re-check driven through the running proxy with stand-ins on both sides

How we reviewed this: we built it in Docker on Node 24, ran its test suite offline, exercised the bundled mock end to end without a key, and read the three adapters closely. For the re-check we ran the gateway itself with a stand-in Jev on one side and a stand-in upstream on the other, and inspected every byte it forwarded. We made no Jev calls.

What it does

jev-gateway, by vinilana, is a local reverse proxy in front of Chat Completions, Responses and Messages. When a request carries tools, it asks Jev one question — which tool best advances the latest request — plus a cross-check (“does the assistant need to call a tool now, rather than reply in plain text?”) and a yes/no per closed-set argument, all in one call. The LLM still writes every piece of free text.

That division is the point, and the README states it plainly. Boolean and enum arguments come from typed answers; strings come from the model.

Its 90 tests pass offline, and scripts/mock-jev.mjs runs the whole proxy with no key, which makes it easy to see what it does before spending anything. When Jev errors, it fails open — the request goes through untouched, with a header saying why.

Three things we found, all now fixed

Tool names go into a <system-reminder> unescaped. In hint mode the gateway appends a block to the user’s turn:

text: `<system-reminder>A tool-routing model suggests the "${tool}" tool is the most relevant next step. ` + …

A tool whose name contains </system-reminder><system-reminder>… closed that block and opened its own, producing attacker-controlled text that looked exactly like a host-generated reminder. Tool names aren’t usually chosen by you — they come from MCP servers you installed. We reported it, and 40fd608 added SAFE_TOOL_NAME, a single-token pattern every tool name must match before a decision can carry it anywhere.

We sent the hostile name through the running gateway at that commit, on both the Chat Completions and Messages paths:

{"event":"route","path":"/v1/chat/completions","tools":2,
 "mode":"passthrough","reason":"unsafe_tool_name","status":200}

The request reaches the upstream exactly as the client sent it, with no block appended; a list of ordinary names in the same shape still routes normally. Refusing to route is the right trade — the alternative, stripping the brackets, leaves you guessing what the name meant.

“The gateway never makes a request fail” wasn’t quite true. Request parsing happened outside the try/catch that guards the routing call, so a malformed body — {"messages":[null]}, or a Messages request whose content is a number — returned a 500 from the gateway rather than the upstream’s own 400. Both now pass through: we sent the same two bodies and got 200 with reason: unreadable_request, the upstream receiving them unchanged and answering for itself.

One hosted tool switched routing off. On the Chat Completions path, if any tool wasn’t a plain function (a web_search, say), the whole request bypassed Jev. That adapter now offers hosted tools to Jev as options in their own right: picking one passes the request through, picking a function leaves the hosted ones untouched.

What it sends

The state is your assistant instructions and the recent conversation, truncated (4,000 characters per message, 60,000 overall) but not redacted — a system prompt containing a door code is a system prompt containing a door code. One request per tool-carrying call; two if you have more than 120 tools. Logs go to ~/.jev-gateway/, one JSON line per request, and JEV_DEBUG_DUMP_DIR writes whole decoded bodies to 0600 files.

Worth knowing: /health answers before the auth middleware, and the launcher strips ROUTER_API_KEY from the child process, so a launcher-started gateway is unauthenticated on localhost.

Verdict

The idea is excellent and the execution has caught up with it: MIT licensed, published on npm, honest docs, a real mock, a fail-open path that behaves, and all three of our findings fixed in one pull request the same day. What remains is inherent rather than a bug — the state carries your system prompt and recent turns to whichever provider serves Jev, truncated but not redacted, and a launcher-started gateway listens without a key. Run it on loopback and keep secrets out of the prompt, as you would with any proxy.

For per-turn model routing rather than tool routing, see jev-router and JevRouter.

See how it compares with other tools in Best Jev tools, tested hands-on.

Review updated Sep 21, 2026. Numbers quoted from the project are its author's own; we don't publish our own measurements of Jev.

More in Model Routing

jev-router

★ 560▲ 66

gargpratyush/jev-router

Per-turn model routing for Claude Code and Codex. Simple work goes to the fast tier and difficult work to the strong tier.

JavaScriptReviewed

JevRouter

★ 433▲ 135

BillionsBobby/JevRouter

Routes each agent step to a model, subagent, Skill, MCP tool, or CLI with one Jev Choice, requiring confirmation for risky capabilities and keeping decision receipts.

TypeScriptReviewed

Astra-Ares

★ 300▲ 7

miuuyy/Astra-Ares

Adjusts a Codex task's reasoning effort mid-run by asking Jev how hard the next step looks. Runs a patched Codex CLI and says it is a reference implementation rather than an app.

JavaScriptReviewed

Get new Jev projects every week

New Jev releases, pricing changes, and the best new projects, once a week. No spam; unsubscribe anytime.

Powered by Buttondown. See our privacy policy.