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

@cmaintz/jev-guard

v1.1.0

Published

Framework-agnostic guardrail that vets an LLM agent's proposed tool calls through TypeSafe AI Jev before they execute.

Readme

@cmaintz/jev-guard

A guardrail that sends an LLM agent's proposed tool call to TypeSafe AI's Jev before it runs, and returns allow, block or hold.

Each guarded call costs one Jev request that asks all of the policy's risk questions at once. Your policy turns the typed answers into a verdict in plain TypeScript. Uncertainty never resolves to allow:

  • a score/choice answer below the escalateBelow confidence floor turns allow into hold;
  • a missing, mistyped or malformed answer turns allow into hold;
  • a provider error (timeout, HTTP failure, invalid response) returns hold with the error, and that result is not cached.

enforce / wrapTool / the adapters throw GuardBlockedError on block, and on hold unless an onHold handler approves.

npm install @cmaintz/jev-guard
import { guard, noul, score, TypeSafeProvider, type GuardPolicy } from '@cmaintz/jev-guard';

const provider = new TypeSafeProvider(process.env.JEV_API_KEY!);

const policy: GuardPolicy = {
  dimensions: {
    risk: score(
      ['none', 'local-reversible', 'local-destructive', 'external-or-irreversible'],
      'Blast radius if this runs unintended',
    ),
    destructive: noul('Does this permanently delete or overwrite data?'),
    exfiltrates: noul('Does this send secrets to an external destination?'),
  },
  decide: (r) => {
    if (Number(r.risk?.value) >= 2 && Number(r.destructive?.value) >= 0.8) return 'block';
    if (Number(r.exfiltrates?.value) >= 0.7) return 'hold';
    return 'allow';
  },
  escalateBelow: 0.8, // score/choice answers below this confidence → hold
  perTool: { read_file: 'allow' }, // decided without a Jev call
};

const result = await guard(
  { tool: 'bash', arguments: { cmd: 'rm -rf /var/lib/postgresql/data' }, task: 'Clear the build cache' },
  policy,
  provider,
  { audit: (entry) => console.log(entry) },
);
// result.verdict: 'allow' | 'block' | 'hold'; result.reasons explains any fail-safe

Why Jev

A regex denylist can't tell "delete the temp cache" from "delete prod". A second LLM reviewing every call adds latency and cost and returns prose you have to parse. Jev returns a typed value to branch on and a confidence to gate on, at a price (TypeSafe quotes $0.042 per million input tokens, output free) that makes checking every call affordable.

Framework adapters

Both adapters use structural types, so they carry no dependency on the framework. Bring your own version.

LangChain JS, via the agent's wrapToolCall middleware hook:

import { createMiddleware } from 'langchain';
import { jevGuardMiddleware } from '@cmaintz/jev-guard/langchain';

const guardMw = createMiddleware(jevGuardMiddleware(policy, provider, { onHold: askHuman }));
// createAgent({ ..., middleware: [guardMw] })

Vercel AI SDK, wrapping a tool's execute and keeping description / inputSchema:

import { guardVercelTool } from '@cmaintz/jev-guard/vercel';

const safeBash = guardVercelTool('bash', bashTool, policy, provider);
// streamText({ ..., tools: { bash: safeBash } })

Anything else:

import { wrapTool } from '@cmaintz/jev-guard';
const safeExecute = wrapTool('bash', bash.execute, policy, provider);

Presets

shellPolicy() · filesystemPolicy() · sqlPolicy() · paymentsPolicy(). Each blocks clearly dangerous calls, holds borderline ones and allows the rest. A missing or non-numeric readout counts as maximum risk. Spread a preset to tweak it:

import { shellPolicy, wrapTool } from '@cmaintz/jev-guard';

const strictShell = { ...shellPolicy(), escalateBelow: 0.9, perTool: { echo: 'allow' as const } };

escalateBelow gates score/choice answers only (Jev returns no confidence for a noul). So only shellPolicy, which has a score dimension, sets it. The noul-only presets gate through their probability thresholds.

Caching

createCache({ ttlMs, max }) memoizes verdicts for identical calls (same tool, task and arguments, whatever the key order). Pass it as { cache }. Provider failures are never cached.

Limitations

  • Not a security boundary. Jev is probabilistic (67.8% agreement with frontier-model reference labels on TypeSafe's own evals), and a determined prompt injection can get through. Keep sandboxing, least-privilege credentials and allowlists; this is a cheap semantic layer on top of them.
  • Latency on the hot path. Each guarded call waits for one round trip (TypeSafe quotes 70–500 ms). Use perTool for cheap, safe tools.
  • No rationale. Jev returns numbers, not reasons. Log every verdict through audit, and show a hold's inputs to the human deciding it.
  • No counting. Keep quantitative limits ("deletes more than N rows") in code.

Live smoke test

From the repo root (needs JEV_API_KEY; see .env.example):

npm run build
node --env-file=packages/guard/.env packages/guard/examples/smoke.mjs

MIT © Christoffer Maintz