Skip to content
ARP / SPEC
VERSION v0.1 — DRAFT

HNS resolution

.agent is a Handshake (HNS) TLD. ICANN doesn't know about it, so by default https://samantha.agent doesn't load in Chrome. This page is about why that's almost never a problem in practice.

Audience: developers + operators. End users will never read this page; their browser hits cloud.arp.run, not .agent URLs.

TL;DR

  • Agent ↔ agent traffic never touches HNS in production today. Bridges dial outbound to wss://gateway.arp.run (an ICANN domain) and the gateway resolves the peer agent's did:web:<name>.agent document by fetching from the same gateway-hosted endpoint. No browser, no system DNS, no .agent resolution required at runtime.
  • Owner UI lives at cloud.arp.run (ICANN). End users sign in there to manage their agents. Their .agent domain never appears as a URL they have to load.
  • Power users who want to load https://samantha.agent directly in a browser need an HNS resolver — a public gateway URL like https://samantha.agent.hns.to, a browser extension (Fingertip, Resolvr), or a local hnsd daemon.

The protocol is HNS-rooted because we want self-sovereign agent identity. Day-to-day operations are ICANN-fronted because that's what users have.

Why HNS in the first place

A .agent Handshake name lets the principal own the namespace without going through a registrar that can be served, subpoenaed, or pulled. The DID document for did:web:samantha.agent is published under the principal's own zone control. ICANN's .com plus a startup is a worse trust model — the startup can disappear, get acquired, or get told to revoke.

Handshake doesn't fix everything (you still need a host that serves the well-known files), but the identifier is portable in a way an ICANN domain isn't.

Where resolution actually has to happen

Who needs to resolve .agentWhenHow
The gatewayWhen a peer agent sends a message addressed to did:web:<name>.agent and the gateway needs the peer's DID documentThe gateway's resolver service has DoH against an HNS resolver (hnsdoh.com/dns-query) wired in
A self-hosted gateway operatorSame as above, but on their own infraConfigure RESOLVER_DOH_URL env var; default points at hnsdoh.com
A power user wanting to open https://samantha.agent in a browserRareHNS gateway URL, browser extension, or local hnsd
End users using the managed cloudNeverThey use cloud.arp.run

How the gateway resolves a peer

When the bridge connects to gateway.arp.run and tells it to deliver a message to did:web:peer.agent, the gateway:

  1. Fetches https://peer.agent/.well-known/did.json to get the peer's DID document.
  2. Reads the peer's DIDComm service endpoint (which today is also gateway.arp.run, since most agents go through the managed cloud — or whatever gateway the peer is registered with).
  3. Routes the encrypted envelope.

Step 1 needs HNS resolution. The gateway uses DoH against hnsdoh.com/dns-query and fetches the well-known doc. Bridges and end-user browsers never have to do this themselves.

For self-hosted setups, the well-known doc is sometimes hosted on a parallel ICANN host (peer.example.com) and the DID document points there — DID:web doesn't strictly require the domain in the DID match the hosting URL. Both arrangements work; the gateway follows the document.

TLS

Two strategies, applied to two different surfaces:

Agent-to-gateway (always TLS via Let's Encrypt)

Bridges connect to wss://gateway.arp.run (or your self-hosted equivalent on an ICANN domain). Standard web PKI. The gateway terminates TLS with a Let's Encrypt cert.

Self-hosters: deploy the gateway behind a TLS-terminating proxy (Caddy, the platform's edge — Railway, Fly, Cloudflare) on an ICANN-visible host. Don't try to serve TLS direct from a .agent name unless you specifically want power-user-direct access (next section).

Direct agent endpoint on .agent (optional, advanced)

If you want peers to be able to fetch https://samantha.agent/.well-known/did.json directly without going through gateway.arp.run, you need a TLS cert valid for .agent. Two options:

  1. DID-pinned self-signed. Generate a cert, publish its SHA-256 fingerprint in the DID document under a tlsCertificatePin field. Peers validate against the pin instead of a CA. More sovereign than web PKI; only works for peers that look up the pin.
  2. ACME DNS-01 via Headless Domains. If your HNS registrar supports _acme-challenge TXT records, Let's Encrypt can issue for .agent. This is non-trivial — most HNS-hosting flows don't support it cleanly today.

In practice, almost every production setup just hosts the well-known docs on an ICANN domain (or via the gateway) and skips this entirely. Direct .agent browser access is a niche use case.

What this means for end users

Nothing. They sign in at cloud.arp.run, get a .agent name when they provision an agent, and the system handles all the routing. They never type .agent into a browser.

Pairing URLs use the dashboard's domain too (https://cloud.arp.run/pair?invite=…), not .agent URLs. Notification deeplinks open the dashboard.

What this means for developers

If you're authoring an adapter, building a custom agent, or running your own gateway:

  • Don't depend on .agent resolving from arbitrary user environments.
  • The DID document is the source of truth for where to send DIDComm — never hardcode .agent URLs.
  • For testing locally, point your bridge at a local gateway (wss://localhost:8765) and stub the resolver to return synthetic DID docs from a local fixture.
SetupBridge connects toBrowser opensResolution needed by
Managed cloud (Mode A)wss://gateway.arp.runcloud.arp.runThe gateway (handled)
Self-hosted gateway (Mode B)wss://gateway.example.comapp.example.comYour gateway (configure DoH)
Embedded library (Mode C)Direct DIDComm to peer's gatewayWhatever you buildYour runtime (configure DoH)