diff --git a/docs.md b/docs.md index 48e2bb3b26..f91d1b2b59 100644 --- a/docs.md +++ b/docs.md @@ -22,12 +22,14 @@ All documentation pages in Markdown. The same pages in HTML are at the same addr - [Registering a SimpleX name](https://simplex.chat/docs/guide/register-simplex-name.md) - [Secret groups](https://simplex.chat/docs/guide/secret-groups.md) - [Sending messages](https://simplex.chat/docs/guide/send-messages.md) +- [Agent protocols over SimpleX](https://simplex.chat/docs/protocol/agent-protocols.md) - [SimpleX Supporter Badges](https://simplex.chat/docs/protocol/badges-overview.md) - [Badge service RPC protocol](https://simplex.chat/docs/protocol/badges-rpc.md) - [SimpleX Channels: stateful information delivery and management](https://simplex.chat/docs/protocol/channels-overview.md) - [SimpleX Channels Protocol](https://simplex.chat/docs/protocol/channels-protocol.md) - [SimpleX Public Names for Channels and Businesses](https://simplex.chat/docs/protocol/names-overview.md) - [SimpleX Chat Protocol](https://simplex.chat/docs/protocol/simplex-chat.md) +- [Publishing SimpleX addresses on websites](https://simplex.chat/docs/protocol/web-discovery.md) - [Hosting your own SMP Server](https://simplex.chat/docs/server.md) - [SimpleX platform](https://simplex.chat/docs/simplex.md) - [App color themes](https://simplex.chat/docs/themes.md) diff --git a/docs/protocol/agent-protocols.html b/docs/protocol/agent-protocols.html new file mode 100644 index 0000000000..57ab0c62a6 --- /dev/null +++ b/docs/protocol/agent-protocols.html @@ -0,0 +1,1447 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + +
+
+
+ +
+ + + + +

Revision 1, 2026-10-19, draft for comments

+

Evgeny Poberezkin

+

Agent protocols over SimpleX

+

Table of contents

+ +

Abstract

+

This document defines how software agents find SimpleX addresses and call the tools of other agents and bots over SimpleX:

+
    +
  • an llms.txt section with communication addresses, beside the link relation types and the well-known document of Publishing SimpleX addresses on websites;
  • +
  • declarations: the protocols a profile serves and their transports, the peer types a channel or a contact address is made for, and the update frequency of a channel;
  • +
  • the chat transport: the command /_call in a conversation;
  • +
  • the Service RPC transport: one request and one response, without a conversation, in a generic envelope;
  • +
  • the binding of the Model Context Protocol (MCP) [MCP] to both transports.
  • +
+

Conventions

+

The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals.

+

JSON schemas use JSON Type Definition [RFC8927]. Whitespace in JSON examples is for readability.

+

Bot: a SimpleX profile operated by software: a bot of the bot library, or an AI agent through @simplex-chat/mcp.

+

Overview

+

A website owner publishes channels for updates and contact addresses for requests [WEB]. An agent:

+
    +
  1. reads the addresses from the website: link relations, /.well-known/simplex.json or llms.txt;
  2. +
  3. retrieves the link data with the link, without connecting;
  4. +
  5. reads the declarations;
  6. +
  7. subscribes to a channel, connects to a contact address, or sends a Service RPC request to it.
  8. +
+
sequenceDiagram
+    participant A as Agent
+    participant W as Website
+    participant R as SMP router
+    participant B as Bot
+
+    A->>W: GET /.well-known/simplex.json
+    W-->>A: channels and contacts
+    A->>R: retrieve link data
+    R-->>A: link data with declarations
+    alt chat transport
+        A->>B: connect, then /_call messages
+        B-->>A: replies
+    else Service RPC transport
+        A->>B: request in the connection request
+        B-->>A: response to the reply queue
+    end
+
+

Two transports carry protocol messages:

+
    +
  • chat: a conversation in a direct chat or a group. The caller connects once and sends commands as messages. The conversation persists between calls.
  • +
  • rpc: Service RPC. The request is sent in the connection request to a contact address, and the response to the reply queue of that request. Both sides then delete the connection. A call needs one round trip, and each call uses a new connection.
  • +
+

Addresses in llms.txt

+

An llms.txt file [LLMSTXT] lists communication addresses in a section with the heading ## Communications. The section is a file list: each item is a Markdown link, then a colon and notes.

+

The notes begin with the network and the type of the address, then the audience and, for updates, the update frequency or, for contacts, the protocols. Free text follows:

+
<network> updates for <audience>[, <frequency>]. <info>
+<network> contact for <audience>[, <protocol>]*. <info>
+
+
    +
  • <network>: the name of the network, SimpleX for SimpleX links.
  • +
  • updates: an address that publishes updates. contact: an address that accepts conversations and requests.
  • +
  • <audience>: people, agents, or people and agents.
  • +
  • <frequency>: a changefreq value of the Sitemaps protocol [SITEMAPS].
  • +
  • <protocol>: the name of a protocol the address serves (protocol names), in any letter case.
  • +
  • <info>: what the address is about.
  • +
+

The network is named in the notes because the host in a SimpleX link is the router that hosts the address, and that router can have any domain name.

+

For SimpleX entries, the type updates requires a channel link, and the type contact a contact address link [WEB]. The link text is the title of the address.

+
## Communications
+
+- [Ridgeline updates](https://smp12.simplex.im/c#…): SimpleX updates for people and agents, weekly. Trail conditions and closures.
+- [Ask Ridgeline](https://smp12.simplex.im/a#…): SimpleX contact for agents, MCP. Bookings and availability.
+- [Ridgeline support](mailto:help@ridgeline.example): Email contact for people.
+
+

Profile declarations

+

A profile or a group declares the protocols it serves in its preferences. A channel declares its audience and its update frequency in its public group record. A contact address declares the peers it serves in its link data.

+

protocols

+

protocols is a key of the preferences: preferences of a user or contact profile, and groupPreferences of a group profile [CHAT]. Clients store the preferences of other profiles as received, so a client that does not know the key decodes it after an upgrade.

+

JSON Type Definition schema [RFC8927] of the protocols key:

+
{
+  "values": {
+    "properties": {
+      "versions": {"elements": {"type": "string"}},
+      "transports": {
+        "optionalProperties": {
+          "chat": {"type": "boolean"},
+          "rpc": {"type": "boolean"}
+        },
+        "additionalProperties": true
+      }
+    },
+    "additionalProperties": true
+  }
+}
+
+
    +
  • Keys: protocol names.
  • +
  • versions: required. The protocol versions the bot serves, in the bot's order of preference.
  • +
  • transports: required. The transports on which the bot serves the protocol.
  • +
  • transports.chat: the bot answers /_call for the protocol in a conversation.
  • +
  • transports.rpc: the bot answers Service RPC requests for the protocol on its contact address. It is valid in preferences only.
  • +
  • An absent transport is false.
  • +
  • Clients MUST ignore unknown keys.
  • +
+

A declaration in preferences applies to direct chats with the profile and to Service RPC requests to its contact address. A declaration in groupPreferences states that the group's owners serve the protocol in the group chat. Other members can serve a protocol in a group without a declaration, because the core removes preferences from member profiles in groups. In a business chat, protocols of the business profile MUST be copied into the chat's groupPreferences, as commands are.

+

commands remains the command menu for people. /_call is not added to it. The underscore marks a command for software, as in the API of the core, and leaves /call free for bots' commands for people.

+

Example, the preferences of a contact profile:

+
{
+  "protocols": {
+    "mcp": {
+      "versions": ["2026-07-28"],
+      "transports": {"chat": true, "rpc": true}
+    }
+  }
+}
+
+

Channel audience and update frequency

+

Two fields of the channel's public group record, publicGroup of its group profile [CHAT]. JSON Type Definition schema [RFC8927]:

+
{
+  "optionalProperties": {
+    "audience": {"elements": {"type": "string"}},
+    "changeFrequency": {"enum": ["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"]}
+  }
+}
+
+
    +
  • audience: the peer types the channel is made for. The values are the values of a profile's peerType: human, bot, business, agent. An absent audience is ["human"]. Agents also read content made for people, so a channel declares agent when it is made for agents, or has dedicated support for them.
  • +
  • changeFrequency: how often the channel is updated. The values are the changefreq values of the Sitemaps protocol [SITEMAPS]: always, hourly, daily, weekly, monthly, yearly, never.
  • +
+

Contact address peers

+

One field of the data published with a contact address link, beside business. JSON Type Definition schema [RFC8927]:

+
{
+  "optionalProperties": {
+    "serves": {"elements": {"type": "string"}}
+  }
+}
+
+
    +
  • serves: the peer types the address is made for, with the values and the default of audience.
  • +
+

Clients MUST ignore unknown values of audience and serves. The values of the channel and the address take precedence over the values on a website [WEB].

+

Protocol names

+

A protocol name consists of lowercase ASCII letters, digits and hyphens.

+

A binding defines the protocol's request and response messages, including how, and whether, a peer discovers the protocol's capabilities. Both transports carry these messages unchanged.

+ + + + + + + + + + + + + +
NameBinding
mcpMCP binding
+

Chat transport

+

Commands

+
/_call <protocol> <request>
+/_call @<member> <protocol> <request>
+
+
    +
  • <protocol>: the name of a protocol the recipient serves.
  • +
  • <request>: the protocol's request message, a JSON object.
  • +
  • @<member>: optional, in a group: a mention of the called member [CHAT].
  • +
  • In a group, a command with a mention is answered by the mentioned member. A command without a mention is a broadcast: each member that serves the protocol answers it.
  • +
  • A command is the text of a text message. One space separates its parts.
  • +
  • A bot that declares transports.chat for a protocol MUST answer each /_call for it that mentions the bot or mentions nobody.
  • +
+

Replies

+
    +
  • A bot sends one reply to each command it answers. The reply quotes the command, with a truncated quote. Its text is the protocol's response message, a JSON object.
  • +
  • A caller matches each reply to its command by the quoted message. Replies can arrive in any order.
  • +
  • In a group, a broadcast can receive several replies, one from each member that serves the protocol. A caller collects them all, each with its sender.
  • +
  • In a direct chat, a caller accepts replies only from the recipient. In a group, a caller of a command with a mention accepts only the mentioned member's reply.
  • +
  • Commands and replies are ordinary messages: people see them in the conversation.
  • +
+

Message size

+

A command and a reply are one message each. The core refuses a message whose encoded JSON exceeds 15,602 bytes [CHAT]. The command or the reply is a string inside that JSON, so its escape characters count towards the limit. A bot whose reply exceeds the limit replies with the binding's error instead.

+

Service RPC transport

+

Exchange

+

The requester's core sends the request with:

+
/_service_request <userId> <target> [timeout=<seconds>] [sign_key=<key>] <json>
+
+
    +
  • <target>: a contact address link, full or short, or the SimpleX name of a contact address [NAMES].
  • +
  • timeout: how long the requester waits for the response. The default is 30 seconds.
  • +
  • sign_key: the requester's Ed25519 private key, for a signed request.
  • +
  • <json>: the request, a JSON object.
  • +
  • The command returns serviceResponse with responseData, the response.
  • +
+

The responder's core reports the request as the event serviceRequest, with requestId, signerKey and requestData. The responder sends the response with:

+
/_service_response <userId> <requestId> <json>
+
+

Requirements:

+
    +
  • The responder's core MUST run with service requests enabled, the option service_requests=on of /_start. Otherwise the core drops each request, and the requester waits until its timeout.
  • +
  • The responder's contact address MUST have ratchet keys. The core adds them to an address created or updated with the option pq_ratchet=on or pq_ratchet=off (/_address, /_short_link_address, /_address_settings). A request to an address without ratchet keys fails at once.
  • +
  • The core accepts a response within 180 seconds of receiving the request. A requester that expects a slow response sets timeout accordingly.
  • +
  • Before encryption, the agent pads a request or a response, its own framing included, to 11,106 bytes, and a longer one fails. A request and a response SHOULD NOT exceed 10,000 bytes of JSON.
  • +
+

Request

+

JSON Type Definition schema [RFC8927] of the request:

+
{
+  "properties": {
+    "protocol": {"type": "string"},
+    "request": {}
+  },
+  "optionalProperties": {
+    "version": {},
+    "requestKey": {"type": "string"}
+  },
+  "additionalProperties": true
+}
+
+
    +
  • protocol: the protocol name.
  • +
  • version: the protocol version, for a protocol whose messages do not include one. Its type is defined by the binding.
  • +
  • requestKey: the requester's Ed25519 public key, in the encoding of the core's signerKey: base64url of the X.509 DER encoding of the key. A request with requestKey MUST be signed with that key.
  • +
  • request: the protocol's request message, the same as after /_call <protocol> in a conversation. The fields of the envelope are never added to it.
  • +
+

Response

+

JSON Type Definition schema [RFC8927] of the response:

+
{
+  "optionalProperties": {
+    "response": {},
+    "error": {
+      "properties": {
+        "code": {"type": "string"}
+      },
+      "optionalProperties": {
+        "message": {"type": "string"},
+        "retryAfter": {"type": "uint32"}
+      },
+      "additionalProperties": true
+    }
+  },
+  "additionalProperties": true
+}
+
+
    +
  • A response has exactly one of response and error.
  • +
  • response: the protocol's response message, the same as the reply in a conversation.
  • +
  • error: the request was not passed to the protocol.
  • +
  • message: a description for the requester's logs.
  • +
  • retryAfter: the number of seconds after which a repeated request can succeed.
  • +
+

Error codes:

+
    +
  • unsupported_protocol: the responder does not serve the protocol over Service RPC.
  • +
  • unsupported_version: the responder does not serve the requested version.
  • +
  • bad_request: the envelope is invalid, or requestKey differs from the verified signer key.
  • +
  • conversation_required: the request needs a conversation. The requester connects to the address and uses the chat transport.
  • +
  • too_large: the response exceeds the size limit.
  • +
  • rate_limited: the requester repeats the request after retryAfter.
  • +
  • internal: the responder failed.
  • +
+

A requester treats an unknown code as final, unless the error has retryAfter.

+

Signed requests

+
    +
  • A signed request has the requester's Ed25519 signature over the request payload, bound to the request's ratchet session: the agent signs SHA3-256("SimpleXService" ‖ AD) ‖ payload, where AD is the ratchet's associated data. The responder's agent verifies the signature, and the core reports the key as signerKey. A signature copied into another session fails verification.
  • +
  • A responder MUST answer bad_request to a request whose requestKey differs from signerKey, and to an unsigned request with requestKey.
  • +
  • A requester signs when the responder needs a persistent identity, for example an account or a purchase. All requests signed with one key are linkable to each other. A requester SHOULD use a separate key for each responder.
  • +
  • An unsigned request has only the payload: the responder cannot link it to other requests by a key.
  • +
+

MCP binding

+

Protocol name: mcp.

+

Messages

+
    +
  • The request is one JSON-RPC request of MCP revision 2026-07-28 or later, with its _meta envelope [MCP]. In a conversation, it follows /_call mcp. Over Service RPC, it is the envelope's request.
  • +
  • The response is the JSON-RPC response to the request: a result or a JSON-RPC error. In a conversation, it is the text of the reply. Over Service RPC, it is the envelope's response.
  • +
  • In a conversation, a caller matches a reply to its request by the quoted message. The response has the request's id, as JSON-RPC requires.
  • +
  • A bot serves the methods answered with one response, for example server/discover, tools/list and tools/call.
  • +
  • A multi-round-trip result (resultType: "input_required") is answered with a new request, as MCP defines.
  • +
  • A response above the size limit is replaced with a JSON-RPC error with code -32603 in a conversation, and with the envelope error too_large over Service RPC.
  • +
  • Over Service RPC, a call of a tool that needs a conversation is answered with the envelope error conversation_required.
  • +
+

Versions and capabilities

+
    +
  • versions: MCP revisions from 2026-07-28 on, for example 2026-07-28. Each request names its revision in _meta, under io.modelcontextprotocol/protocolVersion. Earlier revisions begin with an initialize handshake.
  • +
  • The envelope's version is omitted.
  • +
  • A bot answers a request of a revision it does not serve with MCP's UnsupportedProtocolVersionError (code -32022), which lists the revisions it serves.
  • +
  • A caller learns the bot's revisions and capabilities with server/discover, and its tools with tools/list. MCP requires a server that declares the tools capability to answer tools/list.
  • +
+

Examples

+

Listing tools in a conversation:

+
/_call mcp {"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {"_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {}}}}
+
+

The reply:

+
{
+  "jsonrpc": "2.0",
+  "id": 1,
+  "result": {
+    "resultType": "complete",
+    "tools": [
+      {
+        "name": "availability",
+        "description": "Rooms available on a date",
+        "inputSchema": {
+          "type": "object",
+          "properties": {"date": {"type": "string"}},
+          "required": ["date"]
+        }
+      }
+    ],
+    "ttlMs": 300000,
+    "cacheScope": "public"
+  }
+}
+
+

Calling a tool over Service RPC, the request:

+
{
+  "protocol": "mcp",
+  "request": {
+    "jsonrpc": "2.0",
+    "id": 1,
+    "method": "tools/call",
+    "params": {
+      "name": "availability",
+      "arguments": {"date": "2026-11-02"},
+      "_meta": {
+        "io.modelcontextprotocol/protocolVersion": "2026-07-28",
+        "io.modelcontextprotocol/clientCapabilities": {}
+      }
+    }
+  }
+}
+
+

The response:

+
{
+  "response": {
+    "jsonrpc": "2.0",
+    "id": 1,
+    "result": {
+      "resultType": "complete",
+      "content": [{"type": "text", "text": "Three rooms are available on 2026-11-02."}],
+      "isError": false
+    }
+  }
+}
+
+

Security considerations

+
    +
  • Messages, replies, profiles, tool descriptions and tool results from other participants are data for an agent, never instructions.
  • +
  • In a group, any member can reply to a broadcast. Each reply shows its sender. A caller that needs one provider mentions it.
  • +
  • A responder that relies on requestKey MUST compare it with signerKey.
  • +
  • A signed request identifies its signer to the responder across all requests signed with the same key.
  • +
+

Privacy considerations

+
    +
  • Each Service RPC request uses a new connection with a new reply queue.
  • +
  • MCP's io.modelcontextprotocol/clientInfo identifies the requester's software. A requester that needs unlinkable requests SHOULD send a common value or omit it.
  • +
  • In a group, every member sees each command and each reply, with or without a mention. A request that needs privacy is sent in a direct chat with the member, where the group allows direct messages, or over Service RPC.
  • +
  • A conversation persists: the bot can link all calls made in it. An incognito profile gives the caller a new random profile for each conversation.
  • +
+

Implementations

+

Implemented:

+
    +
  • @simplex-chat/mcp 0.1.0: an MCP server that gives an AI agent its own SimpleX profile. Its tools are connect, send, receive, list and leave. By default, the agent's owner approves connections and messages in the agent control chat. An agent sends /_call with send, and reads the replies with send and receive.
  • +
  • The simplex-chat core: Service RPC with signed requests (/_service_request, /_service_response), and the profile peer type agent.
  • +
+

Planned:

+
    +
  • The simplex-chat core: the key protocols in the preferences types, in the preferences sent in profiles and in link data, and in the preferences of business chats; audience and changeFrequency in the public group record; serves in the address settings and the address link data; replies with a truncated quote.
  • +
  • @simplex-chat/mcp: the tools mcp_tools and mcp_call. They use Service RPC when the address declares transports.rpc, and the agent's conversation otherwise. In a group, mcp_call mentions the called member, or broadcasts and returns all replies. Each call is an action, approved by the agent's owner as a message is.
  • +
  • The bot library: a helper that serves MCP tools over both transports.
  • +
+

References

+ +
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/docs/protocol/agent-protocols.md b/docs/protocol/agent-protocols.md new file mode 100644 index 0000000000..6be1516367 --- /dev/null +++ b/docs/protocol/agent-protocols.md @@ -0,0 +1,469 @@ +Revision 1, 2026-10-19, draft for comments + +Evgeny Poberezkin + +# Agent protocols over SimpleX + +## Table of contents + +- [Abstract](#abstract) +- [Conventions](#conventions) +- [Overview](#overview) +- [Addresses in llms.txt](#addresses-in-llmstxt) +- [Profile declarations](#profile-declarations) + - [protocols](#protocols) + - [Channel audience and update frequency](#channel-audience-and-update-frequency) + - [Contact address peers](#contact-address-peers) + - [Protocol names](#protocol-names) +- [Chat transport](#chat-transport) + - [Commands](#commands) + - [Replies](#replies) + - [Message size](#message-size) +- [Service RPC transport](#service-rpc-transport) + - [Exchange](#exchange) + - [Request](#request) + - [Response](#response) + - [Signed requests](#signed-requests) +- [MCP binding](#mcp-binding) + - [Messages](#messages) + - [Versions and capabilities](#versions-and-capabilities) + - [Examples](#examples) +- [Security considerations](#security-considerations) +- [Privacy considerations](#privacy-considerations) +- [Implementations](#implementations) +- [References](#references) + +## Abstract + +This document defines how software agents find SimpleX addresses and call the tools of other agents and bots over SimpleX: + +- an `llms.txt` section with communication addresses, beside the link relation types and the well-known document of [Publishing SimpleX addresses on websites](https://simplex.chat/docs/protocol/web-discovery.md); +- declarations: the protocols a profile serves and their transports, the peer types a channel or a contact address is made for, and the update frequency of a channel; +- the chat transport: the command `/_call` in a conversation; +- the Service RPC transport: one request and one response, without a conversation, in a generic envelope; +- the binding of the Model Context Protocol (MCP) [MCP] to both transports. + +## Conventions + +The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals. + +JSON schemas use JSON Type Definition [RFC8927]. Whitespace in JSON examples is for readability. + +**Bot**: a SimpleX profile operated by software: a bot of the bot library, or an AI agent through `@simplex-chat/mcp`. + +## Overview + +A website owner publishes channels for updates and contact addresses for requests [WEB]. An agent: + +1. reads the addresses from the website: link relations, `/.well-known/simplex.json` or `llms.txt`; +2. retrieves the link data with the link, without connecting; +3. reads the declarations; +4. subscribes to a channel, connects to a contact address, or sends a Service RPC request to it. + +```mermaid +sequenceDiagram + participant A as Agent + participant W as Website + participant R as SMP router + participant B as Bot + + A->>W: GET /.well-known/simplex.json + W-->>A: channels and contacts + A->>R: retrieve link data + R-->>A: link data with declarations + alt chat transport + A->>B: connect, then /_call messages + B-->>A: replies + else Service RPC transport + A->>B: request in the connection request + B-->>A: response to the reply queue + end +``` + +Two transports carry protocol messages: + +- **chat**: a conversation in a direct chat or a group. The caller connects once and sends commands as messages. The conversation persists between calls. +- **rpc**: Service RPC. The request is sent in the connection request to a contact address, and the response to the reply queue of that request. Both sides then delete the connection. A call needs one round trip, and each call uses a new connection. + +## Addresses in llms.txt + +An `llms.txt` file [LLMSTXT] lists communication addresses in a section with the heading `## Communications`. The section is a file list: each item is a Markdown link, then a colon and notes. + +The notes begin with the network and the type of the address, then the audience and, for updates, the update frequency or, for contacts, the protocols. Free text follows: + +``` + updates for [, ]. + contact for [, ]*. +``` + +- ``: the name of the network, `SimpleX` for SimpleX links. +- `updates`: an address that publishes updates. `contact`: an address that accepts conversations and requests. +- ``: `people`, `agents`, or `people and agents`. +- ``: a `changefreq` value of the Sitemaps protocol [SITEMAPS]. +- ``: the name of a protocol the address serves ([protocol names](#protocol-names)), in any letter case. +- ``: what the address is about. + +The network is named in the notes because the host in a SimpleX link is the router that hosts the address, and that router can have any domain name. + +For SimpleX entries, the type `updates` requires a channel link, and the type `contact` a contact address link [WEB]. The link text is the title of the address. + +``` +## Communications + +- [Ridgeline updates](https://smp12.simplex.im/c#…): SimpleX updates for people and agents, weekly. Trail conditions and closures. +- [Ask Ridgeline](https://smp12.simplex.im/a#…): SimpleX contact for agents, MCP. Bookings and availability. +- [Ridgeline support](mailto:help@ridgeline.example): Email contact for people. +``` + +## Profile declarations + +A profile or a group declares the protocols it serves in its preferences. A channel declares its audience and its update frequency in its public group record. A contact address declares the peers it serves in its link data. + +### protocols + +`protocols` is a key of the preferences: `preferences` of a user or contact profile, and `groupPreferences` of a group profile [CHAT]. Clients store the preferences of other profiles as received, so a client that does not know the key decodes it after an upgrade. + +JSON Type Definition schema [RFC8927] of the `protocols` key: + +```json +{ + "values": { + "properties": { + "versions": {"elements": {"type": "string"}}, + "transports": { + "optionalProperties": { + "chat": {"type": "boolean"}, + "rpc": {"type": "boolean"} + }, + "additionalProperties": true + } + }, + "additionalProperties": true + } +} +``` + +- Keys: protocol names. +- `versions`: required. The protocol versions the bot serves, in the bot's order of preference. +- `transports`: required. The transports on which the bot serves the protocol. +- `transports.chat`: the bot answers `/_call` for the protocol in a conversation. +- `transports.rpc`: the bot answers Service RPC requests for the protocol on its contact address. It is valid in `preferences` only. +- An absent transport is false. +- Clients MUST ignore unknown keys. + +A declaration in `preferences` applies to direct chats with the profile and to Service RPC requests to its contact address. A declaration in `groupPreferences` states that the group's owners serve the protocol in the group chat. Other members can serve a protocol in a group without a declaration, because the core removes preferences from member profiles in groups. In a business chat, `protocols` of the business profile MUST be copied into the chat's `groupPreferences`, as `commands` are. + +`commands` remains the command menu for people. `/_call` is not added to it. The underscore marks a command for software, as in the API of the core, and leaves `/call` free for bots' commands for people. + +Example, the `preferences` of a contact profile: + +```json +{ + "protocols": { + "mcp": { + "versions": ["2026-07-28"], + "transports": {"chat": true, "rpc": true} + } + } +} +``` + +### Channel audience and update frequency + +Two fields of the channel's public group record, `publicGroup` of its group profile [CHAT]. JSON Type Definition schema [RFC8927]: + +```json +{ + "optionalProperties": { + "audience": {"elements": {"type": "string"}}, + "changeFrequency": {"enum": ["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"]} + } +} +``` + +- `audience`: the peer types the channel is made for. The values are the values of a profile's `peerType`: `human`, `bot`, `business`, `agent`. An absent `audience` is `["human"]`. Agents also read content made for people, so a channel declares `agent` when it is made for agents, or has dedicated support for them. +- `changeFrequency`: how often the channel is updated. The values are the `changefreq` values of the Sitemaps protocol [SITEMAPS]: `always`, `hourly`, `daily`, `weekly`, `monthly`, `yearly`, `never`. + +### Contact address peers + +One field of the data published with a contact address link, beside `business`. JSON Type Definition schema [RFC8927]: + +```json +{ + "optionalProperties": { + "serves": {"elements": {"type": "string"}} + } +} +``` + +- `serves`: the peer types the address is made for, with the values and the default of `audience`. + +Clients MUST ignore unknown values of `audience` and `serves`. The values of the channel and the address take precedence over the values on a website [WEB]. + +### Protocol names + +A protocol name consists of lowercase ASCII letters, digits and hyphens. + +A binding defines the protocol's request and response messages, including how, and whether, a peer discovers the protocol's capabilities. Both transports carry these messages unchanged. + +| Name | Binding | +|---|---| +| `mcp` | [MCP binding](#mcp-binding) | + +## Chat transport + +### Commands + +``` +/_call +/_call @ +``` + +- ``: the name of a protocol the recipient serves. +- ``: the protocol's request message, a JSON object. +- `@`: optional, in a group: a mention of the called member [CHAT]. +- In a group, a command with a mention is answered by the mentioned member. A command without a mention is a broadcast: each member that serves the protocol answers it. +- A command is the text of a text message. One space separates its parts. +- A bot that declares `transports.chat` for a protocol MUST answer each `/_call` for it that mentions the bot or mentions nobody. + +### Replies + +- A bot sends one reply to each command it answers. The reply quotes the command, with a truncated quote. Its text is the protocol's response message, a JSON object. +- A caller matches each reply to its command by the quoted message. Replies can arrive in any order. +- In a group, a broadcast can receive several replies, one from each member that serves the protocol. A caller collects them all, each with its sender. +- In a direct chat, a caller accepts replies only from the recipient. In a group, a caller of a command with a mention accepts only the mentioned member's reply. +- Commands and replies are ordinary messages: people see them in the conversation. + +### Message size + +A command and a reply are one message each. The core refuses a message whose encoded JSON exceeds 15,602 bytes [CHAT]. The command or the reply is a string inside that JSON, so its escape characters count towards the limit. A bot whose reply exceeds the limit replies with the binding's error instead. + +## Service RPC transport + +### Exchange + +The requester's core sends the request with: + +``` +/_service_request [timeout=] [sign_key=] +``` + +- ``: a contact address link, full or short, or the SimpleX name of a contact address [NAMES]. +- `timeout`: how long the requester waits for the response. The default is 30 seconds. +- `sign_key`: the requester's Ed25519 private key, for a [signed request](#signed-requests). +- ``: the [request](#request), a JSON object. +- The command returns `serviceResponse` with `responseData`, the [response](#response). + +The responder's core reports the request as the event `serviceRequest`, with `requestId`, `signerKey` and `requestData`. The responder sends the response with: + +``` +/_service_response +``` + +Requirements: + +- The responder's core MUST run with service requests enabled, the option `service_requests=on` of `/_start`. Otherwise the core drops each request, and the requester waits until its timeout. +- The responder's contact address MUST have ratchet keys. The core adds them to an address created or updated with the option `pq_ratchet=on` or `pq_ratchet=off` (`/_address`, `/_short_link_address`, `/_address_settings`). A request to an address without ratchet keys fails at once. +- The core accepts a response within 180 seconds of receiving the request. A requester that expects a slow response sets `timeout` accordingly. +- Before encryption, the agent pads a request or a response, its own framing included, to 11,106 bytes, and a longer one fails. A request and a response SHOULD NOT exceed 10,000 bytes of JSON. + +### Request + +JSON Type Definition schema [RFC8927] of the request: + +```json +{ + "properties": { + "protocol": {"type": "string"}, + "request": {} + }, + "optionalProperties": { + "version": {}, + "requestKey": {"type": "string"} + }, + "additionalProperties": true +} +``` + +- `protocol`: the protocol name. +- `version`: the protocol version, for a protocol whose messages do not include one. Its type is defined by the binding. +- `requestKey`: the requester's Ed25519 public key, in the encoding of the core's `signerKey`: base64url of the X.509 DER encoding of the key. A request with `requestKey` MUST be signed with that key. +- `request`: the protocol's request message, the same as after `/_call ` in a conversation. The fields of the envelope are never added to it. + +### Response + +JSON Type Definition schema [RFC8927] of the response: + +```json +{ + "optionalProperties": { + "response": {}, + "error": { + "properties": { + "code": {"type": "string"} + }, + "optionalProperties": { + "message": {"type": "string"}, + "retryAfter": {"type": "uint32"} + }, + "additionalProperties": true + } + }, + "additionalProperties": true +} +``` + +- A response has exactly one of `response` and `error`. +- `response`: the protocol's response message, the same as the reply in a conversation. +- `error`: the request was not passed to the protocol. +- `message`: a description for the requester's logs. +- `retryAfter`: the number of seconds after which a repeated request can succeed. + +Error codes: + +- `unsupported_protocol`: the responder does not serve the protocol over Service RPC. +- `unsupported_version`: the responder does not serve the requested version. +- `bad_request`: the envelope is invalid, or `requestKey` differs from the verified signer key. +- `conversation_required`: the request needs a conversation. The requester connects to the address and uses the chat transport. +- `too_large`: the response exceeds the size limit. +- `rate_limited`: the requester repeats the request after `retryAfter`. +- `internal`: the responder failed. + +A requester treats an unknown code as final, unless the error has `retryAfter`. + +### Signed requests + +- A signed request has the requester's Ed25519 signature over the request payload, bound to the request's ratchet session: the agent signs `SHA3-256("SimpleXService" ‖ AD) ‖ payload`, where AD is the ratchet's associated data. The responder's agent verifies the signature, and the core reports the key as `signerKey`. A signature copied into another session fails verification. +- A responder MUST answer `bad_request` to a request whose `requestKey` differs from `signerKey`, and to an unsigned request with `requestKey`. +- A requester signs when the responder needs a persistent identity, for example an account or a purchase. All requests signed with one key are linkable to each other. A requester SHOULD use a separate key for each responder. +- An unsigned request has only the payload: the responder cannot link it to other requests by a key. + +## MCP binding + +Protocol name: `mcp`. + +### Messages + +- The request is one JSON-RPC request of MCP revision 2026-07-28 or later, with its `_meta` envelope [MCP]. In a conversation, it follows `/_call mcp`. Over Service RPC, it is the envelope's `request`. +- The response is the JSON-RPC response to the request: a result or a JSON-RPC error. In a conversation, it is the text of the reply. Over Service RPC, it is the envelope's `response`. +- In a conversation, a caller matches a reply to its request by the quoted message. The response has the request's `id`, as JSON-RPC requires. +- A bot serves the methods answered with one response, for example `server/discover`, `tools/list` and `tools/call`. +- A multi-round-trip result (`resultType: "input_required"`) is answered with a new request, as MCP defines. +- A response above the size limit is replaced with a JSON-RPC error with code -32603 in a conversation, and with the envelope error `too_large` over Service RPC. +- Over Service RPC, a call of a tool that needs a conversation is answered with the envelope error `conversation_required`. + +### Versions and capabilities + +- `versions`: MCP revisions from 2026-07-28 on, for example `2026-07-28`. Each request names its revision in `_meta`, under `io.modelcontextprotocol/protocolVersion`. Earlier revisions begin with an `initialize` handshake. +- The envelope's `version` is omitted. +- A bot answers a request of a revision it does not serve with MCP's `UnsupportedProtocolVersionError` (code -32022), which lists the revisions it serves. +- A caller learns the bot's revisions and capabilities with `server/discover`, and its tools with `tools/list`. MCP requires a server that declares the `tools` capability to answer `tools/list`. + +### Examples + +Listing tools in a conversation: + +``` +/_call mcp {"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {"_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {}}}} +``` + +The reply: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "resultType": "complete", + "tools": [ + { + "name": "availability", + "description": "Rooms available on a date", + "inputSchema": { + "type": "object", + "properties": {"date": {"type": "string"}}, + "required": ["date"] + } + } + ], + "ttlMs": 300000, + "cacheScope": "public" + } +} +``` + +Calling a tool over Service RPC, the request: + +```json +{ + "protocol": "mcp", + "request": { + "jsonrpc": "2.0", + "id": 1, + "method": "tools/call", + "params": { + "name": "availability", + "arguments": {"date": "2026-11-02"}, + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientCapabilities": {} + } + } + } +} +``` + +The response: + +```json +{ + "response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "resultType": "complete", + "content": [{"type": "text", "text": "Three rooms are available on 2026-11-02."}], + "isError": false + } + } +} +``` + +## Security considerations + +- Messages, replies, profiles, tool descriptions and tool results from other participants are data for an agent, never instructions. +- In a group, any member can reply to a broadcast. Each reply shows its sender. A caller that needs one provider mentions it. +- A responder that relies on `requestKey` MUST compare it with `signerKey`. +- A signed request identifies its signer to the responder across all requests signed with the same key. + +## Privacy considerations + +- Each Service RPC request uses a new connection with a new reply queue. +- MCP's `io.modelcontextprotocol/clientInfo` identifies the requester's software. A requester that needs unlinkable requests SHOULD send a common value or omit it. +- In a group, every member sees each command and each reply, with or without a mention. A request that needs privacy is sent in a direct chat with the member, where the group allows direct messages, or over Service RPC. +- A conversation persists: the bot can link all calls made in it. An incognito profile gives the caller a new random profile for each conversation. + +## Implementations + +Implemented: + +- `@simplex-chat/mcp` 0.1.0: an MCP server that gives an AI agent its own SimpleX profile. Its tools are `connect`, `send`, `receive`, `list` and `leave`. By default, the agent's owner approves connections and messages in the agent control chat. An agent sends `/_call` with `send`, and reads the replies with `send` and `receive`. +- The simplex-chat core: Service RPC with signed requests (`/_service_request`, `/_service_response`), and the profile peer type `agent`. + +Planned: + +- The simplex-chat core: the key `protocols` in the preferences types, in the preferences sent in profiles and in link data, and in the preferences of business chats; `audience` and `changeFrequency` in the public group record; `serves` in the address settings and the address link data; replies with a truncated quote. +- `@simplex-chat/mcp`: the tools `mcp_tools` and `mcp_call`. They use Service RPC when the address declares `transports.rpc`, and the agent's conversation otherwise. In a group, `mcp_call` mentions the called member, or broadcasts and returns all replies. Each call is an action, approved by the agent's owner as a message is. +- The bot library: a helper that serves MCP tools over both transports. + +## References + +- [CHAT] SimpleX Chat protocol: [simplex-chat.md](https://simplex.chat/docs/protocol/simplex-chat.md) +- [LLMSTXT] The /llms.txt file: https://llmstxt.org +- [MCP] Model Context Protocol specification, revision 2026-07-28: https://modelcontextprotocol.io/specification/2026-07-28 +- [NAMES] SimpleX public names for channels and businesses: [names-overview.md](https://simplex.chat/docs/protocol/names-overview.md) +- [RFC2119] Key words for use in RFCs to Indicate Requirement Levels: https://www.rfc-editor.org/rfc/rfc2119 +- [RFC8174] Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words: https://www.rfc-editor.org/rfc/rfc8174 +- [RFC8927] JSON Type Definition: https://www.rfc-editor.org/rfc/rfc8927 +- [SITEMAPS] Sitemaps XML format: https://www.sitemaps.org/protocol.html +- [WEB] Publishing SimpleX addresses on websites: [web-discovery.md](https://simplex.chat/docs/protocol/web-discovery.md) diff --git a/docs/protocol/web-discovery.html b/docs/protocol/web-discovery.html new file mode 100644 index 0000000000..ce7da46c12 --- /dev/null +++ b/docs/protocol/web-discovery.html @@ -0,0 +1,1292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + +
+
+
+ +
+ + + + +

Revision 1, 2026-10-19, draft

+

Evgeny Poberezkin

+

Publishing SimpleX addresses on websites

+

Table of contents

+ +

Abstract

+

This document defines how a website publishes the SimpleX channels and contact addresses of its owner:

+
    +
  • the link relation types simplex-channel and simplex-contact, for the HTML elements link, a and area, and for the HTTP Link header field;
  • +
  • the well-known URI simplex.json: a JSON document with the owner's channels and contact addresses, their audience, the update frequency of each channel and the protocols each contact address serves.
  • +
+

People and software agents subscribe to a channel to receive updates, and connect to a contact address to send requests. Agent protocols over SimpleX defines the requests an agent sends to a contact address, and an llms.txt section with the same addresses.

+

Conventions

+

The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals.

+

JSON schemas use JSON Type Definition [RFC8927].

+

Terms

+
    +
  • SimpleX link: a connection link of the SimpleX Agent protocol, in the full or the short syntax, with the https or the simplex scheme [AGENT].
  • +
  • Channel link: a short SimpleX link of type c, for example https://smp12.simplex.im/c#<key>.
  • +
  • Contact address link: a short SimpleX link of type a, for example https://smp12.simplex.im/a#<key>, or a full SimpleX link of type contact.
  • +
  • SimpleX name: a name in the SimpleX name service [NAMES]. #example.simplex is the name of a channel, @example.simplex the name of a contact address.
  • +
  • Owner: the person or organization that publishes the website.
  • +
+ +

simplex-channel

+

The target of a simplex-channel link is a SimpleX channel in which the owner of the link context publishes updates. The target MUST be a channel link.

+

simplex-contact

+

The target of a simplex-contact link is a SimpleX contact address at which the owner of the link context accepts conversations and requests. The target MUST be a contact address link.

+

Target attributes

+
    +
  • title: the name of the channel or the address, for display. In HTTP, a title with non-ASCII characters is sent as title* [RFC8187].
  • +
  • hreflang: the language of the channel's posts or of the conversations [BCP47].
  • +
+

A link context MAY have several links of one relation type. Their order is the owner's order of preference: document order in HTML, and the order of link values in HTTP.

+

HTML

+

In the document head:

+
<link rel="simplex-channel" href="https://smp12.simplex.im/c#…" hreflang="en" title="Ridgeline updates">
+<link rel="simplex-contact" href="https://smp12.simplex.im/a#…" hreflang="en" title="Ask Ridgeline">
+
+

In the document body, the relation types are used on visible links:

+
<a rel="simplex-contact" href="https://smp12.simplex.im/a#…">Chat with us</a>
+
+

HTTP

+
Link: <https://smp12.simplex.im/c#…>; rel="simplex-channel"; hreflang="en"; title="Ridgeline updates"
+Link: <https://smp12.simplex.im/a#…>; rel="simplex-contact"; hreflang="en"; title="Ask Ridgeline"
+
+

Well-known URI

+

Retrieval

+

The document is located at the path /.well-known/simplex.json of an origin [RFC8615]. A client retrieves it with an HTTPS GET request. A server responds with status 200, and SHOULD send the media type application/json. A client parses the response body as JSON, whatever media type the server sends.

+

The entries of the document are the channels and contact addresses of the origin's owner. A site that controls only a path of its origin publishes link relations instead.

+

Format

+

The document MUST conform to this JSON Type Definition schema [RFC8927]:

+
{
+  "optionalProperties": {
+    "channels": {"elements": {"ref": "address"}},
+    "contacts": {"elements": {"ref": "address"}}
+  },
+  "additionalProperties": true,
+  "definitions": {
+    "address": {
+      "properties": {
+        "link": {"type": "string"}
+      },
+      "optionalProperties": {
+        "name": {"type": "string"},
+        "title": {"type": "string"},
+        "lang": {"type": "string"},
+        "audience": {"elements": {"type": "string"}},
+        "changeFrequency": {"enum": ["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"]},
+        "protocols": {"elements": {"type": "string"}}
+      },
+      "additionalProperties": true
+    }
+  }
+}
+
+
    +
  • channels: the owner's channels, in the owner's order of preference.
  • +
  • contacts: the owner's contact addresses, in the owner's order of preference.
  • +
  • link: required. A channel link in channels, a contact address link in contacts.
  • +
  • name: the SimpleX name of the channel or the contact address of link.
  • +
  • title: the name of the channel or the address, for display.
  • +
  • lang: the language of the channel's posts or of the conversations [BCP47].
  • +
  • audience: who the channel or the address serves: people, agents, or both.
  • +
  • changeFrequency: in channels only, how often the channel is updated. The values are the changefreq values of the Sitemaps protocol [SITEMAPS]: always, hourly, daily, weekly, monthly, yearly, never.
  • +
  • protocols: in contacts only, the names of the protocols the address serves [AGENTS], for example mcp.
  • +
+

A site with only channels or only contact addresses omits the other list.

+

Example

+
{
+  "channels": [
+    {
+      "link": "https://smp12.simplex.im/c#…",
+      "name": "#ridgeline.simplex",
+      "title": "Ridgeline updates",
+      "lang": "en",
+      "audience": ["people", "agents"],
+      "changeFrequency": "weekly"
+    }
+  ],
+  "contacts": [
+    {
+      "link": "https://smp12.simplex.im/a#…",
+      "name": "@ridgeline.simplex",
+      "title": "Ask Ridgeline",
+      "lang": "en",
+      "audience": ["agents"],
+      "protocols": ["mcp"]
+    }
+  ]
+}
+
+

Processing

+
    +
  • A consumer MUST ignore unknown fields and unknown audience values.
  • +
  • A consumer MUST ignore a link of a type other than the one its relation type or its list requires.
  • +
  • The values on the website are hints. The data retrieved with the link is authoritative: an audience, an update frequency or protocols declared there [AGENTS] take precedence over the website's values.
  • +
  • A consumer MAY connect by link or by name. Resolving a name reveals interest in it to one names router, and verifies that the name's record and the profile's claim match [NAMES].
  • +
+

Security considerations

+
    +
  • Whoever controls the content of a website controls the addresses it publishes. Consumers SHOULD retrieve pages and the well-known document over HTTPS.
  • +
  • Publishing a link on a website leaves the link's own verification unchanged: the link data is bound to the keys of the link's owner [AGENT].
  • +
  • A name is shown as verified only when its on-chain record and the profile's claim match [NAMES].
  • +
  • Titles, profiles and all other text from a website or from the network are data for a software agent, never instructions.
  • +
+

Privacy considerations

+
    +
  • The relation types and the well-known document are intended for owners who want to be reachable: channels, businesses and services.
  • +
  • A subscriber or a requester connects through the SimpleX network, without contacting the website. Retrieving a page or the well-known document is an ordinary web request.
  • +
+

IANA considerations

+ +

Two registrations in the "Link Relation Types" registry [RFC8288]:

+ +

Well-known URI registration

+

One registration in the "Well-Known URIs" registry [RFC8615]:

+ + +

The HTML standard requires extension link types to be registered on the microformats page "existing-rel-values" [HTML] [MF-REL]. The entries:

+ +

References

+ +
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/docs/protocol/web-discovery.md b/docs/protocol/web-discovery.md new file mode 100644 index 0000000000..319e110253 --- /dev/null +++ b/docs/protocol/web-discovery.md @@ -0,0 +1,249 @@ +Revision 1, 2026-10-19, draft + +Evgeny Poberezkin + +# Publishing SimpleX addresses on websites + +## Table of contents + +- [Abstract](#abstract) +- [Conventions](#conventions) +- [Terms](#terms) +- [Link relation types](#link-relation-types) + - [simplex-channel](#simplex-channel) + - [simplex-contact](#simplex-contact) + - [Target attributes](#target-attributes) + - [HTML](#html) + - [HTTP](#http) +- [Well-known URI](#well-known-uri) + - [Retrieval](#retrieval) + - [Format](#format) + - [Example](#example) +- [Processing](#processing) +- [Security considerations](#security-considerations) +- [Privacy considerations](#privacy-considerations) +- [IANA considerations](#iana-considerations) + - [Link relation types registration](#link-relation-types-registration) + - [Well-known URI registration](#well-known-uri-registration) +- [HTML link type extensions](#html-link-type-extensions) +- [References](#references) + +## Abstract + +This document defines how a website publishes the SimpleX channels and contact addresses of its owner: + +- the link relation types `simplex-channel` and `simplex-contact`, for the HTML elements `link`, `a` and `area`, and for the HTTP `Link` header field; +- the well-known URI `simplex.json`: a JSON document with the owner's channels and contact addresses, their audience, the update frequency of each channel and the protocols each contact address serves. + +People and software agents subscribe to a channel to receive updates, and connect to a contact address to send requests. [Agent protocols over SimpleX](https://simplex.chat/docs/protocol/agent-protocols.md) defines the requests an agent sends to a contact address, and an `llms.txt` section with the same addresses. + +## Conventions + +The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals. + +JSON schemas use JSON Type Definition [RFC8927]. + +## Terms + +- **SimpleX link**: a connection link of the SimpleX Agent protocol, in the full or the short syntax, with the `https` or the `simplex` scheme [AGENT]. +- **Channel link**: a short SimpleX link of type `c`, for example `https://smp12.simplex.im/c#`. +- **Contact address link**: a short SimpleX link of type `a`, for example `https://smp12.simplex.im/a#`, or a full SimpleX link of type `contact`. +- **SimpleX name**: a name in the SimpleX name service [NAMES]. `#example.simplex` is the name of a channel, `@example.simplex` the name of a contact address. +- **Owner**: the person or organization that publishes the website. + +## Link relation types + +### simplex-channel + +The target of a `simplex-channel` link is a SimpleX channel in which the owner of the link context publishes updates. The target MUST be a channel link. + +### simplex-contact + +The target of a `simplex-contact` link is a SimpleX contact address at which the owner of the link context accepts conversations and requests. The target MUST be a contact address link. + +### Target attributes + +- `title`: the name of the channel or the address, for display. In HTTP, a title with non-ASCII characters is sent as `title*` [RFC8187]. +- `hreflang`: the language of the channel's posts or of the conversations [BCP47]. + +A link context MAY have several links of one relation type. Their order is the owner's order of preference: document order in HTML, and the order of link values in HTTP. + +### HTML + +In the document head: + +```html + + +``` + +In the document body, the relation types are used on visible links: + +```html +Chat with us +``` + +### HTTP + +``` +Link: ; rel="simplex-channel"; hreflang="en"; title="Ridgeline updates" +Link: ; rel="simplex-contact"; hreflang="en"; title="Ask Ridgeline" +``` + +## Well-known URI + +### Retrieval + +The document is located at the path `/.well-known/simplex.json` of an origin [RFC8615]. A client retrieves it with an HTTPS `GET` request. A server responds with status 200, and SHOULD send the media type `application/json`. A client parses the response body as JSON, whatever media type the server sends. + +The entries of the document are the channels and contact addresses of the origin's owner. A site that controls only a path of its origin publishes link relations instead. + +### Format + +The document MUST conform to this JSON Type Definition schema [RFC8927]: + +```json +{ + "optionalProperties": { + "channels": {"elements": {"ref": "address"}}, + "contacts": {"elements": {"ref": "address"}} + }, + "additionalProperties": true, + "definitions": { + "address": { + "properties": { + "link": {"type": "string"} + }, + "optionalProperties": { + "name": {"type": "string"}, + "title": {"type": "string"}, + "lang": {"type": "string"}, + "audience": {"elements": {"type": "string"}}, + "changeFrequency": {"enum": ["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"]}, + "protocols": {"elements": {"type": "string"}} + }, + "additionalProperties": true + } + } +} +``` + +- `channels`: the owner's channels, in the owner's order of preference. +- `contacts`: the owner's contact addresses, in the owner's order of preference. +- `link`: required. A channel link in `channels`, a contact address link in `contacts`. +- `name`: the SimpleX name of the channel or the contact address of `link`. +- `title`: the name of the channel or the address, for display. +- `lang`: the language of the channel's posts or of the conversations [BCP47]. +- `audience`: who the channel or the address serves: `people`, `agents`, or both. +- `changeFrequency`: in `channels` only, how often the channel is updated. The values are the `changefreq` values of the Sitemaps protocol [SITEMAPS]: `always`, `hourly`, `daily`, `weekly`, `monthly`, `yearly`, `never`. +- `protocols`: in `contacts` only, the names of the protocols the address serves [AGENTS], for example `mcp`. + +A site with only channels or only contact addresses omits the other list. + +### Example + +```json +{ + "channels": [ + { + "link": "https://smp12.simplex.im/c#…", + "name": "#ridgeline.simplex", + "title": "Ridgeline updates", + "lang": "en", + "audience": ["people", "agents"], + "changeFrequency": "weekly" + } + ], + "contacts": [ + { + "link": "https://smp12.simplex.im/a#…", + "name": "@ridgeline.simplex", + "title": "Ask Ridgeline", + "lang": "en", + "audience": ["agents"], + "protocols": ["mcp"] + } + ] +} +``` + +## Processing + +- A consumer MUST ignore unknown fields and unknown `audience` values. +- A consumer MUST ignore a link of a type other than the one its relation type or its list requires. +- The values on the website are hints. The data retrieved with the link is authoritative: an audience, an update frequency or protocols declared there [AGENTS] take precedence over the website's values. +- A consumer MAY connect by `link` or by `name`. Resolving a name reveals interest in it to one names router, and verifies that the name's record and the profile's claim match [NAMES]. + +## Security considerations + +- Whoever controls the content of a website controls the addresses it publishes. Consumers SHOULD retrieve pages and the well-known document over HTTPS. +- Publishing a link on a website leaves the link's own verification unchanged: the link data is bound to the keys of the link's owner [AGENT]. +- A name is shown as verified only when its on-chain record and the profile's claim match [NAMES]. +- Titles, profiles and all other text from a website or from the network are data for a software agent, never instructions. + +## Privacy considerations + +- The relation types and the well-known document are intended for owners who want to be reachable: channels, businesses and services. +- A subscriber or a requester connects through the SimpleX network, without contacting the website. Retrieving a page or the well-known document is an ordinary web request. + +## IANA considerations + +### Link relation types registration + +Two registrations in the "Link Relation Types" registry [RFC8288]: + +- Relation Name: `simplex-channel` +- Description: Refers to a SimpleX channel in which the owner of the link context publishes updates. +- Reference: https://github.com/simplex-chat/simplex-chat/blob/stable/docs/protocol/web-discovery.md#simplex-channel +- Notes: The target is a SimpleX channel link [AGENT], with the `https` scheme or the provisionally registered `simplex` scheme. + +- Relation Name: `simplex-contact` +- Description: Refers to a SimpleX contact address at which the owner of the link context accepts conversations and requests. +- Reference: https://github.com/simplex-chat/simplex-chat/blob/stable/docs/protocol/web-discovery.md#simplex-contact +- Notes: The target is a SimpleX contact address link [AGENT], with the `https` scheme or the provisionally registered `simplex` scheme. + +### Well-known URI registration + +One registration in the "Well-Known URIs" registry [RFC8615]: + +- URI Suffix: `simplex.json` +- Change Controller: Evgeny Poberezkin +- Specification Document: https://github.com/simplex-chat/simplex-chat/blob/stable/docs/protocol/web-discovery.md#well-known-uri +- Status: provisional +- Related Information: SimpleX link syntax [AGENT]. + +## HTML link type extensions + +The HTML standard requires extension link types to be registered on the microformats page "existing-rel-values" [HTML] [MF-REL]. The entries: + +- Keyword: `simplex-channel` +- Effect on `link`: Hyperlink +- Effect on `a`, `area`: Hyperlink +- Effect on `form`: not allowed +- Brief description: Refers to a SimpleX channel in which the owner of the page publishes updates. +- Specification: https://github.com/simplex-chat/simplex-chat/blob/stable/docs/protocol/web-discovery.md#simplex-channel +- Status: proposed + +- Keyword: `simplex-contact` +- Effect on `link`: Hyperlink +- Effect on `a`, `area`: Hyperlink +- Effect on `form`: not allowed +- Brief description: Refers to a SimpleX contact address at which the owner of the page accepts conversations and requests. +- Specification: https://github.com/simplex-chat/simplex-chat/blob/stable/docs/protocol/web-discovery.md#simplex-contact +- Status: proposed + +## References + +- [AGENT] SimpleX Agent protocol, connection links: https://github.com/simplex-chat/simplexmq/blob/stable/protocol/agent-protocol.md#connection-link-1-time-invitation-and-contact-address +- [AGENTS] Agent protocols over SimpleX: [agent-protocols.md](https://simplex.chat/docs/protocol/agent-protocols.md) +- [BCP47] Tags for Identifying Languages: https://www.rfc-editor.org/info/bcp47 +- [HTML] HTML Living Standard, other link types: https://html.spec.whatwg.org/multipage/links.html#other-link-types +- [MF-REL] Microformats, existing rel values: https://microformats.org/wiki/existing-rel-values +- [NAMES] SimpleX public names for channels and businesses: [names-overview.md](https://simplex.chat/docs/protocol/names-overview.md) +- [RFC2119] Key words for use in RFCs to Indicate Requirement Levels: https://www.rfc-editor.org/rfc/rfc2119 +- [RFC8174] Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words: https://www.rfc-editor.org/rfc/rfc8174 +- [RFC8187] Indicating Character Encoding and Language for HTTP Header Field Parameters: https://www.rfc-editor.org/rfc/rfc8187 +- [RFC8288] Web Linking: https://www.rfc-editor.org/rfc/rfc8288 +- [RFC8615] Well-Known Uniform Resource Identifiers (URIs): https://www.rfc-editor.org/rfc/rfc8615 +- [RFC8927] JSON Type Definition: https://www.rfc-editor.org/rfc/rfc8927 +- [SITEMAPS] Sitemaps XML format: https://www.sitemaps.org/protocol.html diff --git a/sitemap.xml b/sitemap.xml index d926a55437..f91a0c8885 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -142,12 +142,14 @@ https://simplex.chat/docs/lang/pl/simplex.html https://simplex.chat/docs/lang/pl/translations.html https://simplex.chat/docs/lang/pl/webrtc.html + https://simplex.chat/docs/protocol/agent-protocols.html https://simplex.chat/docs/protocol/badges-overview.html https://simplex.chat/docs/protocol/badges-rpc.html https://simplex.chat/docs/protocol/channels-overview.html https://simplex.chat/docs/protocol/channels-protocol.html https://simplex.chat/docs/protocol/names-overview.html https://simplex.chat/docs/protocol/simplex-chat.html + https://simplex.chat/docs/protocol/web-discovery.html https://simplex.chat/docs/server.html https://simplex.chat/docs/simplex.html https://simplex.chat/docs/themes.html