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

@usekaval/kaval

v0.3.1

Published

Action-bound verification for AI agents — signed proof packets plus ALLOW/BLOCK/REVIEW gates.

Readme

@usekaval/kaval

The freshness gate for AI. Give kaval a belief your system already holds — a cached fact, a CRM field, an agent memory — and it checks the live world and returns a typed verdict: current, stale, contradicted, unsupported, conflicting, or insufficient.

npm install @usekaval/kaval

Node and module format

This package is ESM-first ("type": "module"). Use import in ESM projects, or dynamic import in CommonJS:

const { Kaval } = await import("@usekaval/kaval");

CJS require("@usekaval/kaval") needs Node ≥20.19 or ≥22.12 (Node’s native require(esm) support). On Node 18, use import / await import() instead — engines.node is >=18 for ESM + fetch, not for CJS require.

Build a proof, then gate the action

import { Kaval } from "@usekaval/kaval";

const kaval = new Kaval({ apiKey: process.env.KAVAL_API_KEY });
const proof = await kaval.audit({
  text: "Acme is eligible for a $12,000 refund",
  as_of: new Date().toISOString(),
  intended_action: "Issue Acme a $12,000 refund",
  materiality: "critical",
  reversibility: "irreversible",
  false_allow_cost_usd: 12_000,
  record: { system: "billing", table: "refunds", id: "acme-2026" },
});
const gate = await kaval.gateAction({
  proof_id: proof.proof_id,
  material_claim_ids: proof.action_decision.material_claim_ids,
  threshold: proof.action_decision.threshold,
  action: proof.research_contract.action,
});
if (gate.enforcement?.controlApplied === true) {
  if (gate.enforcement.executionAllowed !== true) {
    throw new Error("Kaval blocked the action");
  }
} else if (
  gate.enforcement === undefined &&
  (gate.state !== "current" || gate.decision.decision !== "ALLOW")
) {
  // A direct integration without staged enforcement fails closed.
  throw new Error("Kaval did not allow the action");
}
// controlApplied === false is shadow mode: record wouldAllow, but keep the customer's existing
// action policy authoritative.

audit() returns the complete typed ProofPacket: atomic claims, policy bindings, immutable source versions, exact evidence spans, lineage families, claim assessments, calibrated/withheld risk, provenance, expiry, and signature. gateAction() is the cheap action-time check and includes staged enforcement (shadow, block_only, or bounded) when configured by the deployment. Only enforcement.controlApplied === true may control execution. Shadow mode returns controlApplied: false, executionAllowed: null, and a counterfactual wouldAllow for calibration.

Both methods accept { idempotencyKey?, signal?, timeoutMs? }. The constructor defaults to a 30-second deadline; override per call or set timeoutMs: null to disable it. Cancellation and timeout errors retain error.idempotencyKey, because an interrupted billable request can be ambiguous.

Gate a belief before you act on it

import { Kaval } from "@usekaval/kaval";

const kaval = new Kaval({ apiKey: process.env.KAVAL_API_KEY });

const decision = await kaval.verify("Acme's CEO is Jane Doe");
if (!decision.act) {
  // stale / contradicted — re-fetch before relying on it
}

verify() returns the verdict plus acttrue only when the belief is current and confident (≥ 0.7 by default; override with minConfidence).

Safe retries and idempotency

Every billable call automatically sends a fresh UUID Idempotency-Key. If the connection fails without a trustworthy response, or the API says the operation is still being finalized, the client retries once with the same key. It does not retry ordinary API errors, rate limits, or terminal 5xx responses.

Pass your own key when an outer job/retry system needs to keep one logical operation stable:

const operationId = crypto.randomUUID();
const decision = await kaval.verify(
  { belief: "Acme's CEO is Jane Doe" },
  { idempotencyKey: operationId },
);

Reuse a key only after an ambiguous/no-response failure. After receiving a terminal response, start a new key for any new attempt. reportOutcome() and health() are not billable and do not send this header. If both bounded attempts remain ambiguous, the thrown KavalError or transport error exposes the generated key as error.idempotencyKey; pass it back explicitly after your own delay to resume the same operation instead of starting and billing a new one.

Pick a speed/depth tier

const decision = await kaval.verify({
  belief: "Acme's CEO is Jane Doe",
  mode: "deep",
});

decision.tier; // "deep" — the tier that ran (echoes your `mode`)
decision.explanation?.content; // deep only: a cited, markdown rationale with [n] citations
decision.explanation?.citations; // [{ url, title? }] — drawn only from the gathered evidence
decision.explanation?.confidence; // "high" | "medium" | "low"

mode selects the tier (default auto):

  • instant — cache / graph-prior only, no fetch or LLM; fastest, answers from what's already known.
  • fast — a cheap model, origin-only.
  • auto — balanced (the default).
  • deep — the strongest model + a synthesized, inline-cited explanation for audit/human review.

Sweep a store for drift

const report = await kaval.scanStore({
  beliefs: ["Acme is on the Enterprise plan", "Jane Doe is VP Eng at Acme"],
});
report.riskiest.forEach((r) => console.log(r.belief, "→", r.status));

// …or get pushed the newly-stale ones:
await kaval.monitor({ beliefs, webhook: "https://your-app.com/hooks/stale" });

API

audit · gateAction (gate alias) · verify · check · extractAndCheck · scanStore · monitor · reportOutcome · kaval · kavalBatch · health. Billable methods accept a final { idempotencyKey?, signal?, timeoutMs? } request-options argument (kavalBatch includes it alongside concurrency). Construct with { apiKey, baseUrl?, fetch?, timeoutMs? }baseUrl defaults to https://api.usekaval.com. Works in Node 18+, browsers, and edge runtimes (uses the global fetch).

Env vars: this package does not read KAVAL_BASE_URL from the environment — pass baseUrl in the constructor (Python SDK and MCP use KAVAL_BASE_URL; the marketing-site proxy uses KAVAL_API_URL). See the clients README.

The Python client mirrors this surface: pip install kaval.