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

@prmaat/langchain

v0.1.0

Published

PrMaat LangChain integration. A BaseCallbackHandler that signs every LangGraph event with the agent's W3C DID before it hits LangSmith — so traces become cryptographically attributable, not just framework-self-attested. Implements PrMaat Verification Spec

Readme

@prmaat/langchain

LangChain.js callback handler that signs every LangGraph event with the agent's W3C DID, so traces become cryptographically attributable instead of framework-self-attested. Conforms to PrMaat Verification Spec v0.1.

What this gets you

A standard LangChain BaseCallbackHandler you attach to any chain, graph, or model. As your agent runs:

  1. Every LLM start/end, tool call, and chain transition produces a PrMaat-signed event (spec §4 + §5).
  2. Events are bound to LangGraph checkpoint IDs, not callback wall-clock — so signatures don't desync under async streaming or parallel branches (spec §4.3).
  3. Signed events flow to whatever sink you want — PrMaat's hosted audit chain, your own S3 bucket, or LangSmith with PrMaat signatures attached.

The result: you can prove which agent (specific W3C DID + custody level) said what during a run, verifiable by any third party with the prmaat verify CLI. No more "trust LangSmith's database."

Install

npm install @prmaat/langchain
# Peer dep:
npm install @langchain/core

Quick start

import { ChatOpenAI } from "@langchain/openai";
import { PrMaatCallbackHandler, makeBridgeHandle } from "@prmaat/langchain";

// 1. Get a key handle. Bridge custody = signing key lives in a
//    separate process (the PrMaat bridge); this process never holds
//    raw key bytes — required for prmaat-v0.1.audit conformance.
const keyHandle = makeBridgeHandle({
  bridgeUrl: "http://127.0.0.1:7070",
  agentId:   "my-agent",
});

// 2. Create the handler.
const handler = await PrMaatCallbackHandler({
  issuerDid:          "did:prmaat:abc123",
  verificationMethod: "did:prmaat:abc123#key-1",
  keyHandle,
  onSignedEvent: async (event) => {
    // Ship the signed event wherever you want it audit-anchored.
    await fetch("https://prmaat.com/api/agent/events", {
      method: "POST",
      headers: { "Content-Type": "application/json", "Authorization": "Bearer " + APT },
      body: JSON.stringify(event),
    });
  },
});

// 3. Attach to any LangChain runnable.
const model = new ChatOpenAI({ callbacks: [handler] });
await model.invoke("Hello");

// Now every LLM start/end is signed and audit-anchored.

For LangGraph specifically, attach when compiling the StateGraph:

import { StateGraph } from "@langchain/langgraph";

const graph = new StateGraph(/* ... */).compile({
  callbacks: [handler],
});

Custody options (in order of preference)

import {
  makeBridgeHandle,    // ✅ bridge-isolated   — prod, key in separate process
  makeKeychainHandle,  // ✅ os-keychain       — dev, key in macOS Keychain
  makeInlineHandle,    // ⚠️  runtime          — TESTS ONLY, fails verification
  generateTestKeypair, // ⚠️  runtime          — TESTS ONLY
} from "@prmaat/langchain";

The runtime custody level explicitly FAILS PrMaat verification per spec §2.3. If your key lives in the same process that produces messages, your "signed traces" are security theatre — the prmaat verify CLI will reject them with CUSTODY_INSUFFICIENT. This is the bright line that separates real cryptographic accountability from marketing claims.

For development, use makeInlineHandle to iterate, but expect the verifier to fail your bundles. Switch to makeBridgeHandle (or makeKeychainHandle on macOS) before you ship to production.

What gets signed

Every callback produces an event of the appropriate type per spec §4.2:

| LangChain callback | PrMaat event type | Notes | |--------------------|-------------------|-------| | handleLLMStart | agent.tool.invoked | ctx.toolId = llm:<name> | | handleLLMEnd | agent.message.sent | ctx.contentHash + ctx.model | | handleLLMError | agent.tool.completed | with error hash | | handleToolStart | agent.tool.invoked | ctx.toolId = tool:<name> | | handleToolEnd | agent.tool.completed | with result hash |

Each event's ctx.parentEventId is the LangChain runId (UUID issued at the start of the chain/llm/tool invocation) — NOT a wall-clock timestamp. This is the §4.3 mitigation against signature/trace desync under async streaming.

The hash chain (event.prev) connects events from the same handler instance, so a single agent's trace is a verifiable linked list even if events arrive out of order at the audit sink.

Interop guarantee

Every event signed by this handler is independently verifiable by the prmaat verify CLI. The test suite includes test/interop-with-verify.test.mjs which round- trips signed events through the verifier and asserts:

  • ✅ Valid events pass prmaat-v0.1.basic conformance
  • ✅ Tampered events fail with SIGNATURE_INVALID
  • ✅ Honestly-declared runtime custody fails with CUSTODY_INSUFFICIENT

If you ship this handler in production and someone audits your trace, they can run prmaat verify <bundle> against any signed event and get a deterministic OK / FAIL result.

Limitations (v0.1.0)

  • JS only. Python LangChain integration (@prmaat/langchain-py) lands in v0.2.
  • Bridge handle is a v0.1 sketch — relies on the PrMaat bridge exposing a localhost signing socket, planned for bridge v0.4.0. Until then, dev users will mostly use makeInlineHandle (and accept that they fail verification) or wait for the keychain handle.
  • Async hash placeholder. _hashContent() returns a length-only digest in v0.1; v0.2 swaps in a real crypto.subtle.digest call with proper hex output. The structural shape of events is correct — only the content-hash field is a placeholder.
  • No retry / batching. onSignedEvent is awaited inline; if your audit sink is slow it will block the LangChain run. v0.2 adds an async batch queue with at-least-once delivery semantics.

Running tests

cd langchain
node test/handler.test.mjs            # 13 unit tests, no LangChain dep
node test/interop-with-verify.test.mjs # 4 cross-package tests

The unit tests don't require @langchain/core (we test canonicalization, signing, and the sign/verify round-trip in isolation). The full BaseCallbackHandler invocation test ships later in v0.1.1 once we add a LangChain.js fixture.

License

MIT. See LICENSE.

See also

  • PrMaat Verification Spec v0.1 — the spec this handler implements.
  • Health Check — paste your passport DID, instantly see which spec dimensions your LangGraph setup already satisfies. Useful right after wiring this handler into a chain to confirm signatures are landing as expected.
  • Sub-processor registry — PrMaat's own GDPR Art. 28 disclosure + RSS feed for change notifications.
  • @prmaat/verify — reference verifier, MIT, zero deps.
  • PrMaat Bridge — local relay with OS-keychain custody.

Built 2026-05-02 (Genesis Day +1, Cairo) after a 4-1 vote in the PrMaat brainstorm room. Ships ahead of the Day 7 schedule commitment from the launch-night strategy doc.