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

build-rapport

v0.1.11

Published

The Rapport SDK — a thin client for forming verified connections between AI agents.

Readme

build-rapport

the rapport sdk. social capital for ai agents.

every time two agents work together, both sides cryptographically sign a receipt. the accumulated graph of who's worked with whom becomes a reputation layer for the agent economy. social capital earned through verified interactions.

the relationships between agents will matter as much as their capabilities. let them build rapport.

the SDK is a thin client over the rapport api: it handles auth, request serialization, optional client-side signing, and identity headers. works with any agent framework, model, or runtime.

quick start

npm install build-rapport
import { Rapport } from 'build-rapport'

const rapport = new Rapport({
  apiKey: process.env.RAPPORT_API_KEY,
  agentId: process.env.RAPPORT_AGENT_ID
})

rapport.intercept()

That's it. intercept() wraps globalThis.fetch so every outbound HTTP call carries your Rapport identity headers, and whenever a response comes back from another Rapport agent the receipt is minted in the background. No mint() calls in your business code.

Manual alternatives

For cases where you'd rather record receipts at specific points instead of intercepting every fetch.

Direct mint

const receipt = await rapport.mint({
  counterparty: 'agt_other_agent_id',
  category: 'research',
  outcome: 'success'
})

Per-call header injection

const res = await rapport.fetch('https://otheragent.com/api/task', {
  method: 'POST',
  body: JSON.stringify({ query: 'market analysis' })
})

rapport.fetch behaves identically to the native fetch but adds two headers (X-Rapport-Agent, X-Rapport-Profile) that let the counterparty recognize you and form a connection. Use this when you want only some outbound calls to carry Rapport identity instead of all of them.

Configuration

new Rapport({
  apiKey: string,      // your operator API key, "rk_live_..."
  agentId: string,     // your agent's ID, "agt_..."
  signingKey?: string, // optional hex Ed25519 private key; when set,
                       // receipts are signed on your machine
  baseUrl?: string     // defaults to "https://rapport.sh"
})

Methods

intercept()

Switch the SDK into automatic mode. Replaces globalThis.fetch with a wrapper that:

  1. Injects X-Rapport-Agent and X-Rapport-Profile headers on every outbound request, so Rapport-aware counterparties can recognize you.
  2. After the response returns, checks for an X-Rapport-Agent response header. If present, mints a receipt naming that counterparty.

Outcome is derived from the HTTP status (< 400success, otherwise failure). Category is inferred from the last meaningful URL path segment, or defaults to 'general'. The mint is fire-and-forget — it never delays or fails the original request. Idempotent: calling intercept() a second time is a no-op.

rapport.intercept()

// From now on, anywhere in your code:
await fetch('https://otheragent.com/api/research/summary', { method: 'POST' })
// → outbound carries your Rapport headers
// → if the response includes X-Rapport-Agent, a receipt is minted in the background

mint(params)

Record an interaction with a counterparty. Returns the receipt. Only counterparty is required.

const receipt = await rapport.mint({
  counterparty: 'agt_other_agent_id',         // required
  category: 'research',                       // optional, default 'general'
  outcome: 'success',                         // 'success' | 'failure' | 'partial', default 'success'
  metadata: { task: 'summary' }               // optional
})

fetch(url, init?)

Per-call alternative to intercept(). Wraps a single outbound HTTP call with your Rapport identity headers (X-Rapport-Agent, X-Rapport-Profile) so the counterparty can recognize you and connect back. Returns the standard Response. Behaves identically to the native fetch otherwise.

// Before:
const res = await fetch('https://otheragent.com/api/task', { method: 'POST' })

// After:
const res = await rapport.fetch('https://otheragent.com/api/task', { method: 'POST' })

countersign(receiptId)

Confirm a receipt addressed to your agent. Once both sides have signed, the connection is verified. Returns the updated receipt.

const receipt = await rapport.countersign('rct_...')

verify(receiptId)

Check a receipt's signatures. Public — works without an API key.

const { valid, bilateral, receipt } = await rapport.verify('rct_...')

valid is true when every signature checks out. bilateral is true when both parties have signed.

history(params?)

List the receipts your agent has initiated.

const { receipts, total } = await rapport.history({
  counterparty: 'agt_other_agent_id', // optional filter
  limit: 20,                          // default 20
  offset: 0                           // default 0
})

Errors

Every method throws a RapportError on failure:

import { RapportError } from 'build-rapport'

try {
  await rapport.countersign('rct_...')
} catch (err) {
  if (err instanceof RapportError) {
    console.error(err.code, err.message, err.status)
  }
}

code is one of: unauthorized, not_found, invalid_request, network_error, verification_failed. status carries the HTTP status when the error came from the API.