npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@danipl/opencode-jev

v1.2.0

Published

Route OpenCode tool selection through TypeSafe System-1 (Jev): a cheap fast model picks the next tool so the reasoning model executes instead of deliberating.

Readme

npm CI license OpenCode V2

latest release

Your reasoning model should think about your problem — not about which of twelve tools to call. opencode-jev puts TypeSafe's cheap, fast System-1 model in front of every inference request: it picks the next tool, trims the request to that one tool, and lets the expensive model do what you pay it for.

How it works · Developer guide · CI/CD · Config example


Why

Every iteration of an agentic loop re-sends the whole conversation plus every tool schema to a premium model, which burns tokens and latency deliberating between read, grep, edit, bash, MCP tools… — a routing decision, repeated every turn, billed at reasoning prices.

The fix: this plugin observes each outbound inference request (OpenCode V2 http.request session hook), asks Jev — a cheap, fast, calibrated System-1 model — which of the request's tools comes next, and when Jev is confident enough, trims the tools array down to that single tool. The reasoning model then executes instead of deliberating. Dropped tool schemas also shrink the request itself.

flowchart LR
    O["OpenCode<br/>agent loop"] -->|request · 12 tool schemas| J{{"jev plugin<br/>ask System-1"}}
    J -->|"confident ✓<br/>tools: [1]"| L["Reasoning model<br/>executes immediately"]
    J -->|"not confident ✗<br/>request untouched"| L
    style J fill:#12101f,stroke:#818cf8,color:#e2e8f0
    style L fill:#0b0b14,stroke:#22d3ee,color:#e2e8f0
    style O fill:#0b0b14,stroke:#e879f9,color:#e2e8f0

Trimming — not pinning via tool_choice — is deliberate: providers reject forced tool_choice in thinking mode (HTTP 400), while a single offered tool is always valid.

The full picture — diagrams inside the agentic loop, the token/latency math, and the trust dial — lives in docs/HOW_IT_WORKS.md.

At a glance

| | | | --- | --- | | ⚡ System-1 routing | Jev answers "which tool next, and how sure am I?" — fast, cheap, calibrated. | | ✂️ Trim, don't pin | Only the tools array shrinks; tool_choice is never touched. Always provider-valid. | | 🛡️ Fail-safe by design | Low confidence, network error, timeout, parse error, bad key → original request passes through untouched. It can never break a session. | | 🔭 Live decision log | Every request ends in one tagged line — apply: or bypass: with the reason. tail -f it. | | 🫥 Invisible when unconfigured | No API key → no hook registered, no log file, zero latency. | | 🔌 Any compatible gateway | Anthropic Messages (/v1/messages), OpenAI Chat Completions (/chat/completions), OpenAI Responses (/responses) — path-matched. |

Quick start

1. Register the plugin — OpenCode installs it automatically on next start:

// opencode.jsonc — project-level or ~/.config/opencode/
{
  "plugins": ["@danipl/opencode-jev"]
}

Requires OpenCode V2 (Plugin.define API; V1 hosts reject it).

The bare name tracks the latest dist-tag — every publish moves it, so a plain "plugins": ["@danipl/opencode-jev"] keeps you current with zero maintenance. Pin an exact version for reproducibility or to freeze a known-good release:

{ "plugins": ["@danipl/[email protected]"] } // x-release-please-version — exact version, never auto-updates

Heads-up while pre-1.0: feat: releases (minor bumps) can change behavior. If that matters to you, pin; otherwise latest is the recommended choice.

2. Set an API key — either method:

export TYPESAFE_API_KEY="apikey_..."

or copy jev.yaml.example to jev.yaml next to your OpenCode config (or anywhere, pointed to by JEV_CONFIG_PATH).

3. Watch it route:

tail -f /tmp/opencode-jev.log

That's it. Run a session — you'll see apply: lines where Jev trimmed the tools and bypass: lines (with reasons) where the request went through untouched.

Configuration

Config sources — first defined value wins per field:

  1. $JEV_CONFIG_PATH file (JSON or YAML)
  2. ./jev.config.yaml / .yml / .json
  3. ./.opencode/jev.yaml / jev.json
  4. ~/.config/jev/config.yaml / config.json
  5. plugin options (directory-package registrations only)
  6. env TYPESAFE_API_KEY / JEV_API_URL / JEV_MIN_CONFIDENCE

Config-file fields: apiKey, apiUrl, minConfidence, model, timeoutMs (milliseconds; non-positive or bogus values count as unset) — see jev.yaml.example. JEV_MODEL / JEV_TIMEOUT_MS are env fallbacks for model / timeoutMs.

| Env var | Default | Meaning | | --- | --- | --- | | JEV_MODEL | jev-latest | Jev model id (fallback for model) | | JEV_TIMEOUT_MS | 2000 | Jev round-trip timeout (fallback for timeoutMs) | | JEV_DEBUG_FILE | /tmp/opencode-jev.log | decision log path | | JEV_DEBUG | — | 1 echoes the log to stdout | | JEV_DEBUG_MAX_BYTES | 262144 | log rotation cap (one .1 backup) |

Safety

Jev must never break a session. The request passes through untouched on: low confidence, respond_to_user, payloads with no usable tools or an already-pinned tool_choice, network failure, timeout, parse errors, or an invalid API key (latched off after the first 401/403 — zero added latency afterwards). Only primary agent-loop requests are considered (event.kind === "primary"); title/compaction traffic is skipped. Responses-API built-in tools (type !== "function") are never offered to Jev, never trimmed to, and never removed by a trim — they always survive (issue #12 verdict: Jev may only demote function tools).

Reading the decision log

Every decision is appended to the debug log — tail -f /tmp/opencode-jev.log to watch routing live. Each request ends in one tagged line:

  • apply: — Jev acted; tools trimmed to its pick (+ any built-ins kept).
  • bypass: — request untouched, with the reason.

Line-by-line interpretation: docs/DEVELOPMENT.md — "Reading the decision log".

Privacy

With routing active, every eligible request POSTs a compact snapshot to apiUrl (default https://api.typesafe.ai/v1/systemone — TypeSafe's endpoint; override with the apiUrl config field or JEV_API_URL). The snapshot contains:

  • state — the first user message plus the last 4 conversation turns, each turn capped at 2 KB and the whole payload at 8 KB. In a coding agent those turns routinely contain file contents, tool output, and error messages — treat this like sending context to another model provider.
  • Tool names — up to the first 254 names, offered as routing choices. Names only, never schemas or descriptions.

No apiKey configured = no hook registered = nothing ever leaves your machine. If conversation egress is not acceptable at all, leave the plugin unconfigured or point apiUrl at a self-hosted Jev-compatible endpoint.

Development

Full developer guide — architecture, unit testing, local manual testing with OpenCode, PR workflow, SDLC: docs/DEVELOPMENT.md.

npm install
npm run build        # tsc -> dist/
npm pack             # inspect the tarball

Local trial without publishing — point OpenCode at the checkout:

{ "plugins": ["/absolute/path/to/opencode-jev"] }

Releasing

Fully automated via release-please — the commit type picks the bump: fix: → patch, feat: → minor, feat!: or a BREAKING CHANGE: footer → major. Merge the resulting PR and a release PR appears; merge that and the version bump, tag, GitHub Release and npm publish happen on their own. See docs/CICD.md.

License

MIT — © danipl