jev-agent-router

September 18, 2026 ยท View on GitHub

Picks the agent that fits the task, then explains, abstains, or falls back once.

Author: Pinuts. MIT license.

Part of JEV Labs.

Stack: Python 3.10+, HTTP, MCP stdio, Docker, HTML demo.

After jev-agent serve: demo

The problem The solution

Permissions and fallback Works everywhere

Local, no keys

git clone https://github.com/Pinutss/jev-agent-router
cd jev-agent-router
uv sync
uv run jev-agent demo
uv run jev-agent serve

No agent and no LLM are required. JEV_PROVIDER=auto (the default) stays on the local heuristic. If JEV and a gateway are configured, they are used as the judge. Docker:

docker compose up

What the prototype does

The router chooses an agent from a registry. It explains the choice, abstains if no candidate is safe, and allows only one fallback hop.

It does not run agents and does not ship them.

Permissions come only from the registry and the caller constraints. The task, a tool, or a model cannot add them.

Cursor and Hermes plugin

This repository is an Agent Plugin. Cursor and Hermes can install it directly.

Hermes

hermes plugins install Pinutss/jev-agent-router --enable

Cursor

Install from the JEV plugins marketplace, or copy this folder to ~/.cursor/plugins/local/jev-agent-router.

One tool: agent_route. Pass task + agents. Keys stay in the process environment, not in the call.

Requires uv. JEV_PROVIDER defaults to local.

Hermes and OpenClaw

Yes, locally. The MCP process does not need JEV or a gateway:

uv run jev-agent mcp

One tool: agent_route. Pass task + agents. Keys stay in the process environment, not in the call.

Hermes (~/.hermes/config.yaml):

mcp_servers:
  jev-agent:
    command: uv
    args: ["run", "--directory", "/path/to/jev-agent-router", "jev-agent", "mcp"]
    env:
      JEV_PROVIDER: local

OpenClaw (~/.openclaw/openclaw.json, or Settings > MCP > Stdio):

{
  "mcp": {
    "servers": {
      "jev-agent": {
        "command": "uv",
        "args": ["run", "--directory", "/path/to/jev-agent-router", "jev-agent", "mcp"],
        "env": { "JEV_PROVIDER": "local" }
      }
    }
  }
}

Python

from jev_agent_router import AgentRouter, DEFAULT_AGENTS

result = AgentRouter(provider="local").route(
    task="Fix the CORS bug in the FastAPI API",
    agents=DEFAULT_AGENTS,
    required_permissions=["read_code"],
    scope="demo",
)
print(result.decision, result.selected.id if result.selected else result.abstain_reason)

JEV + several LLMs (optional)

If you wire the cloud later: JEV_API_KEY / JEV_BASE_URL, plus an OpenAI-compatible gateway. Keys stay in the environment, never in the HTTP body or the MCP call.

One multi-model key (OpenRouter):

JEV_PROVIDER=jev
OPENROUTER_API_KEY=sk-or-...
JEV_LLM_DEFAULT=openrouter:anthropic/claude-sonnet-4
JEV_LLM_STRATEGY=named

Several providers:

OPENROUTER_API_KEY=sk-or-...
OPENAI_API_KEY=sk-...
GROQ_API_KEY=gsk_...
JEV_LLM_PROVIDERS=openrouter,openai,groq
JEV_LLM_STRATEGY=cheapest

Or a JSON catalog via JEV_MODELS_FILE. Classic GATEWAY_* still works.

cp .env.example .env
uv run jev-agent llms

GET /v1/llms lists the public catalog (has_key, api_key_env), never the raw key. To pick the judge from the call: gateway_provider, gateway_model, llm_prefer.

JEV_PROVIDER=jev will not start if JEV or no usable LLM is configured. With auto, missing keys just keep the local heuristic.

HTTP

uv run jev-agent serve

GET /healthz, POST /v1/route. Binds 127.0.0.1. The body must not contain keys.

Local validation

uv run jev-agent benchmark

Annotated set in benchmarks/annotated_tasks.json. This is a local baseline, not a live JEV trial.

Limits

Local ranking is lexical and deterministic. Scope isolates lists, it is not auth. One fallback hop. No agent runtime. No store, no PyPI yet.

docs/vision.md is a long-term target, not the current contract.