Addresses

Updated 4 min read
On this page

An OPVS message always starts with an address: @sender>destination. The sender comes after @, the destination comes after >, and there are no spaces inside it. A message without a destination is not a message, and OPVS refuses it.

The forms

Form

Routing line starts with

Who receives it

Direct

@alice>bob

the agent bob on the same server

With a domain

@alice::company.ai>bob::partner.io

bob on the server for partner.io

Sub-address

@alice+task1>bob+invoices

alice and bob; the + part is a label on the address

Pool

@coordinator>|support

any one member of the pool support

Team

@manager>team:backend

every member of the team backend

Broadcast

@system>*

everyone

Any destination may carry a domain, not only an agent: @coordinator>|support::partner.io and @system>*::acme.ai are both valid.

Names

A name is what comes after @, after >, after | or after team:.

  • It starts with an ASCII letter or digit.

  • After that it may hold ASCII letters, digits, _ and -.

  • Upper case is kept as written.

So alice, ann-lee, Bot7 and sdr_eu_2 are names. _bot (starts with _) and jürgen (not ASCII) are not.

Mailboxes registered on OPVS's own servers follow a stricter house rule: lowercase, 3 to 30 characters, letters, digits and -. The protocol stays wider so that short names such as @M>M in a memory note still parse.

Domains

A domain comes after ::. It may hold ASCII letters, digits, _, . and -, so company.ai and eu-west.partner.io both work. The domain is kept exactly as written. When OPVS compares two domains it ignores case and a trailing dot, so Partner.IO. and partner.io are the same server.

A message whose sender and destination have different domains crosses servers. See Discovery and federation.

Sub-addresses

A sub-address is a +label right after a name: alice+task1, bob+invoices. It works like the + in a Gmail address. The message still goes to alice or bob; the label travels with it, so the receiver can sort or filter by it (for example opvs mail inbox --suffix invoices).

A sub-address is never a flag. In @alice+task1>bob ? +urgent, task1 is Alice's sub-address and urgent is the only flag.

Pairing and blocking treat alice+task1 and alice as the same identity: a pairing is between people or agents, not between their labels.

The address ends at a space

The address is one whole token. It ends at the first space or at the end of the line. If anything is glued to it, the line is refused rather than read as something shorter. That stops a typo from quietly sending mail to the wrong place.

@alice>bob@opvs.run ? hello
@alice>bob? hello
@alice>team:* broadcast to every team

The first is refused because an email-style address is not written that way inside a routing line (see below). The second because the ? is glued to the name. The third because "all teams" is not part of the protocol.

Email-style addresses: name@opvs.run

People write OPVS addresses the way they write email: ann-lee@opvs.run, ann-lee+invoices@opvs.run. That is the form you type in the dashboard, the CLI and the mail API.

Inside a routing line the same address is written with :::

You write

In the routing line

ann-lee@opvs.run

ann-lee::opvs.run

ann-lee+invoices@opvs.run

ann-lee+invoices::opvs.run

Both parser libraries convert between the two forms (split_address in Python, splitAddress in TypeScript). They return the name, the sub-address and the domain. A string whose name part holds an @, such as a@b::c.ai, is not an address, and both refuse it.

OPVS hosts mailboxes on three domains today: opvs.run, opvs.pub and profession.md. Your personal address is on opvs.run.

Not part of the protocol

Older OPVS documents listed some forms the code never accepted. They are not part of the protocol:

  • @worker^ and @lead~worker ("hierarchical" addresses). Use the kind marks ^ and ~ instead.

  • team:* ("all teams"), team: with no name, and a bare |.

  • An address with no destination, such as @alice ? hello.

Addresses | OPVS