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

@agenticprimitives/agent-resolution

v0.0.0-alpha.2

Published

Provider-neutral agent resolution primitives: agent discovery policy, signed sequenced AgentServicePublication with anti-rollback verification, private resolution grants, connection invitations, audience projection, and resolution provider ports. Resoluti

Downloads

256

Readme

@agenticprimitives/agent-resolution

Every agent has a canonical identity. Naming is optional. Public listing is optional. Inbound addressability is optional. Authorized private resolution is a first-class capability.

Provider-neutral primitives for answering "may this party discover how to reach this agent, and where is it right now?" — with a hard wall between that question and "may this party use it?"

Spec: [specs/338](https://github.com/agentictrustlabs/agenticprimitives/blob/master/specs/338-private-agent-resolution-and-service-publication.md) · Doctrine: ADR-0056


The rule

A resolution grant answers:      "May this party DISCOVER how to reach this agent?"
It NEVER answers:                "May this party USE this agent?"

Successful resolution gives you an endpoint and a verified peer identity. Invocation still requires the whole chain, re-run at the origin:

delegation ∩ entitlement ∩ tool/action policy ∩ exact invocation proof ∩ revocation ∩ audit

Resolution is one of four orthogonal concerns with custody ("who signed"), admission ("may these bytes enter"), and authority ("what may this principal do"). A yes to one is never a yes to another.

Four independent dimensions

"Nameless" = no public label only. Listing, resolution, and inbound are modelled separately.

| Posture | naming | listing | resolution | inbound | | ------------------------------ | --------------- | -------- | --------------- | --------------------- | | Public commercial agent | public | public | public | delegation-required | | Public name, protected details | public | public | authenticated | delegation-required | | Private partner agent | private-label | none | invitation | known-peer | | Pairwise treasury agent | private-label | none | pairwise | delegation-required | | Unnamed internal worker | none | none | invitation | known-peer | | Temporary direct agent | none | none | direct | delegation-required | | Background outbound worker | none | none | none | outbound-only |

import { discoveryPolicyFromPreset, validateDiscoveryPolicy } from '@agenticprimitives/agent-resolution';

const policy = discoveryPolicyFromPreset('private-partner');
validateDiscoveryPolicy(policy); // [] — combinations that cannot be enforced are rejected

Every path resolves to the same canonical identity: eip155:<chainId>:<SmartAgentAddress>.

Worked flow — Agent A reaches a nameless treasury (Agent B)

Scenario: Agent A (caller SA for a person/org) must call Agent B (treasury service SA) over A2A. B has no public ANS name (naming: none, listing: none). Reachability is invitation / private-grant resolution — not a public label.

Where the A2A URL comes from: it is not invented by the private resolver and not looked up by name. It is a field on a signed AgentServicePublicationV1:

publication.surfaces[] → entry with protocol: 'a2a'uri (e.g. https://xyz.example/a2a/v1).

The resolver only admits Alice’s grant and selects a pre-signed publication from B’s owner vault (selectPresignedPublication — select, never edit). Alice extracts the URI after verifyPublication on her side.

Diagrams

1. Conceptual flow — nameless Agent A → treasury Agent B (terms used everywhere below):

Nameless private resolution flow — Agent A to treasury Agent B

Agent A → nameless treasury B. Vault holds signed publication (A2A uri in surfaces[]), subject-bound grant, publication authority. Steps: issue grant → invitation (initialPublication + rendezvous) → first dial or resolver refresh (selectPresignedPublication) → A2A + delegation. Resolver never forges the endpoint.

2. Local architecture — same terms → monorepo Workers:

Local architecture — apps mapped to nameless resolution terms

demo-web-pro / demo-sso-next = Agent A; demo-resolver :8795 = private resolver; demo-publications :8796 = pub store; demo-a2a :8787 = B’s A2A host (URI in publication). Optional demo-edge. Steps match diagram 1. Live treasury may still use a known URL + delegation; private resolve is the parallel Ring-1 path.

| Step | What moves | A2A endpoint? | | --- | --- | --- | | 1 | B issues PrivateResolutionGrantV1 (subject-bound to A) | no — grant = may discover | | 2 | Invitation to A = initialPublication + grant + rendezvous | yes — URI already inside initialPublication.surfaces[] | | 3a | First connect: A verifies that publication locally | URI from verified publication (no resolver hop) | | 3b | Refresh: A → resolver → selectPresignedPublication → A verifies | yes — URI from the selected publication’s surfaces[], not from resolver logic | | 4 | A2A task + delegation ∩ entitlement ∩ policy | use, not resolve |

Nameless = no public label. Publication authority = endpoint/session-key rotation is an ops publish, not a custody ceremony. Delegation = what lets A invoke treasury skills after the URL is known.

sequenceDiagram
  autonumber
  participant B as Agent B treasury SA
  participant Vault as B owner vault
  participant R as Private resolver
  participant A as Agent A
  participant A2A as B A2A host<br/>xyz…/a2a/v1

  B->>Vault: Store signed AgentServicePublicationV1<br/>surfaces: [{protocol:a2a, uri}]
  B->>Vault: Issue PrivateResolutionGrantV1 subject=A
  B-->>A: Invitation = initialPublication + grant + rendezvous

  Note over A: Resolve — endpoint is in the publication
  A->>A: verifyPublication(initialPublication)
  A->>A: a2aUrl = surfaces.find(p=>p.protocol==='a2a').uri

  opt Endpoint moved — same grant
    A->>R: Present grant + PoP
    R->>Vault: Admit + selectPresignedPublication
    R-->>A: Pre-signed publication (includes new uri)
    A->>A: verifyPublication → read surfaces[].uri again
  end

  A->>A2A: Open channel to a2aUrl
  A->>A2A: Task + delegation (other packages)
  alt Authority OK
    A2A-->>A: Result
  else Resolution grant only
    A2A-->>A: Denied — resolution ≠ use
  end

Local apps — term → Worker map

| Conceptual term | Local app | | --- | --- | | Agent A app | demo-web-pro; invite inspect demo-sso-next /visibility | | Agent B A2A host | demo-a2a :8787/api/a2a, A2aTaskDO | | Private resolver | demo-resolver :8795/v1/private/{challenge,resolve} | | B vault (demo stand-in) | demo-publications :8796/v1/publications | | A2A uri | Inside publication surfaces[] → e.g. http://127.0.0.1:8787/api/a2a | | Optional edge | demo-edge/api/a2a/<handle> | | Use (not resolve) | Delegation gates in demo-a2a |

Worked sequence — DNTLS as a Ring-1 resolution provider

DNTLS is not a dependency. A Ring-1 AgentResolutionProvider (method: 'dntls') maps a Service Record → AgentServicePublicationV1; createComposedResolver verifies SA binding (spec 338 §18). Namespace membership may be a policy predicate, never the grant. Bidirectional binding required. DNTLS alone never grants identity, delegation, MCP/A2A permission, entitlement, or custody.

sequenceDiagram
  autonumber
  participant D as DNTLS resolver<br/>(external)
  participant Adapt as dntls provider<br/>(Ring-1)
  participant AP as createComposedResolver
  actor A as Agent A
  participant A2A as B A2A host

  A->>AP: resolve({ kind:'external', method:'dntls', identifier })
  AP->>Adapt: resolve(reference, context)
  Adapt->>D: Resolve name / commitment
  D-->>Adapt: Service Record + proof
  Adapt->>Adapt: Map → AgentServicePublicationV1
  Adapt-->>AP: UnverifiedResolutionBundleV1
  AP->>AP: verifyPublication + SA↔DNTLS binding<br/>+ authorityCheck + continuity
  alt Fail
    AP-->>A: resolution failure
  else OK
    AP-->>A: VerifiedAgentResolutionV1<br/>(reachability only)
  end
  A->>A2A: Open surface URI + AP delegation
  A2A->>A2A: delegation ∩ entitlement ∩ policy
  alt Authority OK
    A2A-->>A: Result + receipt
  else Resolution-only
    A2A-->>A: Denied — resolution ≠ use
  end

Illustrative adapter (ports are real; DNTLS client/wire is external and not shipped):

import {
  createComposedResolver,
  type AgentResolutionProvider,
  type AgentServicePublicationV1,
} from '@agenticprimitives/agent-resolution';

// Ring-1: map DNTLS Service Record → AgentServicePublicationV1
// (agentId, channelId, sequence, surfaces[].uri/protocol, transportKeyBinding,
//  publishedBy, publicationAuthorityRef, digest, proofs[] — then ERC-1271 sign)
declare function mapDntlsRecord(record: unknown): AgentServicePublicationV1;
declare const externalDntlsClient: { resolve(id: string): Promise<{ record: unknown; proof: unknown }> };

const dntlsProvider: AgentResolutionProvider = {
  method: 'dntls',
  supports: (ref) => ref.kind === 'external' && ref.method === 'dntls',
  async resolve(ref, _ctx) {
    if (ref.kind !== 'external') throw new Error('unsupported');
    const { record, proof } = await externalDntlsClient.resolve(ref.identifier);
    return {
      method: 'dntls',
      referenceKind: 'external',
      publication: mapDntlsRecord(record),
      providerEvidence: [proof],
      servedAt: new Date().toISOString(),
    };
  },
};

const resolve = createComposedResolver({
  providers: [dntlsProvider],
  verifier: publicClient,
  // authorityCheck should also require AP facet → DNTLS commitment (bidirectional)
  authorityCheck,
  minAssurance: 'signed-publication',
});

const result = await resolve(
  { kind: 'external', method: 'dntls', identifier: 'treasury.ops.acme.dntls' },
  { requester: 'eip155:84532:0xaaa…', now: new Date().toISOString() },
  'eip155:84532:0xbbb…',
);
// result.ok ⇒ VerifiedAgentResolutionV1 — still no spend / tool permission

Full audit: dntls-comparison.md.

A hash proves unmodified. It does not prove current.

A signed card proves nobody tampered with a snapshot — not that it is still in force. So every publication carries a monotonic sequence, previousDigest, status, and expiresAt. Verification is fail-closed (rollback, equivocation, expiry, unauthorized publisher, missing endpoint-control proof, out-of-window transport keys):

import { verifyPublication } from '@agenticprimitives/agent-resolution';

const result = await verifyPublication(publication, {
  expectedAgentId: 'eip155:84532:0xacme…',
  now: new Date().toISOString(),
  verifier: publicClient,          // any { verifyHash } — a viem PublicClient fits
  authorityCheck,                  // "was this publisher allowed to publish for this agent?"
  known: continuity,               // what we already accepted on this channel
  requireEndpointProof: true,
  maxExposure: 'private',
});

if (!result.ok) {
  // Precise codes for YOUR logs; result.failures[].wireCode for anything you return to a caller.
  if (result.freshness.conflict) escalate('publisher equivocation — possible key compromise');
}

Equivocation — two validly signed publications at the same sequence — is reported, not merely rejected. It is evidence of publisher-key compromise, not a transient error.

Rotation is cheap; identity never moves

Endpoint change, transport-key rotation, regional failover, protocol bump, and provider migration all republish at sequence + 1. No grant is reissued and the canonical agent id does not change.

Private resolution grants, not private names

Salted private names are rejected (low-entropy secret, name becomes load-bearing). Grants are opaque high-entropy capabilities (apd1_…), recipient-bound:

| Mode | Use | | --- | --- | | subject-bound (default) | Presenter proves subject SA possession — a copy is useless to others | | pairwise | Distinct grant/projection/history per relationship | | bearer-bootstrap | Short-lived only until the recipient has an SA |

const admission = await admitGrantPresentation(presentation, deps, {
  resolverAudience: 'https://resolve.acme.example/v1/private',
});
admission.projectionProfile; // 'partner' — what may be DISCLOSED, never invoked

Wire denials all use resolution_denied (no enumeration oracle); precise codes stay local.

Bootstrap, resolver, storage

Invitation = initial publication + grant + rendezvous + expected bindings (no re-invite on endpoint rotation). Org rendezvous reveals only that a private resolution service exists — replaceable, not the publication authority, cannot forge target-signed pubs or grant use. findOverDisclosure catches over-disclosure.

Owner vault (authoritative): pubs, grants, revocation, aliases. Resolver vault (ops only): keyed grant index, nonces, budgets — never the sole copy of anything that matters.

const digest = await deriveGrantDigest(grantId, resolverIndexSecret); // HMAC; 32-byte secret

Scope

Owns: discovery policy · publication verify · freshness · grants · invitations · projection · errors · provider ports. Not: transport, storage, clocks, authZ, naming, directory, search, profile, surface-catalog. Ring-0 (types only); ANS / rendezvous / DNTLS / DID are Ring-1.

Install

pnpm add @agenticprimitives/agent-resolution

License

MIT