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

@witness-agent/sdk

v0.1.0

Published

Human authorization for AI agent actions: a passkey signs one exact action, and the counterparty verifies it on-chain. Monad.

Readme

@witness-agent/sdk

An agent can prove who it is. Witness proves what the human actually authorized.

Your agent asks to spend money. The human approves that exact action with a passkey. Your contract verifies the approval on-chain before it moves anything, without trusting the agent, and without asking the human to hold a wallet.

npm i @witness-agent/sdk viem

Building from a checkout is also supported, and produces the same package:

cd packages/sdk && npm pack        # writes witness-agent-sdk-0.1.0.tgz (15.6 kB, 9 files)
npm i ./witness-agent-sdk-0.1.0.tgz viem # in your app

Used by the reference app at witness-agent.vercel.app, which imports this package's source directly, so the product and the integration surface cannot drift apart.

What it does

| The agent | The human | Your contract | |---|---|---| | asks for 0.5 MON to 0x… | taps a passkey | calls authorizeAndConsume | | cannot sign | signs one digest | verifies it with Monad's P-256 precompile | | cannot retry | one use only | moves the money, or reverts with a typed reason |

The digest binds the chain id, your contract, the permission, the recipient and the amount. Change any one of them and the signature no longer applies, so an approval cannot be replayed against a different contract, a different chain, or a different number.

Quickstart

import { WitnessClient, NATIVE_ACTION_TYPE } from "@witness-agent/sdk";

const client = new WitnessClient(
  {
    chainId: 10143,
    contracts: {
      DemoSafe: "0x…",              // the contract that holds the funds
      WitnessIntentRegistry: "0x…",
      WitnessVerifier: "0x…",
      AgentExecutor: "0x…",         // the agent wallet that will act
    },
    rpId: "your.app",               // must match the origin the human visits
    agentId: 2148n,                 // optional ERC-8004 identity to bind
  },
  { kind: "relayer" }               // or { kind: "wallet", writer }
);

// 1. The human registers one permission. Their passkey is enrolled here; its
//    public key IS the authority the permission names.
const { intentId } = await client.createIntent({
  actionType: NATIVE_ACTION_TYPE,
  maxAmount: 5n * 10n ** 17n,       // 0.5 MON
  expirySeconds: 600,
});

// 2. The agent asks, and the human answers with a biometric prompt.
const action = { intentId, kind: "native", to: "0x…", amount: 5n * 10n ** 17n };
const assertion = await client.requestApproval(action);

// 3. Perform it. Your counterparty checks the signature and the cap on-chain; a
//    refusal comes back as the contract's own Reason, not a generic failure.
const result = await client.executeAuthorizedAction(action, assertion);
if (!result.allowed) {
  console.log(result.name, result.message);   // e.g. OverLimit
}

Verifying instead of spending

If you are the counterparty, the API being paid, the vault, the marketplace, you do not need this client's write path at all. You need one call:

bytes32 digest = safe.actionHash(intentId, recipient, amount);
intentRegistry.checkAndConsume(intentId, actionType, digest, amount, msg.sender, assertion);
// reverts with Unauthorized(OverLimit | Expired | AlreadyConsumed | ...) otherwise

Preflight it from your UI with the read-only client.checkAuthorization(action), which reports the same typed reasons without spending anything.

Transports

  • { kind: "relayer", baseUrl? }, a server route registers permissions and submits agent actions, so a user needs no wallet and no testnet funds. The relayer pays gas and can never approve anything: approving needs the passkey, which never leaves the human's device. This is what the reference app uses.
  • { kind: "wallet", writer }, you hold a wallet client (browser wallet, KMS). Anything with account and writeContract satisfies the ContractWriter type; the SDK does not force a wallet stack.

Guarantees, precisely

  • The digest is never computed off-chain. It is read from your contract (actionHash / nativeActionHash), so the bytes the passkey signs and the bytes the contract recomputes cannot drift.
  • One action, one use. An approval is consumed by the call that uses it. AlreadyConsumed is what a replay attempt sees.
  • Semantics are checked, not just the signature. rpIdHash, the user-presence and user-verification flags, the webauthn.get type, challenge-versus-digest, and the origin are all validated on-chain before the P-256 precompile runs.
  • Refusals are typed. Sixteen Reason values, so a UI can say "that is above what you approved" instead of "transaction failed".

Limits, stated plainly

  • Not audited. The contracts and this client are a working reference, not a reviewed production system. Read them before you rely on them.
  • Passkeys still need a real ceremony. The browser APIs the client calls only work at your registered origin; a mismatched rpId fails every prompt. That is the system working, but it is the most common way a first integration breaks.
  • Witness constrains only what consults it. A contract that never calls the verifier is not protected by it. The check has to live in the counterparty that holds the value, that is the design, not an oversight.
  • agentId is enforced only when your deployment configures a registry. When it does not, the binding is skipped, and this SDK reports the same typed reasons the chain does rather than claiming an enforcement that is not happening.

Building from source

src/ is generated from the reference app's modules so there is one copy of the truth:

npm install
npm run build      # sync src/, bundle ESM + CJS, emit declarations
npm run check      # fail if src/ lags the app

MIT.