Skip to main content
Glama
README.md
# Jev-chooses-a-LLM

**Jev Router for Cursor**

**Cursor executes. LLMs write and build. Jev decides how much intelligence the task deserves.**

Honest promise: pick the **cheapest available route likely to complete successfully under policy** — not a mathematically optimal model.

TypeSafe **Jev** is a decision layer only (Choice / Score / Noul). It does not browse, write prose, edit files, or operate accounts. Env: `TYPESAFE_API_KEY`.


## Personal smoke test

In the Cursor Agents window for this project, paste:

```text
Find today's most popular public posts about TypeSafe Jev on X/Twitter (by views if available). Rank the top 5 and say why each is popular. Do not log in or post anything.
```

Expected: Jev routes first (often BALANCED), then work uses web/research tools. In chat this is soft routing; for hard model switch use SDK `--run`.

## Chat vs SDK (read this)

| Mode | What changes | What does not |
| --- | --- | --- |
| Cursor Chat + MCP | Parent calls `jev_route`, may delegate to `jev-cost` / `jev-balanced` / `jev-intelligence` | Parent chat model is not hot-swapped |
| SDK `--run` | Jev decides tier, then `Agent.create` uses the resolved model from your catalog | Needs `CURSOR_API_KEY` |

Approval gates (`production_deploy`, `financial_transaction`, …) stop SDK runs unless you pass `--approve`.

## What this product is

| Mode | Enforcement | How routing works |
| --- | --- | --- |
| **Chat (soft)** | Rule + MCP + subagents | Parent calls `jev_route`, then delegates to `jev-cost` / `jev-balanced` / `jev-intelligence`. Does **not** hot-swap the parent model. |
| **SDK (hard)** | Code path | `route → validate → discover models → Agent.create/send` with selected model / `auto-smart` `optimize_for`. Supports dry-run and escalation. |

## Hard routing rules (deterministic)

1. `confidence < 0.70` → **BALANCED**
2. Security-sensitive → at least **INTELLIGENCE**
3. Financial / production deploy → **INTELLIGENCE** + human approval flag
4. Send/delete email, publish → approval required
5. Read-only research OK; simple reversible edit may be **COST**
6. COST fail → BALANCED → INTELLIGENCE → **stop**
7. Max **2** escalations; no infinite retry; no same-tier retry unless error says retry can succeed
8. Jev unavailable → **BALANCED** + `degradedRouting: true`


## What you need for a *working* system

This repo is enough to run end-to-end **if** you bring keys and follow the right mode.

### Required for routing (Jev)

1. Node.js 20+ (22.13+ recommended; 22+ for `--use-system-ca` on Windows TLS issues)
2. `TYPESAFE_API_KEY` in local `.env` (never commit)
3. `npm install && npm test && npm run demo`

### Required for real model switching (SDK)

4. `CURSOR_API_KEY` in `.env`
5. `npm install @cursor/sdk` (optionalDependency / peer)
6. Run:

```bash
npx tsx sdk-runner/cli.ts --run "your task"
# Windows TLS/antivirus MITM:
# $env:NODE_OPTIONS="--use-system-ca"
```

### Cursor Chat (soft mode)

7. Symlink/copy this folder into `~/.cursor/plugins/local/Jev-chooses-a-LLM` (see `scripts/setup.sh`)
8. Enable MCP `jev-router`
9. **Honest limit:** chat parent model is **not** hot-swapped. Jev decides the tier; the parent (e.g. Grok) may still execute unless you use SDK `--run`.

### Not included / not claimed

- Your personal API keys
- Guaranteed Cursor Router `auto-smart` (account-dependent; we fall back to catalog models)
- Automatic X login / posting
- Dollar cost when the plan does not expose billed cents

## Clone

```bash
git clone https://github.com/Bodila51/Jev-chooses-a-LLM.git
cd jev-router-for-cursor
cp .env.example .env
# put TYPESAFE_API_KEY (and CURSOR_API_KEY for SDK --run) in .env — never commit it
npm install
npm test
npm run demo
```

## Install

```bash
cd jev-router-for-cursor
cp .env.example .env   # set TYPESAFE_API_KEY; CURSOR_API_KEY for live SDK
npm install
npm test
npm run demo
```

### Cursor Chat plugin (local)

```bash
./scripts/setup.sh
# or: ln -s "$(pwd)" ~/.cursor/plugins/local/jev-router-for-cursor
```

Enable the plugin in Cursor. Set variable `TYPESAFE_API_KEY` (Plugins → Configure) or export it for the MCP process. Restart Cursor if needed.

### MCP only

```bash
npm run mcp
# or: npx tsx mcp/server.ts
```

Tools: `jev_route`, `jev_dry_run`, `jev_status`.

`mcp.json` wires the server for the plugin via `${CURSOR_PLUGIN_ROOT}`.

## Commands (Chat)

| Command | Effect |
| --- | --- |
| `/jev-route` | Route only |
| `/jev-run` | Route then delegate to subagent |
| `/jev-dry-run` | Dry-run routing |
| `/jev-bypass` | Skip Jev this turn |
| `/jev-status` | Config + hard rules |

## SDK runner

```bash
# Dry-run (no CURSOR_API_KEY required for routing path)
npm run dry-run -- "Rename foo to bar in util.ts"

# Route only
npm run route -- "Research TS test runners"

# Status
npx tsx sdk-runner/cli.ts --status

# Live run (needs CURSOR_API_KEY and Node >= 22.13 for @cursor/sdk)
npx tsx sdk-runner/cli.ts --run "Fix the failing auth test"
```

Programmatic:

```ts
import { runRoutedTask } from "./sdk-runner/index.js";

const result = await runRoutedTask({
  facts: { task: "…", repoPresent: true, needsEdit: true },
  dryRun: true,
});
```

### Models

- Prefer **Cursor Router**: `auto-smart` + `optimize_for`: `cost` | `balanced` | `intelligence` when `Cursor.models.list()` shows it.
- If missing: pick real catalog IDs for the three tiers; never invent IDs.
- Offline/static fallback in `config.example.json` documents `composer-2.5` only as a last resort label.

### Cost

`run.usage` / `agent.getUsage()` — if cost is unavailable it is labeled **`unavailable`**. This product never invents dollar amounts.

## Config

See `config.example.json`:

```json
{
  "enabled": true,
  "defaultMode": "balanced",
  "confidenceThreshold": 0.7,
  "maximumEscalations": 2,
  "maximumTaskCostUsd": 1.0,
  "showRoutingTrace": true,
  "logPromptContent": false,
  "requireApprovalFor": ["send_email","delete_data","publish","production_deploy","financial_transaction"]
}
```

Kill switch: `"enabled": false` or `/jev-bypass`.

## Architecture

```
User task
  ├─ Chat: rule → MCP jev_route → subagent jev-{cost|balanced|intelligence}
  └─ SDK:  facts → Jev → policy → model catalog → Agent.create/send → escalate
```

Shared: `shared/config.ts`, `shared/telemetry.ts`, `shared/redaction.ts`  
MCP: `mcp/server.ts`, `mcp/router.ts`, `mcp/policy.ts`, `mcp/typesafe-client.ts`  
SDK: `sdk-runner/*`

## Skills (optional)

- `email-triage` — Jev classify/rank only; no send
- `research-rank` — Jev ranks candidates; Cursor browses/writes

## Testing

```bash
npm test
```

Uses mock TypeSafe client and fixtures (11 product scenarios). No real API keys required in CI.

Chat mode is **soft-enforced** (rule + agents). SDK mode is **hard-enforced** in code.

## Security

See [SECURITY.md](./SECURITY.md). Never commit `.env`. Telemetry redacts secrets; prompts off by default.

## Limitations

- Chat cannot force the parent model ID; it delegates to subagents.
- Live `@cursor/sdk` needs **Node >= 22.13** and `CURSOR_API_KEY`.
- Without `TYPESAFE_API_KEY`, dry-run/demo uses a deterministic mock; live Chat routing should set the key or expect `degradedRouting`.
- Optional Gmail/X are not bundled OAuth apps — skills document the pattern only.

## Uninstall

```bash
rm -f ~/.cursor/plugins/local/jev-router-for-cursor
# remove MCP entry / disable plugin in Cursor
```

## License

MIT — see [LICENSE](./LICENSE).