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

wickd

v0.4.0

Published

Guardrails for AI agents — budget limits, kill switches, and human approval gates.

Readme

wickd

Budget limits, kill switches, and approval gates for AI agents.

Install

npm install wickd

Quick start

import { agent, Budget, notify } from "wickd";
import OpenAI from "openai";

const myAgent = agent({
  fn: async (task: string) => {
    const client = new OpenAI();
    const response = await client.chat.completions.create({
      model: "gpt-4o",
      messages: [{ role: "user", content: task }],
    });
    return response.choices[0].message.content;
  },
  budget: new Budget({ perRun: 2.0, daily: 20.0 }),
  onBudgetKill: notify.console(),
});

const result = await myAgent.run("Summarise yesterday's support tickets");

One wrapper. Your agent now has a hard cost cap, a full trace of every LLM call, and a summary printed after every run:

[wickd] ✓ my_agent — $0.0043 cost | 1 calls | budget: $0.0043/$2.00 | 1203ms | trace: a1b2c3d4

Budget enforcement

Hard cost ceilings, checked in real time inside every LLM call.

const myAgent = agent({
  fn: processInvoices,
  budget: new Budget({
    perRun: 2.0,     // kill if this run exceeds $2
    daily: 20.0,     // kill if total today exceeds $20
    monthly: 500.0,  // kill if total this month exceeds $500
  }),
  onBudgetKill: notify.slack("https://hooks.slack.com/..."),
});

When a cap is hit, Wickd throws BudgetExceeded, saves the full trace, and fires your notification handler.

import { BudgetExceeded } from "wickd";

try {
  await myAgent.run("Process all invoices");
} catch (e) {
  if (e instanceof BudgetExceeded) {
    console.log(`Killed at $${e.spent.toFixed(2)}`);
  }
}

Approval gates

Pause execution at sensitive checkpoints and wait for a human.

import { agent, Budget, approvalGate } from "wickd";

const updateUser = approvalGate("database_write", (userId: string, data: Record<string, unknown>) => {
  db.update(userId, data);
});

const sendEmail = approvalGate("send_email", (to: string, subject: string, body: string) => {
  email.send(to, subject, body);
});

const supportAgent = agent({
  fn: async (task: string) => {
    // pauses here and asks for approval
    await updateUser("user_123", { email: "[email protected]" });
    await sendEmail("[email protected]", "Update", "Your email was changed");
  },
  budget: new Budget({ perRun: 5.0 }),
});

For headless environments, use the webhook handler:

import { approvalGate, webhookApprovalHandler } from "wickd";

const handler = webhookApprovalHandler("https://your-api.com/approvals", {
  timeout: 300_000,
  pollInterval: 2000,
});

const riskyAction = approvalGate("deploy", deployToProduction, handler);

Notifications

import { notify } from "wickd";

// stderr (local dev)
onBudgetKill: notify.console()

// Slack incoming webhook
onBudgetKill: notify.slack("https://hooks.slack.com/...")

// Generic webhook (JSON POST)
onBudgetKill: notify.webhook("https://your-api.com/alerts")

// Authenticated webhook
onBudgetKill: notify.webhook("https://your-api.com/alerts", {
  Authorization: "Bearer sk-...",
})

Multiple handlers:

const myAgent = agent({
  fn: myAgentFn,
  budget: new Budget({ perRun: 2.0 }),
  notify: [notify.console(), notify.slack("https://hooks.slack.com/...")],
  onBudgetKill: notify.webhook("https://pagerduty.com/..."),
  onRunComplete: notify.slack("https://hooks.slack.com/..."),
});

Framework compatibility

Wickd patches LLM SDKs at the transport layer, so it works with anything built on top of them -- Vercel AI SDK, LangChain.js, LangGraph, OpenAI Agents SDK. No framework-specific code needed.

import { agent, Budget } from "wickd";
import { generateText } from "ai";

const myAgent = agent({
  fn: async (task: string) => {
    const { text } = await generateText({
      model: openai("gpt-4o"),
      prompt: task,
    });
    return text;
  },
  budget: new Budget({ perRun: 1.0 }),
});

How it works

  1. agent() wraps your function and patches the OpenAI, Anthropic, and Google GenAI SDKs
  2. Every LLM call is intercepted -- tokens and cost are tracked in real time
  3. If cost exceeds the budget, execution is killed immediately (BudgetExceeded)
  4. approvalGate() functions pause for human approval before running
  5. A full trace is saved to ~/.wickd/traces/ after every run

Everything runs locally. No data leaves your machine.

API

agent(options)

| Option | Type | Description | |--------|------|-------------| | fn | (...args) => any | The agent function to wrap | | budget | Budget | Budget limits (perRun, daily, monthly) | | name | string | Agent name for traces (defaults to function name) | | onBudgetKill | NotifyHandler | Called when budget is exceeded | | onRunComplete | NotifyHandler | Called after every run | | notify | NotifyHandler[] | Handlers for all notification events | | autoPatch | boolean | Auto-patch LLM SDKs (default: true) |

Budget

new Budget({ perRun: 2.0, daily: 20.0, monthly: 500.0 })

approvalGate(name, fn, handler?)

Wraps a function with a human approval checkpoint. Returns an async version of the function.

Manual patching

import { patchOpenAI, patchAnthropic, patchGoogle, patchAll } from "wickd";

patchOpenAI();
patchAnthropic();
patchGoogle();
patchAll();       // all of the above

License

MIT