OHAN protocol v1: how two people's agents meet, talk and stop
OHAN-01. the overview that ties the documents together. status: draft for v1, revised sun 25 oct 2026 after structured review passes from the angles of a w3c credentials editor, a nostr relay developer and a nostr user, and code review passes on cryptography, storage and consistency; to be published at ohan.live/spec on tue 27 oct 2026. the documents it binds: OHAN-02 card, OHAN-03 envelope, OHAN-04 relay, OHAN-05 gate, OHAN-06 security. field names are frozen where the documents say so; anything named as coming later may change.
a v1 draft. it describes what runs today on a network that is invite only, and it will change. every change is recorded, and a breaking one bumps the wire id (OHAN-00 §5).
0. in one paragraph
a person makes a key on their own device and claims a handle. the handle resolves to a signed card: keys, relays, what they chose to show. to reach someone you resolve their card, pin their key and send a sealed envelope to the relays on their card. their agent fetches it, verifies it, and if you are not yet a contact tells them only that you want to reach them. they say yes, and from then on messages flow both ways, each one signed by its sender, sealed to its recipient, held by relays that cannot read it, and shown to a person only after their own code checked it. agents draft, read and propose. people decide.
what OHAN is, and is not. OHAN carries intents, connects people and holds the yes. it does not converse. a message is the first intent it carries, and a plain hello, reply and thread between two people stay on the network for good. screening and ranking by your own rules, drafts in your voice, the call itself and the rules of a group belong to the products built on it, openDM first.
1. the objects
| object | what it is | who signs it | where it lives |
|---|---|---|---|
| handle | @name, lowercase letters, digits and dashes, 1 to 31; an agent is @name.agent | nobody; it is a name | on a card, in a did (did:web:ohan.live:name) |
| key | ed25519 to sign, x25519 to receive sealed mail | self | the person's device, encrypted at rest |
| card | the signed public record of a handle: keys, relays, listed flag, chosen profile fields, proof | the holder | any box, mirrored anywhere, derived into a did document |
| pin | {handle, sign, enc, relays} of someone you added | nobody; it is a local fact | the person's contacts file |
| envelope | ohan.envelope.1: id, from, to, sender (key, card hash, via if switched on), intent, urgency, content, proofs, thread, policy, signature | the sender | sealed inside an event; both parties' thread files after |
| event | ohan.event.1: the sealed envelope as a relay holds it: the recipient's signing key, the seal version, expiry, a stamp (the reference client stamps every event), padded ciphertext, id, signature | the sender | relays, until delivered or 30 days |
| allow | the recipient's signed list of sender keys it accepted, posted to its own relays, so a relay can tell a contact from a stranger without reading anything | the recipient | each of the recipient's relays |
| thread | a chain of envelopes with one id | each message by its sender | both parties' thread files |
| ack | an envelope with intent ack, the recipient's signed yes to a knock. sealed like any message, so no box can see it; the allow list is what the relay sees | the recipient | the sender's thread file |
later versions add agents, structured items and own domains; each publishes with its code.
2. the lifecycle
join ──► resolve ──► pin ──► knock ──► accept ──► exchange ──► record
│ │
└────── rotate / export / lapse └── unpin / block / revoke
- join. the client makes the keys, shows the card it would publish, the person says yes in a dialog, the card is stamped and registered. the handle is resolvable and unlisted. an export of the identity is offered.
- resolve.
@maya→GET /v0/resolve/@mayaon a box (handles on your own domain come later). the client verifies the card's proof against the key inside the card. the box is a courier, not an authority. - pin. after a yes in the window (y1: a pinned handle's messages skip the gate), the client stores her handle, both keys and her relays and posts
allowfor her key to its own relays. pinning is unilateral and silent; she learns nothing. - knock. the first envelope to someone who has not pinned you, sent after your yes in the window. it is a full sealed message like any other, carrying a stamp of the published stranger difficulty (18 bits), which the reference client puts on every event, because you are not on her allow list at her relays. your client remembers the handle and key you knocked for 30 days. her gate holds it and shows her only your handle.
- accept. she says yes in her dialog. her client pins you, shows the message, sends a signed
ackenvelope back through your relays, and postsallowwith your key to her own relays. your client sees the ack from exactly the handle and key it knocked, pins her, postsallowfor her key and tells you "@maya accepted you" (OHAN-05 g11). both sides now pass each other's gates, and your events land in her contact lane without stamps. - exchange. envelopes in a thread. each is signed, sealed, padded, delivered to every relay on the recipient's card, fetched with a signed request, verified, deduplicated, written to the thread file and only then marked delivered to the relay. a reply names the message it answers. each envelope carries the hash of the sender's current card, so a rotation is noticed on the next message.
- record. both sides keep every verified envelope in their own thread files. there is no copy anywhere else.
- stop. unpin, block (and unblock), rotate, export and import to another device, or let the handle lapse (it is deactivated, never given away). see OHAN-06 §9.
3. the handshake, step by step
what each side knows at each step, which is the point of the design.
| step | sender does | recipient's client does | the recipient knows | the sender knows |
|---|---|---|---|---|
| 1 | resolves @maya, verifies, pins, shows the fingerprint | nothing | nothing | her keys and relays |
| 2 | drafts; the dialog shows "send to a stranger, @maya: …"; yes; sign, pad, seal, stamp, publish | nothing yet | nothing | the relays accepted it |
| 3 | fetches with a signed request, verifies, sees an unpinned sender, holds it | "@sam wants to reach you" | nothing | |
| 4a | ignore | the same line stays | nothing, ever | |
| 4b | block | nothing more, ever | nothing, ever | |
| 4c | accept: pin, show, send ack, post allow | the message | that she accepted | |
| 5 | fetches the ack from the handle and key it knocked, pins her, posts allow (g11) |
properties: no step before 4c sends anything to the sender. a stranger cannot learn whether their message was read, held or dropped. a recipient cannot be made to see a body by sending many messages (one line per stranger, at most ten new strangers shown a day, no counts). pins are mutual only after 4c, and either side can undo their own half at any time. the yes at step 2 and at 4c is a window on the screen or the host's own prompt, never a word in the chat. one signal leaks at the relay: a sender who keeps writing after a block or a removal can infer it is not on the recipient's allow list, because the relay holds at most 3 undelivered events from a stranger and 500 from a contact (OHAN-06 r1b).
4. data exchange
v1: text. one intent, message, with content.body up to 16 kb of plain text or markdown, urgency (low, med, high, critical; the recipient's agent may downgrade), thread.id and thread.reply_to, and policy (retention, shareable_with). ack closes a knock or an offer. attachments, proofs and context items are empty in v1.
policy is a social contract with provenance. a recipient's client should honour shareable_with and retention; it cannot be forced to. every envelope carries its sender's signature, so a copy that leaks names where it came from. that is what email never had.
later versions add structured items. each publishes with its code. the rule stays "ask, don't dump": an agent sends what the other side needs to decide, not what it knows.
what may travel between two people is decided by rules enforced in code on each side; the full rules publish later.
5. how an agent understands it
OHAN does not ask the model to understand a protocol. it asks the model to understand a sentence, and gives the code everything else.
- the binding is mcp. the openthings mcp exposes the verbs as tools: start, join, my card, find, add, send, inbox, decide, remove, settings. any host that speaks mcp joins the network with no code of its own.
- the sentence shape. "join openthings as @sam", "add @maya with openthings", "tell @maya …", "what's new on openthings", "accept @maya", "block @eve". the words route the request even among ten other mcps; bare forms work too.
- every result is a script. it opens with "say this to the person, as it is:", carries the content as plain lines, and ends with "next:" naming the one thing to do or ask. the agent never has to remember protocol state.
- intents are verbs the agent already knows.
messageandackin v1; the names reserved for later are in OHAN-14. an unknown intent degrades tomessageand is shown as text. unknown fields are carried, never dropped. new intents are added to the registry file in the ohan repo with a one line meaning; nobody needs a code change to receive one. - what the agent knows about the other side: their card (what they chose to show), whether they are pinned, the fingerprint, the thread history. reputation is computed locally from signed material; no box says "trusted".
- what the agent is told it may not do: sign, send, accept, change a card, read a stranger's body, send anything that never travels (OHAN-06 e6). the instructions say it once; the code refuses regardless, as long as the model cannot run programs as the person (OHAN-06 k3).
- agent to agent is still person to person. every envelope names the principal (
from), and, only if the person switched it on, the host that sent it (sender.via). later versions add agents, structured items and own domains; each publishes with its code.
6. context
the site's first line is about where our agents and our context live. OHAN's answer in v1 is deliberately small and is the foundation of the larger one.
- context stays with the person. the card, the pins, the threads, the inbox and the consent log are plain files on the person's own device, readable by any host the person uses. switching from claude to a local model keeps the handle, the contacts and the history, with nothing rebuilt.
- what travels is the item for the decision, never the context it came from. in v1 only text travels.
- later versions add more of the person's own context at the gate and on the network; each publishes with its code.
- memory as communication. the long take says memory becomes a layer of communication kept by the person's own agent. the thread files are that layer's first form: signed, dated, verifiable, and yours.
7. addressing and resolution
@nameon the free zone isdid:web:ohan.live:name;@name.agentisdid:web:ohan.live:name:agentwithcontroller= the person.- handles on your own domain come later and publish with their code.
- relays are urls on the card and nothing else. no field in a card, an envelope or a grant may name a transport; https is the first carrier, not the protocol.
8. versioning and extension
- protocol ids on the wire:
ohan.card.1,ohan.envelope.1,ohan.event.1,ohan.relay.1(OHAN-00 §2). a breaking change bumps the number; a receiver accepts the ids it knows and says which it does not. every card and envelope carries anid(urn:uuid:), so grants and receipts can point at them later. - unknown intents degrade to
message. unknown fields are carried. unknown context item types are shown as "an item of type x". - the registry:
spec/14-registry.md(OHAN-14) lists intents, context item types, proof types and service types with a one line meaning and the version they arrived in. an application adds its own asx-<name>:<kind>until it is adopted into the list. - test vectors in
spec/vectors/: a JCS vector with a float, a Multikey vector, a card with its proof verifiable by a third party data integrity library, a sealed event, a signed fetch, a small order ephemeral key. a second implementation checks itself against them.
9. how this differs from the nearest protocols
| protocol | starts from | discovery | delivery when offline | consent at the recipient | where the gate runs | what OHAN leaves |
|---|---|---|---|---|---|---|
| OHAN v1 | the person, with keys | a handle on a box | relays holding sealed events, 30 days | a MUST: held, shown as a knock, nothing lands without a yes | the person's own device, in code | |
| Principal Agent Protocol (baur, ietf draft) | the person's device bound key, mandates that narrow | a federation registry, opt in | none: both sessions must be open | accept or reject of a token, no per contact gate | the implementer | the six phase handshake with ephemeral session dids; didcomm as the transport |
| Personal Agent Protocol ("poppy", meta and sierra, draft 0.1) | a business letting a person's agent in, over oauth | /.well-known/poppy.json | n/a | the business's terms | the business | everything person to person; it has none |
| Agent Messaging Protocol (23blocks, draft 0.1.2) | the agent, under a provider and tenant | the address agent@tenant.provider | provider queues, polling or websocket | trust level annotations; no gate | the provider | agents as subjects, no end to end encryption, no revocation |
| didcomm v2 (dif) | a did, any method | out of band invitations | mediators holding messages | none specified | the agent | jwe and jws envelopes, the mediator coordination protocol; consider a binding after the pilots |
| nostr nip-17 | a secp256k1 key | nip-05 names, relay lists | relays, kind 1059 gift wraps | none; clients filter after the fact | the client | the nsec experience, broadcast relays, no gate |
| A2A 1.0 | an agent at a domain | agent cards at well known urls | tasks on a server | none | the server | identity of the person behind the agent |
| MCP | a tool | configured by the person | n/a | the host's own approvals | the host | nothing; it is the way in |
| xmtp | a wallet key, mls groups | the wallet address | the network's nodes | consent states (unknown, allowed, denied) and a message requests view that apps are told to build | the client app | wallets as identity, and no person required behind an agent |
| aweb (awebai, mit licence, 2026) | the agent, under a dns namespace and a team controller | domain/name addresses in its registry | durable mail on federated servers; hosted mail is readable by the server | "controlled delivery": verified first contact, or team members and contacts | the server | agents as the subjects; a server that can read mail |
| NANDA index (mit media lab and project nanda, ietf individual draft, jul 2026) | an identifier resolved through a registry | an ai catalog pointing at an a2a card, an mcp descriptor or a gateway; personal agents keyed to an email with identity provider proof | n/a: resolution only | out of its scope | n/a | the email as the key to a person; it lists semantic search as a non-goal |
| x401 (proof) and agentid (agentmail), 2026 | an agent bound to a verified human through an issuer: identity proofing, or an openid connect provider | the issuer | n/a | the website or app checks the claim | the service | one issuer as everyone's gate |
| chain of trust (godaddy, infoblox, google, cloudflare; a demonstration, oct 2026) | an organisation's agent, found through dns and an agent name service | dns lookup | n/a | the merchant checks a signed, scoped mandate | the merchant and the payment provider | commerce as the only use; certificate authorities as the root |
the one sentence: the pieces are being drafted, several now tie an agent to a human through an issuer, and some networks are live. xmtp holds strangers in a requests view and seals mail end to end, but asks for no person behind an agent; moltbook claims a person behind every agent, on a platform that can read the messages. none requires a person behind every agent, holds a stranger unread on the person's own device and seals what travels, all at once, and none puts an agent on both sides of a human thing. OHAN puts those pieces together for people, in the open.
10. not in v1, on purpose
agents with their own keys; attachments, proofs and context items on the wire; listing and profile fields; own domain handles; hiding the sender from the relay; rules the person writes for the gate; presence (a product's own service, never the box's); receipts; selective disclosure; groups; payments; any index; chatgpt on the web and claude on the web (both need a hosted connector holding a scoped key, which needs grants first).