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

@kiff/kiff-guard

v1.6.0

Published

Drop-in guard that puts KIFF clearance in front of any agent's tool calls — observe to audit, enforce to govern. TypeScript SDK.

Readme

@kiff/kiff-guard (TypeScript)

Drop-in KIFF clearance for any agent's tool calls — observe to audit, enforce to govern. The TypeScript SDK, a faithful port of the Python kiff-guard core.

It speaks the same versioned decide contract (POST /v1/proposals/decide, RFC 017, additive-only /v1) and upholds the same invariants the Python SDK does, pinned by the conformance suite:

  • observe is decide-independent — works with no client and no tenant;
  • one governed receipt per tool call;
  • unknown outcomes fail safe — anything that isn't an explicit allowed withholds, so the cloud can add outcomes without old SDKs failing open;
  • roles are never sent — the API key's roles govern server-side.

Zero required runtime dependencies (uses the global fetch, Node >= 18).

Quickstart (zero-config audit, no KIFF account)

import { Guard, exportYaml } from "@kiff/kiff-guard";
import { registerKiffGuard } from "@kiff/kiff-guard/adapters/openclaw";

const guard = new Guard({ mode: "observe" });
// attach via the OpenClaw plugin (below); run the agent; then:
for (const r of guard.receipts) console.log(r.state, r.tool, r.outcome);
console.log(exportYaml("my-domain", guard.catalog));

Enforce (with a tenant + active domain)

import { Guard, HTTPClient, ToolMap } from "@kiff/kiff-guard";

const client = new HTTPClient({
  apiKey: "kiff_live_...",                       // mint in the dashboard
  toolMap: new ToolMap().bind("refund_order", "REFUND_ORDER", "Order", "order_id"),
});
const guard = new Guard({ client, tenant: "<tenant>", agent: "support", mode: "enforce" });

Custom agent? No adapter required

The adapter below is convenience glue for OpenClaw. It adds no governance logic — the guard logic lives in the core. If you run a custom agent (your own loop, a Deno/Node service, a framework with no adapter yet), use the core directly. HTTPClient already speaks the hosted decide route (POST /v1/proposals/decide against api.kiff.dev); there is nothing extra to install or run.

Observe — zero config, no KIFF account. Call observe wherever your loop is about to run a tool:

import { Guard } from "@kiff/kiff-guard";

const guard = new Guard({ mode: "observe" });   // no client, no tenant

function runTool(name: string, args: Record<string, unknown>) {
  guard.observe(name, args);                    // learn + record, never blocks
  return tools[name](args);                     // your agent runs the tool
}
// ... after the run: guard.receipts each have state === "observed".

Enforce — decide before you run. Gate on decision.withheld (true for anything that isn't an explicit allowed, so an unknown future outcome fails safe), then record exactly one receipt:

import { Guard, HTTPClient, ToolMap } from "@kiff/kiff-guard";

const client = new HTTPClient({
  apiKey: "kiff_live_...",
  domain: "card-refund", // active domain for this guard
  toolMap: new ToolMap().bind("refund_order", "REFUND_ORDER", "Order", "order_id"),
});
const guard = new Guard({ client, tenant: "<tenant>", agent: "support", mode: "enforce" });

async function runTool(name: string, args: Record<string, unknown>) {
  const decision = await guard.decideOnly(name, args);   // calls KIFF, does not run
  if (decision.withheld) {                                // != "allowed" → withhold
    guard.recordWithheld(name, args, decision);
    return `withheld: ${decision.outcome} — ${decision.reason}`;
  }
  const result = tools[name](args);                       // your agent runs the tool
  guard.recordExecuted(name, args, decision);             // one receipt per call
  return result;
}

This is the same core the OpenClaw adapter calls; an adapter just translates one framework's pre-tool seam into these calls. You send actorId (the agent); you never send roles — the API key's roles govern authority server-side, so your only integration responsibility is authenticating the caller's identity, not granting it.

For stacks neither SDK covers (Ruby, Go, shell), a proposal is a single HTTP POST — see cookbook/custom-agent-http.

Connect to KIFF Cloud

Call connect when you want the hosted dashboard to show a live guard runtime. Run it at startup and periodically as a heartbeat. It is explicit so local observe mode stays zero-config and never phones home unless you provide a Cloud client.

await guard.connect({
  adapter: "openclaw",
  project: "finance",
  environment: "prod",
  workflow: "duplicate-payment",
  sdkVersion: "0.1.0",
});

Cloud stores the tenant from the API key plus the project, environment, agent, workflow, adapter, SDK version, mode, first/last seen time, and heartbeat count. When the API key is bound to an agent, omit agent in the Guard constructor: connect() leaves agent_id out of the request and uses the agent name returned by Cloud for later decisions. With an unbound key, set agent explicitly; Cloud still requires it.

Adapters

| Framework | Lang | Shape | Status | |---|---|---|---| | OpenClaw | ts | vote (before_tool_call) | shipped |

OpenClaw is the first adapter where KIFF's approval_required renders as native human-in-the-loop (requireApproval → the /approve flow), not a collapse to a block. More JS-ecosystem adapters (LangGraph.js, Vercel AI SDK, Mastra) follow.

OpenClaw plugin

import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { Guard } from "@kiff/kiff-guard";
import { registerKiffGuard } from "@kiff/kiff-guard/adapters/openclaw";

const guard = new Guard({ mode: "observe" }); // or enforce with a client

export default definePluginEntry({
  id: "kiff-guard",
  name: "KIFF Guard",
  register(api) {
    registerKiffGuard(api, guard);
  },
});

observe records + learns every tool call and never blocks. enforce calls KIFF before each tool: allowed proceeds, approval_required routes a real human via requireApproval, everything else (and any unknown outcome) blocks. Fail-closed by default if the decide path is down.

Develop

npm install
npm run typecheck   # tsc strict, no emit
npm run build       # -> dist/
npm test            # vitest: guard core + conformance + adapter

The conformance suite (src/conformance.test.ts) is the durability contract: a new adapter provides a drive shim and the shared invariants (O1–O5 observe, E1–E4 enforce, incl. fail-safe-on-unknown) do the rest. Same posture as the Python SDK's conformance.py.