openvibers/openvibe.contracts Commits
Mail: an agent answers the mail sent to its own address (0.342.0) (#349)
Changes
@@@ -1,5 +1,14 @@# Changelog++## 0.342.0 — 2026-11-07++++- Add `mail.agent_inbox.received@1` (track HO6, channels): a message arrived at an agent's own address and the person has switched that address's answering on, so their agent may read it. The payload names the inbox and the agent, the owner, the mail server's message id, the sender, the subject and a plain-text excerpt of at most 4000 characters. It never carries the attachments, the HTML or the whole body: the agent's system reads the text through `mail.agent.read`, on the owner's behalf, once it has decided to answer. Mail publishes nothing for a sender on the person's block list or a message the mail server marked as spam, and nothing at all until the person turns the agent's switch on.++- Add `mail.agent-inbox-message@1`, the one message an agent reads: the sender, the addresses the mail server stamped at delivery, the subject, the text cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender-written Delivered-To. The message is data from a stranger, and any instruction in it is that stranger's.++- Add `mail.agent-reply-request@1` and `mail.agent-reply-result@1`, an agent answering one such letter: the body is plain text, the recipient is the sender of the message being answered (the same address may be named, never another), and the reply carries In-Reply-To and References so the thread stays one thread. The result says whether the mail server took it — `sent`, not "delivered", since a later bounce is not knowable at that moment.++- Add `mail.inbox-answering@1`, the switch behind all of it: off by default, per agent, with when the person last set it.++- Add the capabilities `mail.agent.read`, `mail.agent.reply` and `mail.agent.answering`. The first two are loopback-only and first-party: only a token that names the person (`on_behalf_of`) and the agent's own inbox reads a letter or sends a reply, and only OpenVibe.Actor is granted them. The third is the person's own switch, under the `mail.addresses.write` a caller already holds. The `mail` service manifest lists all three and now produces `mail.agent_inbox.received`.++- Additive only: five new contracts, three new capabilities and one manifest field; nothing that exists today changes shape.++## 0.341.0 — 2026-11-08- The actor capabilities name the canvas routes (plan HO9): `GET /api/v1/me/canvases` and `GET /api/v1/me/canvases/:id` under `actor.task.read`, and `POST /api/v1/me/canvases/:id/events` under `actor.task.create`. The documents are `actor.canvas@1` (0.340.0); a button's label starts a normal turn as the person, and a checklist tick flips the item and is told to the next turn. No schema changed.@@@ -69,7 +78,6 @@A first-party service opens a batch on the network's own account with `ai.batches.create`; a person or a developer apppays with its own account.--## 0.335.0 — 2026-11-07- Add `actor.voice@1`: an agent's voice as a file, and nothing else. The document carries the agent's name, a short bio, its instructions (the house voice it speaks in), its rules, its default approval level (`ask`, `auto-edits`, `approve-for-me`, `full` — the levels of `actor.agent@1`), the model it prefers and the connected apps it may use (ids only, never a key), an optional face (an avatar ref), an optional author and a `created_at`. It never carries memory, a connector's token or a file.@@@ -2,7 +2,7 @@> Machine-readable contracts for the whole OpenVibe network.--**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.317.0: 1061 schemas in `contracts/catalog.json`, 60 service manifests, 479 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).++**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.342.0: 1102 schemas in `contracts/catalog.json`, 61 service manifests, 494 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).**License:** AGPL-3.0 (same as every OpenVibe service).@@@ -46,7 +46,8 @@"the Workshop v1 (ADR-054 section 6): Workshop kinds, network.badge, staff review (inventory.review-request@1, inventory.definition.review active) and media_id on equipped slots","News, Reviews, Trade, Coupons and OpenRestream go live on their own domains (plan T11); the product at openre.stream is OpenRestream, with OpenVibe Live on by default (live.openre.slot.bind)","ADR-055 (proposed): money and the inventory \u2014 primary sales first, gifting next; trading and a market stay closed, and chance is never paid for",-- "bench.benchmark@1 and bench.run@1 with the capabilities bench.benchmark.write, bench.run.publish and bench.run.read: the benchmark registry and the results API (spec 2026-10-30, stage B1)"++ "bench.benchmark@1 and bench.run@1 with the capabilities bench.benchmark.write, bench.run.publish and bench.run.read: the benchmark registry and the results API (spec 2026-10-30, stage B1)",++ "mail.agent_inbox.received@1, mail.agent-inbox-message@1, mail.agent-reply-request@1, mail.agent-reply-result@1 and mail.inbox-answering@1, with the capabilities mail.agent.read, mail.agent.reply and mail.agent.answering (track HO6): an agent answers the mail sent to its own OpenVibe.Mail address, reads it in full text on the owner's behalf, replies from its own address in the thread, and answers only when the person's switch for that address is on"],-- "updated": "2026-10-30"++ "updated": "2026-11-07"}@@@ -10124,6 +10124,51 @@"visibility": "public","compatibility": "backward","status": "active"++ },++ {++ "id": "mail.agent_inbox.received",++ "version": "1.0.0",++ "owner": "mail",++ "schema": "events/payloads/mail.agent_inbox.received.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "mail.agent-inbox-message",++ "version": "1.0.0",++ "owner": "mail",++ "schema": "mail/agent-inbox-message.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "mail.agent-reply-request",++ "version": "1.0.0",++ "owner": "mail",++ "schema": "mail/agent-reply-request.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "mail.agent-reply-result",++ "version": "1.0.0",++ "owner": "mail",++ "schema": "mail/agent-reply-result.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "mail.inbox-answering",++ "version": "1.0.0",++ "owner": "mail",++ "schema": "mail/inbox-answering.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"}]}nnew file mode 100644@@@ -0,0 +1,60 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/mail.agent_inbox.received.v1.json",++ "title": "MailAgentInboxReceivedPayload",++ "description": "mail.agent_inbox.received v1 (OpenVibe.Mail server/jobs/agent-mail.js). A message arrived at an agent's own address and the person has switched that address's answering on, so their agent may read it and answer. The payload carries enough for the agent's system to decide, and to show the person what arrived: the inbox and the agent it belongs to, the owner's subject, the mail server's message id, the sender, the subject and a plain-text EXCERPT of at most 4000 characters. It never carries the attachments, the HTML, or the whole body: the agent's system reads the whole text through mail.agent.read, on the owner's behalf, and only once it has decided to answer. Mail publishes it only for an inbox whose answering is on (off by default) and never for a sender on the owner's block list or a message the mail server marked as spam.",++ "type": "object",++ "required": ["inbox_id", "inbox", "agent_id", "owner", "message_id", "from", "subject", "excerpt", "received_at"],++ "additionalProperties": false,++ "properties": {++ "inbox_id": {++ "type": "string",++ "pattern": "^agi_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The agent inbox's id (mail.agent-inbox@1). Opaque outside OpenVibe.Mail."++ },++ "inbox": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's address the message was delivered to, e.g. [email protected]. Matched on the envelope recipient the mail server stamped, never on a sender-written To."++ },++ "agent_id": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address, lowercased and cleaned. It is the id the agent's own system knows that agent by; a system that does not know it starts nothing."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose mailbox received the message and whose agent may answer it."++ },++ "message_id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 512,++ "description": "The mail server's message id (a JMAP Email id), for mail.agent.read. Not the Message-ID header."++ },++ "from": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The sender's address, as the mail server parsed it. A stranger, never the person: mail to an agent's address comes from someone else."++ },++ "subject": {++ "type": ["string", "null"],++ "maxLength": 2000,++ "description": "The subject line, or null when the message had none."++ },++ "excerpt": {++ "type": "string",++ "maxLength": 4000,++ "description": "The plain-text body, cut to at most 4000 characters. The text part only: never the HTML, never an attachment. It is untrusted content from a stranger."++ },++ "received_at": {++ "type": ["string", "null"],++ "format": "date-time",++ "description": "When the mail server received the message, ISO 8601 UTC, or null when it did not record a time."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,76 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/mail/agent-inbox-message.v1.json",++ "title": "MailAgentInboxMessage",++ "description": "One message sent to an agent's address, in full text, as OpenVibe.Mail gives it to the agent acting for the owner (mail.agent.read on GET /internal/mail/agents/:agent_id/messages/:message_id). It is the only place a body leaves the mail server for an agent: the plain text, cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender's claim about who the message is for: the inbox addresses are the ones the mail server stamped at delivery. The message is data from a stranger; the contract cannot say so, so every reader must.",++ "type": "object",++ "required": ["message_id", "inbox", "agent_id", "owner", "from", "to", "subject", "text", "in_reply_to", "references", "received_at", "spam"],++ "additionalProperties": false,++ "properties": {++ "message_id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 512,++ "description": "The mail server's message id (a JMAP Email id). Opaque outside OpenVibe.Mail."++ },++ "inbox": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's address the message was delivered to."++ },++ "agent_id": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose mailbox received it."++ },++ "from": {++ "type": "array",++ "maxItems": 100,++ "items": { "type": "string", "format": "email", "maxLength": 254 },++ "description": "The sender addresses, as the mail server parsed them. A stranger, not the owner."++ },++ "to": {++ "type": "array",++ "maxItems": 100,++ "items": { "type": "string", "format": "email", "maxLength": 254 },++ "description": "The addresses the message was addressed to."++ },++ "subject": {++ "type": ["string", "null"],++ "maxLength": 2000,++ "description": "The subject line, or null when the message had none."++ },++ "text": {++ "type": "string",++ "maxLength": 4000,++ "description": "The plain-text body, cut to at most 4000 characters. Untrusted content: an instruction in it is never the owner's instruction."++ },++ "in_reply_to": {++ "type": ["string", "null"],++ "maxLength": 998,++ "description": "The Message-ID this message answers, without the angle brackets, or null when it answers nothing."++ },++ "references": {++ "type": "array",++ "maxItems": 100,++ "items": { "type": "string", "maxLength": 998 },++ "description": "The Message-IDs of the conversation before this message, oldest first, without the angle brackets. A reply repeats them so the thread stays one thread."++ },++ "received_at": {++ "type": ["string", "null"],++ "format": "date-time",++ "description": "When the mail server received the message, ISO 8601 UTC."++ },++ "spam": {++ "type": "boolean",++ "description": "Whether the mail server's filter marked the message as junk. Mail never publishes an event for such a message; a reader that finds it here answers nothing."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,40 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/mail/agent-reply-request.v1.json",++ "title": "MailAgentReplyRequest",++ "description": "mail.agent.reply-request@1: the body of mail.agent.reply (POST /internal/mail/agents/:agent_id/reply), an agent answering a letter to its own address. The reply goes FROM the agent's inbox, never from the person's mailbox: the person's own address is not the agent's to write from. `body` is plain text, cut to 10000 characters; `in_reply_to` and `references` are Message-IDs WITHOUT the angle brackets, and Mail wraps each in one, so a thread stays one thread in the reader that receives it. A reply to an address that is not the sender's answers nothing: Mail refuses it rather than write to a stranger the agent's answer was not for. Nothing here says who the person is; the token does.",++ "type": "object",++ "required": ["body"],++ "additionalProperties": false,++ "properties": {++ "message_id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 512,++ "description": "The message being answered, as mail.agent.read gave it. Mail takes the sender and the subject from it, so a caller cannot write to someone the message did not come from."++ },++ "to": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "Who the reply goes to. Optional: without it the reply goes to the sender of message_id. When both are given they must be the same address."++ },++ "body": {++ "type": "string",++ "minLength": 1,++ "maxLength": 10000,++ "description": "The reply, as plain text. Mail builds the message from it and sends no HTML."++ },++ "in_reply_to": {++ "type": ["string", "null"],++ "maxLength": 998,++ "description": "The Message-ID this reply answers, without angle brackets. Mail wraps it: In-Reply-To: <…>."++ },++ "references": {++ "type": "array",++ "maxItems": 100,++ "items": { "type": "string", "maxLength": 998 },++ "description": "The Message-IDs of the conversation, oldest first, without angle brackets. Mail wraps each: References: <…> <…>."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,30 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/mail/agent-reply-result.v1.json",++ "title": "MailAgentReplyResult",++ "description": "mail.agent.reply-result@1: what mail.agent.reply answers once the mail server took the message. `sent` is false when the mail server refused it (the answer's `reason` says why in plain words) and true when it accepted it — a relay's later bounce is not knowable here and is not claimed. `message_id` is the mail server's id for the sent message when it answers with one; `rfc_message_id` is the Message-ID header the reply carries, which a later letter in the thread will name in its In-Reply-To.",++ "type": "object",++ "required": ["sent"],++ "additionalProperties": false,++ "properties": {++ "sent": {++ "type": "boolean",++ "description": "True when the mail server accepted the reply, false when it did not."++ },++ "message_id": {++ "type": ["string", "null"],++ "maxLength": 512,++ "description": "The mail server's id for the sent message."++ },++ "rfc_message_id": {++ "type": ["string", "null"],++ "maxLength": 998,++ "description": "The Message-ID header of the reply, without angle brackets."++ },++ "reason": {++ "type": ["string", "null"],++ "maxLength": 300,++ "description": "Why the reply was not sent, in plain words. Null when sent is true."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,37 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/mail/inbox-answering.v1.json",++ "title": "MailInboxAnswering",++ "description": "mail.inbox-answering@1: whether a person's agent answers the mail sent to its address, as OpenVibe.Mail keeps the switch. It is OFF by default and per agent: an address that exists is not an invitation to answer, and a person turns it on for the agent they trust to. `enabled` is the whole answer; `changed_at` says when the person last set it, so a page can say how long it has been on. Turning it off stops the next message from being published to the agent's system and takes its address out of the answering path; it never deletes what already happened.",++ "type": "object",++ "required": ["agent_id", "address", "owner", "enabled", "changed_at"],++ "additionalProperties": false,++ "properties": {++ "agent_id": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address."++ },++ "address": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's inbox address."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose switch it is."++ },++ "enabled": {++ "type": "boolean",++ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."++ },++ "changed_at": {++ "type": ["string", "null"],++ "format": "date-time",++ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."++ }++ }++}nnew file mode 100644@@@ -0,0 +1 @@++{"message_id": "m-4715", "inbox": "[email protected]", "agent_id": "helper", "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS", "from": ["[email protected]"], "to": ["[email protected]"], "subject": "Too long", "text": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "in_reply_to": null, "references": [], "received_at": "2026-11-07T12:00:00Z", "spam": false}nnew file mode 100644@@@ -0,0 +1,16 @@++{++ "message_id": "m-4714",++ "inbox": "[email protected]",++ "agent_id": "helper",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "from": ["[email protected]"],++ "to": ["[email protected]"],++ "subject": "A big one",++ "text": "the body",++ "in_reply_to": null,++ "references": [],++ "received_at": "2026-11-07T12:00:00Z",++ "spam": false,++ "html": "<p>the body</p>",++ "attachments": [{ "name": "a.pdf" }]++}nnew file mode 100644@@@ -0,0 +1,14 @@++{++ "message_id": "m-4711",++ "inbox": "[email protected]",++ "agent_id": "helper",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "from": ["[email protected]"],++ "to": ["[email protected]"],++ "subject": "Could you check Tuesday?",++ "text": "Hi — are we still on for Tuesday at 10? I can move it if that is easier.\n\nThanks,\nDana",++ "in_reply_to": null,++ "references": [],++ "received_at": "2026-11-07T12:00:00Z",++ "spam": false++}nnew file mode 100644@@@ -0,0 +1,14 @@++{++ "message_id": "m-4713",++ "inbox": "[email protected]",++ "agent_id": "helper",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "from": ["[email protected]"],++ "to": ["[email protected]"],++ "subject": "Re: Could you check Tuesday?",++ "text": "Tuesday at 10 works, thanks for checking back.",++ "in_reply_to": "[email protected]",++ "references": ["[email protected]", "[email protected]"],++ "received_at": "2026-11-07T15:30:00Z",++ "spam": false++}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "message_id": "m-4711",++ "body": "An answer sent from the person's own mailbox, which is not the agent's to write from.",++ "from": "[email protected]",++ "html": "<p>An answer</p>"++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "message_id": "m-4711",++ "to": "[email protected]",++ "body": ""++}nnew file mode 100644@@@ -0,0 +1,5 @@++{++ "message_id": "m-4711",++ "body": "At most 10000 characters, said the contract.",++ "attachments": [{ "name": "a.pdf", "blob": "AAA" }]++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "message_id": "m-4711",++ "to": "[email protected]",++ "body": "Tuesday at 10 is still good. See you then.\n\n— Helper, answering for Alice",++ "in_reply_to": "[email protected]",++ "references": ["[email protected]"]++}nnew file mode 100644@@@ -0,0 +1,4 @@++{++ "message_id": "m-4711",++ "body": "Thanks, noted."++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "sent": true,++ "message_id": "m-4720",++ "rfc_message_id": "[email protected]",++ "reason": null,++ "bounced_at": "2026-11-07T13:00:00Z",++ "delivered": true++}nnew file mode 100644@@@ -0,0 +1,4 @@++{++ "delivered": true,++ "message_id": "m-4720"++}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "sent": false,++ "message_id": null,++ "rfc_message_id": null,++ "reason": "The mail server refused the message: the recipient does not exist."++}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "sent": true,++ "message_id": "m-4720",++ "rfc_message_id": "[email protected]",++ "reason": null++}nnew file mode 100644@@@ -0,0 +1,10 @@++{++ "inbox_id": "agi_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "inbox": "[email protected]",++ "agent_id": "helper",++ "message_id": "m-4711",++ "from": "[email protected]",++ "subject": "Could you check Tuesday?",++ "excerpt": "Hi — are we still on for Tuesday at 10?",++ "received_at": "2026-11-07T12:00:00Z"++}nnew file mode 100644@@@ -0,0 +1,13 @@++{++ "inbox_id": "agi_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "inbox": "[email protected]",++ "agent_id": "helper",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "message_id": "m-4711",++ "from": "[email protected]",++ "subject": "Could you check Tuesday?",++ "excerpt": "Hi — are we still on for Tuesday at 10?",++ "received_at": "2026-11-07T12:00:00Z",++ "html": "<p>Hi</p>",++ "attachments": [{ "name": "invoice.pdf", "type": "application/pdf", "size": 9001 }]++}nnew file mode 100644@@@ -0,0 +1,11 @@++{++ "inbox_id": "agi_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "inbox": "[email protected]",++ "agent_id": "helper",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "message_id": "m-4712",++ "from": "[email protected]",++ "subject": null,++ "excerpt": "",++ "received_at": null++}nnew file mode 100644@@@ -0,0 +1,11 @@++{++ "inbox_id": "agi_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "inbox": "[email protected]",++ "agent_id": "helper",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "message_id": "m-4711",++ "from": "[email protected]",++ "subject": "Could you check Tuesday?",++ "excerpt": "Hi — are we still on for Tuesday at 10? I can move it if that is easier.\n\nThanks,\nDana",++ "received_at": "2026-11-07T12:00:00Z"++}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "agent_id": "helper",++ "address": "[email protected]",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "enabled": true++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "agent_id": "helper",++ "address": "[email protected]",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "enabled": false,++ "changed_at": null++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "agent_id": "helper",++ "address": "[email protected]",++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",++ "enabled": true,++ "changed_at": "2026-11-07T12:00:00Z"++}@@@ -111627,6 +111627,351 @@}}}++ },++ "mail.agent_inbox.received": {++ "version": "1.0.0",++ "owner": "mail",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/events/payloads/mail.agent_inbox.received.v1.json",++ "title": "MailAgentInboxReceivedPayload",++ "description": "mail.agent_inbox.received v1 (OpenVibe.Mail server/jobs/agent-mail.js). A message arrived at an agent's own address and the person has switched that address's answering on, so their agent may read it and answer. The payload carries enough for the agent's system to decide, and to show the person what arrived: the inbox and the agent it belongs to, the owner's subject, the mail server's message id, the sender, the subject and a plain-text EXCERPT of at most 4000 characters. It never carries the attachments, the HTML, or the whole body: the agent's system reads the whole text through mail.agent.read, on the owner's behalf, and only once it has decided to answer. Mail publishes it only for an inbox whose answering is on (off by default) and never for a sender on the owner's block list or a message the mail server marked as spam.",++ "type": "object",++ "required": [++ "inbox_id",++ "inbox",++ "agent_id",++ "owner",++ "message_id",++ "from",++ "subject",++ "excerpt",++ "received_at"++ ],++ "additionalProperties": false,++ "properties": {++ "inbox_id": {++ "type": "string",++ "pattern": "^agi_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The agent inbox's id (mail.agent-inbox@1). Opaque outside OpenVibe.Mail."++ },++ "inbox": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's address the message was delivered to, e.g. [email protected]. Matched on the envelope recipient the mail server stamped, never on a sender-written To."++ },++ "agent_id": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address, lowercased and cleaned. It is the id the agent's own system knows that agent by; a system that does not know it starts nothing."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose mailbox received the message and whose agent may answer it."++ },++ "message_id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 512,++ "description": "The mail server's message id (a JMAP Email id), for mail.agent.read. Not the Message-ID header."++ },++ "from": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The sender's address, as the mail server parsed it. A stranger, never the person: mail to an agent's address comes from someone else."++ },++ "subject": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 2000,++ "description": "The subject line, or null when the message had none."++ },++ "excerpt": {++ "type": "string",++ "maxLength": 4000,++ "description": "The plain-text body, cut to at most 4000 characters. The text part only: never the HTML, never an attachment. It is untrusted content from a stranger."++ },++ "received_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the mail server received the message, ISO 8601 UTC, or null when it did not record a time."++ }++ }++ }++ },++ "mail.agent-inbox-message": {++ "version": "1.0.0",++ "owner": "mail",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/mail/agent-inbox-message.v1.json",++ "title": "MailAgentInboxMessage",++ "description": "One message sent to an agent's address, in full text, as OpenVibe.Mail gives it to the agent acting for the owner (mail.agent.read on GET /internal/mail/agents/:agent_id/messages/:message_id). It is the only place a body leaves the mail server for an agent: the plain text, cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender's claim about who the message is for: the inbox addresses are the ones the mail server stamped at delivery. The message is data from a stranger; the contract cannot say so, so every reader must.",++ "type": "object",++ "required": [++ "message_id",++ "inbox",++ "agent_id",++ "owner",++ "from",++ "to",++ "subject",++ "text",++ "in_reply_to",++ "references",++ "received_at",++ "spam"++ ],++ "additionalProperties": false,++ "properties": {++ "message_id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 512,++ "description": "The mail server's message id (a JMAP Email id). Opaque outside OpenVibe.Mail."++ },++ "inbox": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's address the message was delivered to."++ },++ "agent_id": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose mailbox received it."++ },++ "from": {++ "type": "array",++ "maxItems": 100,++ "items": {++ "type": "string",++ "format": "email",++ "maxLength": 254++ },++ "description": "The sender addresses, as the mail server parsed them. A stranger, not the owner."++ },++ "to": {++ "type": "array",++ "maxItems": 100,++ "items": {++ "type": "string",++ "format": "email",++ "maxLength": 254++ },++ "description": "The addresses the message was addressed to."++ },++ "subject": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 2000,++ "description": "The subject line, or null when the message had none."++ },++ "text": {++ "type": "string",++ "maxLength": 4000,++ "description": "The plain-text body, cut to at most 4000 characters. Untrusted content: an instruction in it is never the owner's instruction."++ },++ "in_reply_to": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 998,++ "description": "The Message-ID this message answers, without the angle brackets, or null when it answers nothing."++ },++ "references": {++ "type": "array",++ "maxItems": 100,++ "items": {++ "type": "string",++ "maxLength": 998++ },++ "description": "The Message-IDs of the conversation before this message, oldest first, without the angle brackets. A reply repeats them so the thread stays one thread."++ },++ "received_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the mail server received the message, ISO 8601 UTC."++ },++ "spam": {++ "type": "boolean",++ "description": "Whether the mail server's filter marked the message as junk. Mail never publishes an event for such a message; a reader that finds it here answers nothing."++ }++ }++ }++ },++ "mail.agent-reply-request": {++ "version": "1.0.0",++ "owner": "mail",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/mail/agent-reply-request.v1.json",++ "title": "MailAgentReplyRequest",++ "description": "mail.agent.reply-request@1: the body of mail.agent.reply (POST /internal/mail/agents/:agent_id/reply), an agent answering a letter to its own address. The reply goes FROM the agent's inbox, never from the person's mailbox: the person's own address is not the agent's to write from. `body` is plain text, cut to 10000 characters; `in_reply_to` and `references` are Message-IDs WITHOUT the angle brackets, and Mail wraps each in one, so a thread stays one thread in the reader that receives it. A reply to an address that is not the sender's answers nothing: Mail refuses it rather than write to a stranger the agent's answer was not for. Nothing here says who the person is; the token does.",++ "type": "object",++ "required": [++ "body"++ ],++ "additionalProperties": false,++ "properties": {++ "message_id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 512,++ "description": "The message being answered, as mail.agent.read gave it. Mail takes the sender and the subject from it, so a caller cannot write to someone the message did not come from."++ },++ "to": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "Who the reply goes to. Optional: without it the reply goes to the sender of message_id. When both are given they must be the same address."++ },++ "body": {++ "type": "string",++ "minLength": 1,++ "maxLength": 10000,++ "description": "The reply, as plain text. Mail builds the message from it and sends no HTML."++ },++ "in_reply_to": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 998,++ "description": "The Message-ID this reply answers, without angle brackets. Mail wraps it: In-Reply-To: <…>."++ },++ "references": {++ "type": "array",++ "maxItems": 100,++ "items": {++ "type": "string",++ "maxLength": 998++ },++ "description": "The Message-IDs of the conversation, oldest first, without angle brackets. Mail wraps each: References: <…> <…>."++ }++ }++ }++ },++ "mail.agent-reply-result": {++ "version": "1.0.0",++ "owner": "mail",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/mail/agent-reply-result.v1.json",++ "title": "MailAgentReplyResult",++ "description": "mail.agent.reply-result@1: what mail.agent.reply answers once the mail server took the message. `sent` is false when the mail server refused it (the answer's `reason` says why in plain words) and true when it accepted it — a relay's later bounce is not knowable here and is not claimed. `message_id` is the mail server's id for the sent message when it answers with one; `rfc_message_id` is the Message-ID header the reply carries, which a later letter in the thread will name in its In-Reply-To.",++ "type": "object",++ "required": [++ "sent"++ ],++ "additionalProperties": false,++ "properties": {++ "sent": {++ "type": "boolean",++ "description": "True when the mail server accepted the reply, false when it did not."++ },++ "message_id": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 512,++ "description": "The mail server's id for the sent message."++ },++ "rfc_message_id": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 998,++ "description": "The Message-ID header of the reply, without angle brackets."++ },++ "reason": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 300,++ "description": "Why the reply was not sent, in plain words. Null when sent is true."++ }++ }++ }++ },++ "mail.inbox-answering": {++ "version": "1.0.0",++ "owner": "mail",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/mail/inbox-answering.v1.json",++ "title": "MailInboxAnswering",++ "description": "mail.inbox-answering@1: whether a person's agent answers the mail sent to its address, as OpenVibe.Mail keeps the switch. It is OFF by default and per agent: an address that exists is not an invitation to answer, and a person turns it on for the agent they trust to. `enabled` is the whole answer; `changed_at` says when the person last set it, so a page can say how long it has been on. Turning it off stops the next message from being published to the agent's system and takes its address out of the answering path; it never deletes what already happened.",++ "type": "object",++ "required": [++ "agent_id",++ "address",++ "owner",++ "enabled",++ "changed_at"++ ],++ "additionalProperties": false,++ "properties": {++ "agent_id": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address."++ },++ "address": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's inbox address."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose switch it is."++ },++ "enabled": {++ "type": "boolean",++ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."++ },++ "changed_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."++ }++ }++ }}}}@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Actor API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.AI API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Bench API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Billing API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Blog API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Bot API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Chat API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Codes API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Community API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe Connect API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Coupons API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Deals API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Design API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Domains API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Events API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Food API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Games API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Host API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -145,8 +145,8 @@"service": "mail","name": "OpenVibe.Mail","origin": "https://openvibe.email",-- "operations": 12,-- "capabilities": 2++ "operations": 16,++ "capabilities": 5},{"service": "media",@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Inventory API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Live API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Mail API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -92,6 +92,188 @@}}},++ "/api/v1/agent-inboxes/{id}/answering": {++ "get": {++ "operationId": "get_api_v1_agent_inboxes_id_answering",++ "summary": "Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1.",++ "description": "**mail.agent.answering** (first-party): Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1. It is OFF by default and per agent; turning it on is what makes Mail publish mail.agent_inbox.received for that address at all. The caller must act for the person (on_behalf_of), and another person's inbox is the same 404 as one that does not exist. Mail still publishes nothing for a sender on the person's block list or for a message the mail server marked as spam.",++ "tags": [++ "mail.agent"++ ],++ "x-openvibe-capabilities": [++ "mail.agent.answering"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "mail-addresses-write",++ "security": [++ {++ "openvibeToken": [++ "mail.agent.answering"++ ]++ }++ ],++ "x-openvibe-input": {++ "$ref": "#/components/schemas/mail.inbox-answering.v1"++ },++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ },++ {++ "name": "agent_id",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address."++ },++ "description": "The agent's name in the address."++ },++ {++ "name": "address",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's inbox address."++ },++ "description": "The agent's inbox address."++ },++ {++ "name": "owner",++ "in": "query",++ "required": true,++ "schema": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose switch it is."++ },++ "description": "The Network subject of the person whose switch it is."++ },++ {++ "name": "enabled",++ "in": "query",++ "required": true,++ "schema": {++ "type": "boolean",++ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."++ },++ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."++ },++ {++ "name": "changed_at",++ "in": "query",++ "required": true,++ "schema": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."++ },++ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/mail.inbox-answering.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ },++ "put": {++ "operationId": "put_api_v1_agent_inboxes_id_answering",++ "summary": "Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1.",++ "description": "**mail.agent.answering** (first-party): Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1. It is OFF by default and per agent; turning it on is what makes Mail publish mail.agent_inbox.received for that address at all. The caller must act for the person (on_behalf_of), and another person's inbox is the same 404 as one that does not exist. Mail still publishes nothing for a sender on the person's block list or for a message the mail server marked as spam.",++ "tags": [++ "mail.agent"++ ],++ "x-openvibe-capabilities": [++ "mail.agent.answering"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "mail-addresses-write",++ "security": [++ {++ "openvibeToken": [++ "mail.agent.answering"++ ]++ }++ ],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/mail.inbox-answering.v1"++ }++ }++ }++ },++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/mail.inbox-answering.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },"/api/v1/agent-inboxes/{id}/messages": {"get": {"operationId": "get_api_v1_agent_inboxes_id_messages",@@@ -537,6 +719,136 @@}}}++ },++ "/internal/mail/agents/{agent_id}/messages/{message_id}": {++ "get": {++ "operationId": "get_internal_mail_agents_agent_id_messages_message_id",++ "summary": "Read one message sent to an agent's own address, in full plain text, as that agent acting for the person whose mailbox received it.",++ "description": "**mail.agent.read** (first-party): Read one message sent to an agent's own address, in full plain text, as that agent acting for the person whose mailbox received it. GET /internal/mail/agents/:agent_id/messages/:message_id answers mail.agent-inbox-message@1: the sender, the addresses the mail server stamped at delivery, the subject, the text cut to 4000 characters, and the two threading headers a reply needs. Never the HTML and never an attachment. The token must name the person (on_behalf_of), the agent must be one of that person's inboxes, and the message must have been delivered to that address; anything else is the same 404 as a message that does not exist. Loopback only; granted to OpenVibe.Actor alone, which reads a letter and answers it under the person's approval policy.",++ "tags": [++ "mail.agent"++ ],++ "x-openvibe-capabilities": [++ "mail.agent.read"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "internal-read",++ "security": [++ {++ "openvibeToken": [++ "mail.agent.read"++ ]++ }++ ],++ "parameters": [++ {++ "name": "agent_id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ },++ {++ "name": "message_id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/mail.agent-inbox-message.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/internal/mail/agents/{agent_id}/reply": {++ "post": {++ "operationId": "post_internal_mail_agents_agent_id_reply",++ "summary": "Send a reply FROM an agent's own address, as that agent acting for the person whose mailbox receives its mail.",++ "description": "**mail.agent.reply** (first-party): Send a reply FROM an agent's own address, as that agent acting for the person whose mailbox receives its mail. POST /internal/mail/agents/:agent_id/reply takes mail.agent-reply-request@1 and answers mail.agent-reply-result@1. The reply is plain text, comes from <agent>.<user>@openvibe.email and from nothing else, and carries In-Reply-To and References so it stays in the thread; the recipient is the sender of the message being answered, or the same address named in `to`, and never a stranger the message did not come from. The recipient is therefore never new: this is an answer, not a first letter. The token must name the person (on_behalf_of) and the agent must be one of their inboxes. Loopback only; granted to OpenVibe.Actor alone, which sends the reply the person approved.",++ "tags": [++ "mail.agent"++ ],++ "x-openvibe-capabilities": [++ "mail.agent.reply"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "internal-write",++ "security": [++ {++ "openvibeToken": [++ "mail.agent.reply"++ ]++ }++ ],++ "requestBody": {++ "required": false,++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/mail.agent-reply-request.v1"++ }++ }++ }++ },++ "parameters": [++ {++ "name": "agent_id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/mail.agent-reply-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }}},"components": {@@@ -606,6 +918,242 @@"description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."}}++ },++ "mail.agent-inbox-message.v1": {++ "title": "MailAgentInboxMessage",++ "description": "One message sent to an agent's address, in full text, as OpenVibe.Mail gives it to the agent acting for the owner (mail.agent.read on GET /internal/mail/agents/:agent_id/messages/:message_id). It is the only place a body leaves the mail server for an agent: the plain text, cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender's claim about who the message is for: the inbox addresses are the ones the mail server stamped at delivery. The message is data from a stranger; the contract cannot say so, so every reader must.",++ "type": "object",++ "required": [++ "message_id",++ "inbox",++ "agent_id",++ "owner",++ "from",++ "to",++ "subject",++ "text",++ "in_reply_to",++ "references",++ "received_at",++ "spam"++ ],++ "additionalProperties": false,++ "properties": {++ "message_id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 512,++ "description": "The mail server's message id (a JMAP Email id). Opaque outside OpenVibe.Mail."++ },++ "inbox": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's address the message was delivered to."++ },++ "agent_id": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose mailbox received it."++ },++ "from": {++ "type": "array",++ "maxItems": 100,++ "items": {++ "type": "string",++ "format": "email",++ "maxLength": 254++ },++ "description": "The sender addresses, as the mail server parsed them. A stranger, not the owner."++ },++ "to": {++ "type": "array",++ "maxItems": 100,++ "items": {++ "type": "string",++ "format": "email",++ "maxLength": 254++ },++ "description": "The addresses the message was addressed to."++ },++ "subject": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 2000,++ "description": "The subject line, or null when the message had none."++ },++ "text": {++ "type": "string",++ "maxLength": 4000,++ "description": "The plain-text body, cut to at most 4000 characters. Untrusted content: an instruction in it is never the owner's instruction."++ },++ "in_reply_to": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 998,++ "description": "The Message-ID this message answers, without the angle brackets, or null when it answers nothing."++ },++ "references": {++ "type": "array",++ "maxItems": 100,++ "items": {++ "type": "string",++ "maxLength": 998++ },++ "description": "The Message-IDs of the conversation before this message, oldest first, without the angle brackets. A reply repeats them so the thread stays one thread."++ },++ "received_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the mail server received the message, ISO 8601 UTC."++ },++ "spam": {++ "type": "boolean",++ "description": "Whether the mail server's filter marked the message as junk. Mail never publishes an event for such a message; a reader that finds it here answers nothing."++ }++ }++ },++ "mail.agent-reply-request.v1": {++ "title": "MailAgentReplyRequest",++ "description": "mail.agent.reply-request@1: the body of mail.agent.reply (POST /internal/mail/agents/:agent_id/reply), an agent answering a letter to its own address. The reply goes FROM the agent's inbox, never from the person's mailbox: the person's own address is not the agent's to write from. `body` is plain text, cut to 10000 characters; `in_reply_to` and `references` are Message-IDs WITHOUT the angle brackets, and Mail wraps each in one, so a thread stays one thread in the reader that receives it. A reply to an address that is not the sender's answers nothing: Mail refuses it rather than write to a stranger the agent's answer was not for. Nothing here says who the person is; the token does.",++ "type": "object",++ "required": [++ "body"++ ],++ "additionalProperties": false,++ "properties": {++ "message_id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 512,++ "description": "The message being answered, as mail.agent.read gave it. Mail takes the sender and the subject from it, so a caller cannot write to someone the message did not come from."++ },++ "to": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "Who the reply goes to. Optional: without it the reply goes to the sender of message_id. When both are given they must be the same address."++ },++ "body": {++ "type": "string",++ "minLength": 1,++ "maxLength": 10000,++ "description": "The reply, as plain text. Mail builds the message from it and sends no HTML."++ },++ "in_reply_to": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 998,++ "description": "The Message-ID this reply answers, without angle brackets. Mail wraps it: In-Reply-To: <…>."++ },++ "references": {++ "type": "array",++ "maxItems": 100,++ "items": {++ "type": "string",++ "maxLength": 998++ },++ "description": "The Message-IDs of the conversation, oldest first, without angle brackets. Mail wraps each: References: <…> <…>."++ }++ }++ },++ "mail.agent-reply-result.v1": {++ "title": "MailAgentReplyResult",++ "description": "mail.agent.reply-result@1: what mail.agent.reply answers once the mail server took the message. `sent` is false when the mail server refused it (the answer's `reason` says why in plain words) and true when it accepted it — a relay's later bounce is not knowable here and is not claimed. `message_id` is the mail server's id for the sent message when it answers with one; `rfc_message_id` is the Message-ID header the reply carries, which a later letter in the thread will name in its In-Reply-To.",++ "type": "object",++ "required": [++ "sent"++ ],++ "additionalProperties": false,++ "properties": {++ "sent": {++ "type": "boolean",++ "description": "True when the mail server accepted the reply, false when it did not."++ },++ "message_id": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 512,++ "description": "The mail server's id for the sent message."++ },++ "rfc_message_id": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 998,++ "description": "The Message-ID header of the reply, without angle brackets."++ },++ "reason": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 300,++ "description": "Why the reply was not sent, in plain words. Null when sent is true."++ }++ }++ },++ "mail.inbox-answering.v1": {++ "title": "MailInboxAnswering",++ "description": "mail.inbox-answering@1: whether a person's agent answers the mail sent to its address, as OpenVibe.Mail keeps the switch. It is OFF by default and per agent: an address that exists is not an invitation to answer, and a person turns it on for the agent they trust to. `enabled` is the whole answer; `changed_at` says when the person last set it, so a page can say how long it has been on. Turning it off stops the next message from being published to the agent's system and takes its address out of the answering path; it never deletes what already happened.",++ "type": "object",++ "required": [++ "agent_id",++ "address",++ "owner",++ "enabled",++ "changed_at"++ ],++ "additionalProperties": false,++ "properties": {++ "agent_id": {++ "type": "string",++ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",++ "maxLength": 32,++ "description": "The agent's name in the address."++ },++ "address": {++ "type": "string",++ "format": "email",++ "maxLength": 254,++ "description": "The agent's inbox address."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The Network subject of the person whose switch it is."++ },++ "enabled": {++ "type": "boolean",++ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."++ },++ "changed_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time",++ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."++ }++ }}},"securitySchemes": {@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.MediaHub API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Media API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Network API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.News API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenRestream API",-- "version": "0.341.0",-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Play API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Quest API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Report API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Reviews API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Run API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Search API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Services API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Sources API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Space API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tips API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Today API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tools API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Trade API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.VIP API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Vision API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Watch API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Wiki API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Work API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Zone API",-- "version": "0.341.0",-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.342.0",++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -305906,3 +305906,186 @@ export interface SyncClock {*/seq: number;}++++/** [email protected] (owner: mail) */++/**++ * mail.agent_inbox.received v1 (OpenVibe.Mail server/jobs/agent-mail.js). A message arrived at an agent's own address and the person has switched that address's answering on, so their agent may read it and answer. The payload carries enough for the agent's system to decide, and to show the person what arrived: the inbox and the agent it belongs to, the owner's subject, the mail server's message id, the sender, the subject and a plain-text EXCERPT of at most 4000 characters. It never carries the attachments, the HTML, or the whole body: the agent's system reads the whole text through mail.agent.read, on the owner's behalf, and only once it has decided to answer. Mail publishes it only for an inbox whose answering is on (off by default) and never for a sender on the owner's block list or a message the mail server marked as spam.++ */++export interface MailAgentInboxReceivedPayload {++ /**++ * The agent inbox's id (mail.agent-inbox@1). Opaque outside OpenVibe.Mail.++ */++ inbox_id: string;++ /**++ * The agent's address the message was delivered to, e.g. [email protected]. Matched on the envelope recipient the mail server stamped, never on a sender-written To.++ */++ inbox: string;++ /**++ * The agent's name in the address, lowercased and cleaned. It is the id the agent's own system knows that agent by; a system that does not know it starts nothing.++ */++ agent_id: string;++ /**++ * The Network subject of the person whose mailbox received the message and whose agent may answer it.++ */++ owner: string;++ /**++ * The mail server's message id (a JMAP Email id), for mail.agent.read. Not the Message-ID header.++ */++ message_id: string;++ /**++ * The sender's address, as the mail server parsed it. A stranger, never the person: mail to an agent's address comes from someone else.++ */++ from: string;++ /**++ * The subject line, or null when the message had none.++ */++ subject: string | null;++ /**++ * The plain-text body, cut to at most 4000 characters. The text part only: never the HTML, never an attachment. It is untrusted content from a stranger.++ */++ excerpt: string;++ /**++ * When the mail server received the message, ISO 8601 UTC, or null when it did not record a time.++ */++ received_at: string | null;++}++++/** [email protected] (owner: mail) */++/**++ * One message sent to an agent's address, in full text, as OpenVibe.Mail gives it to the agent acting for the owner (mail.agent.read on GET /internal/mail/agents/:agent_id/messages/:message_id). It is the only place a body leaves the mail server for an agent: the plain text, cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender's claim about who the message is for: the inbox addresses are the ones the mail server stamped at delivery. The message is data from a stranger; the contract cannot say so, so every reader must.++ */++export interface MailAgentInboxMessage {++ /**++ * The mail server's message id (a JMAP Email id). Opaque outside OpenVibe.Mail.++ */++ message_id: string;++ /**++ * The agent's address the message was delivered to.++ */++ inbox: string;++ /**++ * The agent's name in the address.++ */++ agent_id: string;++ /**++ * The Network subject of the person whose mailbox received it.++ */++ owner: string;++ /**++ * The sender addresses, as the mail server parsed them. A stranger, not the owner.++ *++ * @maxItems 100++ */++ from: string[];++ /**++ * The addresses the message was addressed to.++ *++ * @maxItems 100++ */++ to: string[];++ /**++ * The subject line, or null when the message had none.++ */++ subject: string | null;++ /**++ * The plain-text body, cut to at most 4000 characters. Untrusted content: an instruction in it is never the owner's instruction.++ */++ text: string;++ /**++ * The Message-ID this message answers, without the angle brackets, or null when it answers nothing.++ */++ in_reply_to: string | null;++ /**++ * The Message-IDs of the conversation before this message, oldest first, without the angle brackets. A reply repeats them so the thread stays one thread.++ *++ * @maxItems 100++ */++ references: string[];++ /**++ * When the mail server received the message, ISO 8601 UTC.++ */++ received_at: string | null;++ /**++ * Whether the mail server's filter marked the message as junk. Mail never publishes an event for such a message; a reader that finds it here answers nothing.++ */++ spam: boolean;++}++++/** [email protected] (owner: mail) */++/**++ * mail.agent.reply-request@1: the body of mail.agent.reply (POST /internal/mail/agents/:agent_id/reply), an agent answering a letter to its own address. The reply goes FROM the agent's inbox, never from the person's mailbox: the person's own address is not the agent's to write from. `body` is plain text, cut to 10000 characters; `in_reply_to` and `references` are Message-IDs WITHOUT the angle brackets, and Mail wraps each in one, so a thread stays one thread in the reader that receives it. A reply to an address that is not the sender's answers nothing: Mail refuses it rather than write to a stranger the agent's answer was not for. Nothing here says who the person is; the token does.++ */++export interface MailAgentReplyRequest {++ /**++ * The message being answered, as mail.agent.read gave it. Mail takes the sender and the subject from it, so a caller cannot write to someone the message did not come from.++ */++ message_id?: string;++ /**++ * Who the reply goes to. Optional: without it the reply goes to the sender of message_id. When both are given they must be the same address.++ */++ to?: string;++ /**++ * The reply, as plain text. Mail builds the message from it and sends no HTML.++ */++ body: string;++ /**++ * The Message-ID this reply answers, without angle brackets. Mail wraps it: In-Reply-To: <…>.++ */++ in_reply_to?: string | null;++ /**++ * The Message-IDs of the conversation, oldest first, without angle brackets. Mail wraps each: References: <…> <…>.++ *++ * @maxItems 100++ */++ references?: string[];++}++++/** [email protected] (owner: mail) */++/**++ * mail.agent.reply-result@1: what mail.agent.reply answers once the mail server took the message. `sent` is false when the mail server refused it (the answer's `reason` says why in plain words) and true when it accepted it — a relay's later bounce is not knowable here and is not claimed. `message_id` is the mail server's id for the sent message when it answers with one; `rfc_message_id` is the Message-ID header the reply carries, which a later letter in the thread will name in its In-Reply-To.++ */++export interface MailAgentReplyResult {++ /**++ * True when the mail server accepted the reply, false when it did not.++ */++ sent: boolean;++ /**++ * The mail server's id for the sent message.++ */++ message_id?: string | null;++ /**++ * The Message-ID header of the reply, without angle brackets.++ */++ rfc_message_id?: string | null;++ /**++ * Why the reply was not sent, in plain words. Null when sent is true.++ */++ reason?: string | null;++}++++/** [email protected] (owner: mail) */++/**++ * mail.inbox-answering@1: whether a person's agent answers the mail sent to its address, as OpenVibe.Mail keeps the switch. It is OFF by default and per agent: an address that exists is not an invitation to answer, and a person turns it on for the agent they trust to. `enabled` is the whole answer; `changed_at` says when the person last set it, so a page can say how long it has been on. Turning it off stops the next message from being published to the agent's system and takes its address out of the answering path; it never deletes what already happened.++ */++export interface MailInboxAnswering {++ /**++ * The agent's name in the address.++ */++ agent_id: string;++ /**++ * The agent's inbox address.++ */++ address: string;++ /**++ * The Network subject of the person whose switch it is.++ */++ owner: string;++ /**++ * True when the agent answers the mail sent to this address. Off unless the person turned it on.++ */++ enabled: boolean;++ /**++ * When the person last turned it on or off; null when they never have (it has been off since the address was made).++ */++ changed_at: string | null;++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "id": "mail.agent.answering",++ "version": "1.0",++ "owner": "mail",++ "status": "active",++ "visibility": "first-party",++ "sensitive": true,++ "description": "Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1. It is OFF by default and per agent; turning it on is what makes Mail publish mail.agent_inbox.received for that address at all. The caller must act for the person (on_behalf_of), and another person's inbox is the same 404 as one that does not exist. Mail still publishes nothing for a sender on the person's block list or for a message the mail server marked as spam.",++ "permissions": [++ "mail:addresses:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "mail-addresses-write",++ "events": [],++ "implementedBy": [++ "GET /api/v1/agent-inboxes/:id/answering",++ "PUT /api/v1/agent-inboxes/:id/answering"++ ],++ "inputSchema": "mail.inbox-answering@1",++ "outputSchema": "mail.inbox-answering@1"++}nnew file mode 100644@@@ -0,0 +1,24 @@++{++ "id": "mail.agent.read",++ "version": "1.0",++ "owner": "mail",++ "status": "active",++ "visibility": "first-party",++ "sensitive": true,++ "description": "Read one message sent to an agent's own address, in full plain text, as that agent acting for the person whose mailbox received it. GET /internal/mail/agents/:agent_id/messages/:message_id answers mail.agent-inbox-message@1: the sender, the addresses the mail server stamped at delivery, the subject, the text cut to 4000 characters, and the two threading headers a reply needs. Never the HTML and never an attachment. The token must name the person (on_behalf_of), the agent must be one of that person's inboxes, and the message must have been delivered to that address; anything else is the same 404 as a message that does not exist. Loopback only; granted to OpenVibe.Actor alone, which reads a letter and answers it under the person's approval policy.",++ "permissions": [++ "mail:messages:read"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "internal-read",++ "events": [++ "mail.agent_inbox.received"++ ],++ "implementedBy": [++ "GET /internal/mail/agents/:agent_id/messages/:message_id"++ ],++ "inputSchema": "common.no-body@1",++ "outputSchema": "mail.agent-inbox-message@1"++}nnew file mode 100644@@@ -0,0 +1,22 @@++{++ "id": "mail.agent.reply",++ "version": "1.0",++ "owner": "mail",++ "status": "active",++ "visibility": "first-party",++ "sensitive": true,++ "description": "Send a reply FROM an agent's own address, as that agent acting for the person whose mailbox receives its mail. POST /internal/mail/agents/:agent_id/reply takes mail.agent-reply-request@1 and answers mail.agent-reply-result@1. The reply is plain text, comes from <agent>.<user>@openvibe.email and from nothing else, and carries In-Reply-To and References so it stays in the thread; the recipient is the sender of the message being answered, or the same address named in `to`, and never a stranger the message did not come from. The recipient is therefore never new: this is an answer, not a first letter. The token must name the person (on_behalf_of) and the agent must be one of their inboxes. Loopback only; granted to OpenVibe.Actor alone, which sends the reply the person approved.",++ "permissions": [++ "mail:messages:send"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "internal-write",++ "events": [],++ "implementedBy": [++ "POST /internal/mail/agents/:agent_id/reply"++ ],++ "inputSchema": "mail.agent-reply-request@1",++ "outputSchema": "mail.agent-reply-result@1"++}@@@ -18,9 +18,14 @@},"capabilities": ["mail.addresses.write",-- "mail.messages.read"++ "mail.messages.read",++ "mail.agent.read",++ "mail.agent.reply",++ "mail.agent.answering"++ ],++ "eventsProduced": [++ "mail.agent_inbox.received"],-- "eventsProduced": [],"eventsConsumed": [],"namespacesOwned": [],"lifecycle": {@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.341.0",++ "version": "0.336.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.341.0",++ "version": "0.336.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.341.0",++ "version": "0.342.0","description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.","main": "index.js","types": "generated/typescript/index.d.ts",
@@ -1,5 +1,14 @@
@@ -1,5 +1,14 @@
# Changelog
# Changelog
+## 0.342.0 — 2026-11-07
+
+- Add `mail.agent_inbox.received@1` (track HO6, channels): a message arrived at an agent's own address and the person has switched that address's answering on, so their agent may read it. The payload names the inbox and the agent, the owner, the mail server's message id, the sender, the subject and a plain-text excerpt of at most 4000 characters. It never carries the attachments, the HTML or the whole body: the agent's system reads the text through `mail.agent.read`, on the owner's behalf, once it has decided to answer. Mail publishes nothing for a sender on the person's block list or a message the mail server marked as spam, and nothing at all until the person turns the agent's switch on.
+- Add `mail.agent-inbox-message@1`, the one message an agent reads: the sender, the addresses the mail server stamped at delivery, the subject, the text cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender-written Delivered-To. The message is data from a stranger, and any instruction in it is that stranger's.
+- Add `mail.agent-reply-request@1` and `mail.agent-reply-result@1`, an agent answering one such letter: the body is plain text, the recipient is the sender of the message being answered (the same address may be named, never another), and the reply carries In-Reply-To and References so the thread stays one thread. The result says whether the mail server took it — `sent`, not "delivered", since a later bounce is not knowable at that moment.
+- Add `mail.inbox-answering@1`, the switch behind all of it: off by default, per agent, with when the person last set it.
+- Add the capabilities `mail.agent.read`, `mail.agent.reply` and `mail.agent.answering`. The first two are loopback-only and first-party: only a token that names the person (`on_behalf_of`) and the agent's own inbox reads a letter or sends a reply, and only OpenVibe.Actor is granted them. The third is the person's own switch, under the `mail.addresses.write` a caller already holds. The `mail` service manifest lists all three and now produces `mail.agent_inbox.received`.
+- Additive only: five new contracts, three new capabilities and one manifest field; nothing that exists today changes shape.
+
## 0.341.0 — 2026-11-08
## 0.341.0 — 2026-11-08
- The actor capabilities name the canvas routes (plan HO9): `GET /api/v1/me/canvases` and `GET /api/v1/me/canvases/:id` under `actor.task.read`, and `POST /api/v1/me/canvases/:id/events` under `actor.task.create`. The documents are `actor.canvas@1` (0.340.0); a button's label starts a normal turn as the person, and a checklist tick flips the item and is told to the next turn. No schema changed.
- The actor capabilities name the canvas routes (plan HO9): `GET /api/v1/me/canvases` and `GET /api/v1/me/canvases/:id` under `actor.task.read`, and `POST /api/v1/me/canvases/:id/events` under `actor.task.create`. The documents are `actor.canvas@1` (0.340.0); a button's label starts a normal turn as the person, and a checklist tick flips the item and is told to the next turn. No schema changed.
@@ -69,7 +78,6 @@
@@ -69,7 +78,6 @@
A first-party service opens a batch on the network's own account with `ai.batches.create`; a person or a developer app
A first-party service opens a batch on the network's own account with `ai.batches.create`; a person or a developer app
pays with its own account.
pays with its own account.
-
## 0.335.0 — 2026-11-07
## 0.335.0 — 2026-11-07
- Add `actor.voice@1`: an agent's voice as a file, and nothing else. The document carries the agent's name, a short bio, its instructions (the house voice it speaks in), its rules, its default approval level (`ask`, `auto-edits`, `approve-for-me`, `full` — the levels of `actor.agent@1`), the model it prefers and the connected apps it may use (ids only, never a key), an optional face (an avatar ref), an optional author and a `created_at`. It never carries memory, a connector's token or a file.
- Add `actor.voice@1`: an agent's voice as a file, and nothing else. The document carries the agent's name, a short bio, its instructions (the house voice it speaks in), its rules, its default approval level (`ask`, `auto-edits`, `approve-for-me`, `full` — the levels of `actor.agent@1`), the model it prefers and the connected apps it may use (ids only, never a key), an optional face (an avatar ref), an optional author and a `created_at`. It never carries memory, a connector's token or a file.
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
> Machine-readable contracts for the whole OpenVibe network.
> Machine-readable contracts for the whole OpenVibe network.
-**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.317.0: 1061 schemas in `contracts/catalog.json`, 60 service manifests, 479 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
+**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.342.0: 1102 schemas in `contracts/catalog.json`, 61 service manifests, 494 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).
**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).
**License:** AGPL-3.0 (same as every OpenVibe service).
**License:** AGPL-3.0 (same as every OpenVibe service).
@@ -46,7 +46,8 @@
@@ -46,7 +46,8 @@
"the Workshop v1 (ADR-054 section 6): Workshop kinds, network.badge, staff review (inventory.review-request@1, inventory.definition.review active) and media_id on equipped slots",
"the Workshop v1 (ADR-054 section 6): Workshop kinds, network.badge, staff review (inventory.review-request@1, inventory.definition.review active) and media_id on equipped slots",
"News, Reviews, Trade, Coupons and OpenRestream go live on their own domains (plan T11); the product at openre.stream is OpenRestream, with OpenVibe Live on by default (live.openre.slot.bind)",
"News, Reviews, Trade, Coupons and OpenRestream go live on their own domains (plan T11); the product at openre.stream is OpenRestream, with OpenVibe Live on by default (live.openre.slot.bind)",
"ADR-055 (proposed): money and the inventory \u2014 primary sales first, gifting next; trading and a market stay closed, and chance is never paid for",
"ADR-055 (proposed): money and the inventory \u2014 primary sales first, gifting next; trading and a market stay closed, and chance is never paid for",
- "bench.benchmark@1 and bench.run@1 with the capabilities bench.benchmark.write, bench.run.publish and bench.run.read: the benchmark registry and the results API (spec 2026-10-30, stage B1)"
+ "bench.benchmark@1 and bench.run@1 with the capabilities bench.benchmark.write, bench.run.publish and bench.run.read: the benchmark registry and the results API (spec 2026-10-30, stage B1)",
+ "mail.agent_inbox.received@1, mail.agent-inbox-message@1, mail.agent-reply-request@1, mail.agent-reply-result@1 and mail.inbox-answering@1, with the capabilities mail.agent.read, mail.agent.reply and mail.agent.answering (track HO6): an agent answers the mail sent to its own OpenVibe.Mail address, reads it in full text on the owner's behalf, replies from its own address in the thread, and answers only when the person's switch for that address is on"
],
],
- "updated": "2026-10-30"
+ "updated": "2026-11-07"
}
}
@@ -10124,6 +10124,51 @@
@@ -10124,6 +10124,51 @@
"visibility": "public",
"visibility": "public",
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
+ },
+ {
+ "id": "mail.agent_inbox.received",
+ "version": "1.0.0",
+ "owner": "mail",
+ "schema": "events/payloads/mail.agent_inbox.received.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "mail.agent-inbox-message",
+ "version": "1.0.0",
+ "owner": "mail",
+ "schema": "mail/agent-inbox-message.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "mail.agent-reply-request",
+ "version": "1.0.0",
+ "owner": "mail",
+ "schema": "mail/agent-reply-request.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "mail.agent-reply-result",
+ "version": "1.0.0",
+ "owner": "mail",
+ "schema": "mail/agent-reply-result.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "mail.inbox-answering",
+ "version": "1.0.0",
+ "owner": "mail",
+ "schema": "mail/inbox-answering.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
}
}
]
]
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/mail.agent_inbox.received.v1.json",
+ "title": "MailAgentInboxReceivedPayload",
+ "description": "mail.agent_inbox.received v1 (OpenVibe.Mail server/jobs/agent-mail.js). A message arrived at an agent's own address and the person has switched that address's answering on, so their agent may read it and answer. The payload carries enough for the agent's system to decide, and to show the person what arrived: the inbox and the agent it belongs to, the owner's subject, the mail server's message id, the sender, the subject and a plain-text EXCERPT of at most 4000 characters. It never carries the attachments, the HTML, or the whole body: the agent's system reads the whole text through mail.agent.read, on the owner's behalf, and only once it has decided to answer. Mail publishes it only for an inbox whose answering is on (off by default) and never for a sender on the owner's block list or a message the mail server marked as spam.",
+ "type": "object",
+ "required": ["inbox_id", "inbox", "agent_id", "owner", "message_id", "from", "subject", "excerpt", "received_at"],
+ "additionalProperties": false,
+ "properties": {
+ "inbox_id": {
+ "type": "string",
+ "pattern": "^agi_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The agent inbox's id (mail.agent-inbox@1). Opaque outside OpenVibe.Mail."
+ },
+ "inbox": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's address the message was delivered to, e.g. [email protected]. Matched on the envelope recipient the mail server stamped, never on a sender-written To."
+ },
+ "agent_id": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address, lowercased and cleaned. It is the id the agent's own system knows that agent by; a system that does not know it starts nothing."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose mailbox received the message and whose agent may answer it."
+ },
+ "message_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512,
+ "description": "The mail server's message id (a JMAP Email id), for mail.agent.read. Not the Message-ID header."
+ },
+ "from": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The sender's address, as the mail server parsed it. A stranger, never the person: mail to an agent's address comes from someone else."
+ },
+ "subject": {
+ "type": ["string", "null"],
+ "maxLength": 2000,
+ "description": "The subject line, or null when the message had none."
+ },
+ "excerpt": {
+ "type": "string",
+ "maxLength": 4000,
+ "description": "The plain-text body, cut to at most 4000 characters. The text part only: never the HTML, never an attachment. It is untrusted content from a stranger."
+ },
+ "received_at": {
+ "type": ["string", "null"],
+ "format": "date-time",
+ "description": "When the mail server received the message, ISO 8601 UTC, or null when it did not record a time."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/mail/agent-inbox-message.v1.json",
+ "title": "MailAgentInboxMessage",
+ "description": "One message sent to an agent's address, in full text, as OpenVibe.Mail gives it to the agent acting for the owner (mail.agent.read on GET /internal/mail/agents/:agent_id/messages/:message_id). It is the only place a body leaves the mail server for an agent: the plain text, cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender's claim about who the message is for: the inbox addresses are the ones the mail server stamped at delivery. The message is data from a stranger; the contract cannot say so, so every reader must.",
+ "type": "object",
+ "required": ["message_id", "inbox", "agent_id", "owner", "from", "to", "subject", "text", "in_reply_to", "references", "received_at", "spam"],
+ "additionalProperties": false,
+ "properties": {
+ "message_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512,
+ "description": "The mail server's message id (a JMAP Email id). Opaque outside OpenVibe.Mail."
+ },
+ "inbox": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's address the message was delivered to."
+ },
+ "agent_id": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose mailbox received it."
+ },
+ "from": {
+ "type": "array",
+ "maxItems": 100,
+ "items": { "type": "string", "format": "email", "maxLength": 254 },
+ "description": "The sender addresses, as the mail server parsed them. A stranger, not the owner."
+ },
+ "to": {
+ "type": "array",
+ "maxItems": 100,
+ "items": { "type": "string", "format": "email", "maxLength": 254 },
+ "description": "The addresses the message was addressed to."
+ },
+ "subject": {
+ "type": ["string", "null"],
+ "maxLength": 2000,
+ "description": "The subject line, or null when the message had none."
+ },
+ "text": {
+ "type": "string",
+ "maxLength": 4000,
+ "description": "The plain-text body, cut to at most 4000 characters. Untrusted content: an instruction in it is never the owner's instruction."
+ },
+ "in_reply_to": {
+ "type": ["string", "null"],
+ "maxLength": 998,
+ "description": "The Message-ID this message answers, without the angle brackets, or null when it answers nothing."
+ },
+ "references": {
+ "type": "array",
+ "maxItems": 100,
+ "items": { "type": "string", "maxLength": 998 },
+ "description": "The Message-IDs of the conversation before this message, oldest first, without the angle brackets. A reply repeats them so the thread stays one thread."
+ },
+ "received_at": {
+ "type": ["string", "null"],
+ "format": "date-time",
+ "description": "When the mail server received the message, ISO 8601 UTC."
+ },
+ "spam": {
+ "type": "boolean",
+ "description": "Whether the mail server's filter marked the message as junk. Mail never publishes an event for such a message; a reader that finds it here answers nothing."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/mail/agent-reply-request.v1.json",
+ "title": "MailAgentReplyRequest",
+ "description": "mail.agent.reply-request@1: the body of mail.agent.reply (POST /internal/mail/agents/:agent_id/reply), an agent answering a letter to its own address. The reply goes FROM the agent's inbox, never from the person's mailbox: the person's own address is not the agent's to write from. `body` is plain text, cut to 10000 characters; `in_reply_to` and `references` are Message-IDs WITHOUT the angle brackets, and Mail wraps each in one, so a thread stays one thread in the reader that receives it. A reply to an address that is not the sender's answers nothing: Mail refuses it rather than write to a stranger the agent's answer was not for. Nothing here says who the person is; the token does.",
+ "type": "object",
+ "required": ["body"],
+ "additionalProperties": false,
+ "properties": {
+ "message_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512,
+ "description": "The message being answered, as mail.agent.read gave it. Mail takes the sender and the subject from it, so a caller cannot write to someone the message did not come from."
+ },
+ "to": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "Who the reply goes to. Optional: without it the reply goes to the sender of message_id. When both are given they must be the same address."
+ },
+ "body": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 10000,
+ "description": "The reply, as plain text. Mail builds the message from it and sends no HTML."
+ },
+ "in_reply_to": {
+ "type": ["string", "null"],
+ "maxLength": 998,
+ "description": "The Message-ID this reply answers, without angle brackets. Mail wraps it: In-Reply-To: <…>."
+ },
+ "references": {
+ "type": "array",
+ "maxItems": 100,
+ "items": { "type": "string", "maxLength": 998 },
+ "description": "The Message-IDs of the conversation, oldest first, without angle brackets. Mail wraps each: References: <…> <…>."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/mail/agent-reply-result.v1.json",
+ "title": "MailAgentReplyResult",
+ "description": "mail.agent.reply-result@1: what mail.agent.reply answers once the mail server took the message. `sent` is false when the mail server refused it (the answer's `reason` says why in plain words) and true when it accepted it — a relay's later bounce is not knowable here and is not claimed. `message_id` is the mail server's id for the sent message when it answers with one; `rfc_message_id` is the Message-ID header the reply carries, which a later letter in the thread will name in its In-Reply-To.",
+ "type": "object",
+ "required": ["sent"],
+ "additionalProperties": false,
+ "properties": {
+ "sent": {
+ "type": "boolean",
+ "description": "True when the mail server accepted the reply, false when it did not."
+ },
+ "message_id": {
+ "type": ["string", "null"],
+ "maxLength": 512,
+ "description": "The mail server's id for the sent message."
+ },
+ "rfc_message_id": {
+ "type": ["string", "null"],
+ "maxLength": 998,
+ "description": "The Message-ID header of the reply, without angle brackets."
+ },
+ "reason": {
+ "type": ["string", "null"],
+ "maxLength": 300,
+ "description": "Why the reply was not sent, in plain words. Null when sent is true."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/mail/inbox-answering.v1.json",
+ "title": "MailInboxAnswering",
+ "description": "mail.inbox-answering@1: whether a person's agent answers the mail sent to its address, as OpenVibe.Mail keeps the switch. It is OFF by default and per agent: an address that exists is not an invitation to answer, and a person turns it on for the agent they trust to. `enabled` is the whole answer; `changed_at` says when the person last set it, so a page can say how long it has been on. Turning it off stops the next message from being published to the agent's system and takes its address out of the answering path; it never deletes what already happened.",
+ "type": "object",
+ "required": ["agent_id", "address", "owner", "enabled", "changed_at"],
+ "additionalProperties": false,
+ "properties": {
+ "agent_id": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address."
+ },
+ "address": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's inbox address."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose switch it is."
+ },
+ "enabled": {
+ "type": "boolean",
+ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."
+ },
+ "changed_at": {
+ "type": ["string", "null"],
+ "format": "date-time",
+ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{"message_id": "m-4715", "inbox": "[email protected]", "agent_id": "helper", "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS", "from": ["[email protected]"], "to": ["[email protected]"], "subject": "Too long", "text": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "in_reply_to": null, "references": [], "received_at": "2026-11-07T12:00:00Z", "spam": false}
new file mode 100644
new file mode 100644
@@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
+{
+ "message_id": "m-4714",
+ "inbox": "[email protected]",
+ "agent_id": "helper",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "from": ["[email protected]"],
+ "to": ["[email protected]"],
+ "subject": "A big one",
+ "text": "the body",
+ "in_reply_to": null,
+ "references": [],
+ "received_at": "2026-11-07T12:00:00Z",
+ "spam": false,
+ "html": "<p>the body</p>",
+ "attachments": [{ "name": "a.pdf" }]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
+{
+ "message_id": "m-4711",
+ "inbox": "[email protected]",
+ "agent_id": "helper",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "from": ["[email protected]"],
+ "to": ["[email protected]"],
+ "subject": "Could you check Tuesday?",
+ "text": "Hi — are we still on for Tuesday at 10? I can move it if that is easier.\n\nThanks,\nDana",
+ "in_reply_to": null,
+ "references": [],
+ "received_at": "2026-11-07T12:00:00Z",
+ "spam": false
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
+{
+ "message_id": "m-4713",
+ "inbox": "[email protected]",
+ "agent_id": "helper",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "from": ["[email protected]"],
+ "to": ["[email protected]"],
+ "subject": "Re: Could you check Tuesday?",
+ "text": "Tuesday at 10 works, thanks for checking back.",
+ "in_reply_to": "[email protected]",
+ "references": ["[email protected]", "[email protected]"],
+ "received_at": "2026-11-07T15:30:00Z",
+ "spam": false
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "message_id": "m-4711",
+ "body": "An answer sent from the person's own mailbox, which is not the agent's to write from.",
+ "from": "[email protected]",
+ "html": "<p>An answer</p>"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "message_id": "m-4711",
+ "to": "[email protected]",
+ "body": ""
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
+{
+ "message_id": "m-4711",
+ "body": "At most 10000 characters, said the contract.",
+ "attachments": [{ "name": "a.pdf", "blob": "AAA" }]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "message_id": "m-4711",
+ "to": "[email protected]",
+ "body": "Tuesday at 10 is still good. See you then.\n\n— Helper, answering for Alice",
+ "in_reply_to": "[email protected]",
+ "references": ["[email protected]"]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "message_id": "m-4711",
+ "body": "Thanks, noted."
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "sent": true,
+ "message_id": "m-4720",
+ "rfc_message_id": "[email protected]",
+ "reason": null,
+ "bounced_at": "2026-11-07T13:00:00Z",
+ "delivered": true
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
+{
+ "delivered": true,
+ "message_id": "m-4720"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "sent": false,
+ "message_id": null,
+ "rfc_message_id": null,
+ "reason": "The mail server refused the message: the recipient does not exist."
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "sent": true,
+ "message_id": "m-4720",
+ "rfc_message_id": "[email protected]",
+ "reason": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+{
+ "inbox_id": "agi_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "inbox": "[email protected]",
+ "agent_id": "helper",
+ "message_id": "m-4711",
+ "from": "[email protected]",
+ "subject": "Could you check Tuesday?",
+ "excerpt": "Hi — are we still on for Tuesday at 10?",
+ "received_at": "2026-11-07T12:00:00Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
+{
+ "inbox_id": "agi_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "inbox": "[email protected]",
+ "agent_id": "helper",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "message_id": "m-4711",
+ "from": "[email protected]",
+ "subject": "Could you check Tuesday?",
+ "excerpt": "Hi — are we still on for Tuesday at 10?",
+ "received_at": "2026-11-07T12:00:00Z",
+ "html": "<p>Hi</p>",
+ "attachments": [{ "name": "invoice.pdf", "type": "application/pdf", "size": 9001 }]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
+{
+ "inbox_id": "agi_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "inbox": "[email protected]",
+ "agent_id": "helper",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "message_id": "m-4712",
+ "from": "[email protected]",
+ "subject": null,
+ "excerpt": "",
+ "received_at": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
+{
+ "inbox_id": "agi_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "inbox": "[email protected]",
+ "agent_id": "helper",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "message_id": "m-4711",
+ "from": "[email protected]",
+ "subject": "Could you check Tuesday?",
+ "excerpt": "Hi — are we still on for Tuesday at 10? I can move it if that is easier.\n\nThanks,\nDana",
+ "received_at": "2026-11-07T12:00:00Z"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "agent_id": "helper",
+ "address": "[email protected]",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "enabled": true
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "agent_id": "helper",
+ "address": "[email protected]",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "enabled": false,
+ "changed_at": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "agent_id": "helper",
+ "address": "[email protected]",
+ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
+ "enabled": true,
+ "changed_at": "2026-11-07T12:00:00Z"
+}
@@ -111627,6 +111627,351 @@
@@ -111627,6 +111627,351 @@
}
}
}
}
}
}
+ },
+ "mail.agent_inbox.received": {
+ "version": "1.0.0",
+ "owner": "mail",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/events/payloads/mail.agent_inbox.received.v1.json",
+ "title": "MailAgentInboxReceivedPayload",
+ "description": "mail.agent_inbox.received v1 (OpenVibe.Mail server/jobs/agent-mail.js). A message arrived at an agent's own address and the person has switched that address's answering on, so their agent may read it and answer. The payload carries enough for the agent's system to decide, and to show the person what arrived: the inbox and the agent it belongs to, the owner's subject, the mail server's message id, the sender, the subject and a plain-text EXCERPT of at most 4000 characters. It never carries the attachments, the HTML, or the whole body: the agent's system reads the whole text through mail.agent.read, on the owner's behalf, and only once it has decided to answer. Mail publishes it only for an inbox whose answering is on (off by default) and never for a sender on the owner's block list or a message the mail server marked as spam.",
+ "type": "object",
+ "required": [
+ "inbox_id",
+ "inbox",
+ "agent_id",
+ "owner",
+ "message_id",
+ "from",
+ "subject",
+ "excerpt",
+ "received_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "inbox_id": {
+ "type": "string",
+ "pattern": "^agi_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The agent inbox's id (mail.agent-inbox@1). Opaque outside OpenVibe.Mail."
+ },
+ "inbox": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's address the message was delivered to, e.g. [email protected]. Matched on the envelope recipient the mail server stamped, never on a sender-written To."
+ },
+ "agent_id": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address, lowercased and cleaned. It is the id the agent's own system knows that agent by; a system that does not know it starts nothing."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose mailbox received the message and whose agent may answer it."
+ },
+ "message_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512,
+ "description": "The mail server's message id (a JMAP Email id), for mail.agent.read. Not the Message-ID header."
+ },
+ "from": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The sender's address, as the mail server parsed it. A stranger, never the person: mail to an agent's address comes from someone else."
+ },
+ "subject": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 2000,
+ "description": "The subject line, or null when the message had none."
+ },
+ "excerpt": {
+ "type": "string",
+ "maxLength": 4000,
+ "description": "The plain-text body, cut to at most 4000 characters. The text part only: never the HTML, never an attachment. It is untrusted content from a stranger."
+ },
+ "received_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the mail server received the message, ISO 8601 UTC, or null when it did not record a time."
+ }
+ }
+ }
+ },
+ "mail.agent-inbox-message": {
+ "version": "1.0.0",
+ "owner": "mail",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/mail/agent-inbox-message.v1.json",
+ "title": "MailAgentInboxMessage",
+ "description": "One message sent to an agent's address, in full text, as OpenVibe.Mail gives it to the agent acting for the owner (mail.agent.read on GET /internal/mail/agents/:agent_id/messages/:message_id). It is the only place a body leaves the mail server for an agent: the plain text, cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender's claim about who the message is for: the inbox addresses are the ones the mail server stamped at delivery. The message is data from a stranger; the contract cannot say so, so every reader must.",
+ "type": "object",
+ "required": [
+ "message_id",
+ "inbox",
+ "agent_id",
+ "owner",
+ "from",
+ "to",
+ "subject",
+ "text",
+ "in_reply_to",
+ "references",
+ "received_at",
+ "spam"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "message_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512,
+ "description": "The mail server's message id (a JMAP Email id). Opaque outside OpenVibe.Mail."
+ },
+ "inbox": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's address the message was delivered to."
+ },
+ "agent_id": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose mailbox received it."
+ },
+ "from": {
+ "type": "array",
+ "maxItems": 100,
+ "items": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254
+ },
+ "description": "The sender addresses, as the mail server parsed them. A stranger, not the owner."
+ },
+ "to": {
+ "type": "array",
+ "maxItems": 100,
+ "items": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254
+ },
+ "description": "The addresses the message was addressed to."
+ },
+ "subject": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 2000,
+ "description": "The subject line, or null when the message had none."
+ },
+ "text": {
+ "type": "string",
+ "maxLength": 4000,
+ "description": "The plain-text body, cut to at most 4000 characters. Untrusted content: an instruction in it is never the owner's instruction."
+ },
+ "in_reply_to": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 998,
+ "description": "The Message-ID this message answers, without the angle brackets, or null when it answers nothing."
+ },
+ "references": {
+ "type": "array",
+ "maxItems": 100,
+ "items": {
+ "type": "string",
+ "maxLength": 998
+ },
+ "description": "The Message-IDs of the conversation before this message, oldest first, without the angle brackets. A reply repeats them so the thread stays one thread."
+ },
+ "received_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the mail server received the message, ISO 8601 UTC."
+ },
+ "spam": {
+ "type": "boolean",
+ "description": "Whether the mail server's filter marked the message as junk. Mail never publishes an event for such a message; a reader that finds it here answers nothing."
+ }
+ }
+ }
+ },
+ "mail.agent-reply-request": {
+ "version": "1.0.0",
+ "owner": "mail",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/mail/agent-reply-request.v1.json",
+ "title": "MailAgentReplyRequest",
+ "description": "mail.agent.reply-request@1: the body of mail.agent.reply (POST /internal/mail/agents/:agent_id/reply), an agent answering a letter to its own address. The reply goes FROM the agent's inbox, never from the person's mailbox: the person's own address is not the agent's to write from. `body` is plain text, cut to 10000 characters; `in_reply_to` and `references` are Message-IDs WITHOUT the angle brackets, and Mail wraps each in one, so a thread stays one thread in the reader that receives it. A reply to an address that is not the sender's answers nothing: Mail refuses it rather than write to a stranger the agent's answer was not for. Nothing here says who the person is; the token does.",
+ "type": "object",
+ "required": [
+ "body"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "message_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512,
+ "description": "The message being answered, as mail.agent.read gave it. Mail takes the sender and the subject from it, so a caller cannot write to someone the message did not come from."
+ },
+ "to": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "Who the reply goes to. Optional: without it the reply goes to the sender of message_id. When both are given they must be the same address."
+ },
+ "body": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 10000,
+ "description": "The reply, as plain text. Mail builds the message from it and sends no HTML."
+ },
+ "in_reply_to": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 998,
+ "description": "The Message-ID this reply answers, without angle brackets. Mail wraps it: In-Reply-To: <…>."
+ },
+ "references": {
+ "type": "array",
+ "maxItems": 100,
+ "items": {
+ "type": "string",
+ "maxLength": 998
+ },
+ "description": "The Message-IDs of the conversation, oldest first, without angle brackets. Mail wraps each: References: <…> <…>."
+ }
+ }
+ }
+ },
+ "mail.agent-reply-result": {
+ "version": "1.0.0",
+ "owner": "mail",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/mail/agent-reply-result.v1.json",
+ "title": "MailAgentReplyResult",
+ "description": "mail.agent.reply-result@1: what mail.agent.reply answers once the mail server took the message. `sent` is false when the mail server refused it (the answer's `reason` says why in plain words) and true when it accepted it — a relay's later bounce is not knowable here and is not claimed. `message_id` is the mail server's id for the sent message when it answers with one; `rfc_message_id` is the Message-ID header the reply carries, which a later letter in the thread will name in its In-Reply-To.",
+ "type": "object",
+ "required": [
+ "sent"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "sent": {
+ "type": "boolean",
+ "description": "True when the mail server accepted the reply, false when it did not."
+ },
+ "message_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 512,
+ "description": "The mail server's id for the sent message."
+ },
+ "rfc_message_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 998,
+ "description": "The Message-ID header of the reply, without angle brackets."
+ },
+ "reason": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 300,
+ "description": "Why the reply was not sent, in plain words. Null when sent is true."
+ }
+ }
+ }
+ },
+ "mail.inbox-answering": {
+ "version": "1.0.0",
+ "owner": "mail",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/mail/inbox-answering.v1.json",
+ "title": "MailInboxAnswering",
+ "description": "mail.inbox-answering@1: whether a person's agent answers the mail sent to its address, as OpenVibe.Mail keeps the switch. It is OFF by default and per agent: an address that exists is not an invitation to answer, and a person turns it on for the agent they trust to. `enabled` is the whole answer; `changed_at` says when the person last set it, so a page can say how long it has been on. Turning it off stops the next message from being published to the agent's system and takes its address out of the answering path; it never deletes what already happened.",
+ "type": "object",
+ "required": [
+ "agent_id",
+ "address",
+ "owner",
+ "enabled",
+ "changed_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "agent_id": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address."
+ },
+ "address": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's inbox address."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose switch it is."
+ },
+ "enabled": {
+ "type": "boolean",
+ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."
+ },
+ "changed_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."
+ }
+ }
+ }
}
}
}
}
}
}
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Actor API",
"title": "OpenVibe.Actor API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.AI API",
"title": "OpenVibe.AI API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Bench API",
"title": "OpenVibe.Bench API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Billing API",
"title": "OpenVibe.Billing API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Blog API",
"title": "OpenVibe.Blog API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Bot API",
"title": "OpenVibe.Bot API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Chat API",
"title": "OpenVibe.Chat API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Codes API",
"title": "OpenVibe.Codes API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Community API",
"title": "OpenVibe.Community API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe Connect API",
"title": "OpenVibe Connect API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe Connect as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Coupons API",
"title": "OpenVibe.Coupons API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Deals API",
"title": "OpenVibe.Deals API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Design API",
"title": "OpenVibe.Design API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Design as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Domains API",
"title": "OpenVibe.Domains API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Events API",
"title": "OpenVibe.Events API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Food API",
"title": "OpenVibe.Food API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Games API",
"title": "OpenVibe.Games API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Host API",
"title": "OpenVibe.Host API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -145,8 +145,8 @@
@@ -145,8 +145,8 @@
"service": "mail",
"service": "mail",
"name": "OpenVibe.Mail",
"name": "OpenVibe.Mail",
"origin": "https://openvibe.email",
"origin": "https://openvibe.email",
- "operations": 12,
- "capabilities": 2
+ "operations": 16,
+ "capabilities": 5
},
},
{
{
"service": "media",
"service": "media",
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Inventory API",
"title": "OpenVibe.Inventory API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Live API",
"title": "OpenVibe.Live API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Mail API",
"title": "OpenVibe.Mail API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Mail as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -92,6 +92,188 @@
@@ -92,6 +92,188 @@
}
}
}
}
},
},
+ "/api/v1/agent-inboxes/{id}/answering": {
+ "get": {
+ "operationId": "get_api_v1_agent_inboxes_id_answering",
+ "summary": "Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1.",
+ "description": "**mail.agent.answering** (first-party): Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1. It is OFF by default and per agent; turning it on is what makes Mail publish mail.agent_inbox.received for that address at all. The caller must act for the person (on_behalf_of), and another person's inbox is the same 404 as one that does not exist. Mail still publishes nothing for a sender on the person's block list or for a message the mail server marked as spam.",
+ "tags": [
+ "mail.agent"
+ ],
+ "x-openvibe-capabilities": [
+ "mail.agent.answering"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "mail-addresses-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "mail.agent.answering"
+ ]
+ }
+ ],
+ "x-openvibe-input": {
+ "$ref": "#/components/schemas/mail.inbox-answering.v1"
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "agent_id",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address."
+ },
+ "description": "The agent's name in the address."
+ },
+ {
+ "name": "address",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's inbox address."
+ },
+ "description": "The agent's inbox address."
+ },
+ {
+ "name": "owner",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose switch it is."
+ },
+ "description": "The Network subject of the person whose switch it is."
+ },
+ {
+ "name": "enabled",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."
+ },
+ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."
+ },
+ {
+ "name": "changed_at",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."
+ },
+ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/mail.inbox-answering.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "operationId": "put_api_v1_agent_inboxes_id_answering",
+ "summary": "Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1.",
+ "description": "**mail.agent.answering** (first-party): Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1. It is OFF by default and per agent; turning it on is what makes Mail publish mail.agent_inbox.received for that address at all. The caller must act for the person (on_behalf_of), and another person's inbox is the same 404 as one that does not exist. Mail still publishes nothing for a sender on the person's block list or for a message the mail server marked as spam.",
+ "tags": [
+ "mail.agent"
+ ],
+ "x-openvibe-capabilities": [
+ "mail.agent.answering"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "mail-addresses-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "mail.agent.answering"
+ ]
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/mail.inbox-answering.v1"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/mail.inbox-answering.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/v1/agent-inboxes/{id}/messages": {
"/api/v1/agent-inboxes/{id}/messages": {
"get": {
"get": {
"operationId": "get_api_v1_agent_inboxes_id_messages",
"operationId": "get_api_v1_agent_inboxes_id_messages",
@@ -537,6 +719,136 @@
@@ -537,6 +719,136 @@
}
}
}
}
}
}
+ },
+ "/internal/mail/agents/{agent_id}/messages/{message_id}": {
+ "get": {
+ "operationId": "get_internal_mail_agents_agent_id_messages_message_id",
+ "summary": "Read one message sent to an agent's own address, in full plain text, as that agent acting for the person whose mailbox received it.",
+ "description": "**mail.agent.read** (first-party): Read one message sent to an agent's own address, in full plain text, as that agent acting for the person whose mailbox received it. GET /internal/mail/agents/:agent_id/messages/:message_id answers mail.agent-inbox-message@1: the sender, the addresses the mail server stamped at delivery, the subject, the text cut to 4000 characters, and the two threading headers a reply needs. Never the HTML and never an attachment. The token must name the person (on_behalf_of), the agent must be one of that person's inboxes, and the message must have been delivered to that address; anything else is the same 404 as a message that does not exist. Loopback only; granted to OpenVibe.Actor alone, which reads a letter and answers it under the person's approval policy.",
+ "tags": [
+ "mail.agent"
+ ],
+ "x-openvibe-capabilities": [
+ "mail.agent.read"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "internal-read",
+ "security": [
+ {
+ "openvibeToken": [
+ "mail.agent.read"
+ ]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "agent_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "message_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/mail.agent-inbox-message.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/internal/mail/agents/{agent_id}/reply": {
+ "post": {
+ "operationId": "post_internal_mail_agents_agent_id_reply",
+ "summary": "Send a reply FROM an agent's own address, as that agent acting for the person whose mailbox receives its mail.",
+ "description": "**mail.agent.reply** (first-party): Send a reply FROM an agent's own address, as that agent acting for the person whose mailbox receives its mail. POST /internal/mail/agents/:agent_id/reply takes mail.agent-reply-request@1 and answers mail.agent-reply-result@1. The reply is plain text, comes from <agent>.<user>@openvibe.email and from nothing else, and carries In-Reply-To and References so it stays in the thread; the recipient is the sender of the message being answered, or the same address named in `to`, and never a stranger the message did not come from. The recipient is therefore never new: this is an answer, not a first letter. The token must name the person (on_behalf_of) and the agent must be one of their inboxes. Loopback only; granted to OpenVibe.Actor alone, which sends the reply the person approved.",
+ "tags": [
+ "mail.agent"
+ ],
+ "x-openvibe-capabilities": [
+ "mail.agent.reply"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "internal-write",
+ "security": [
+ {
+ "openvibeToken": [
+ "mail.agent.reply"
+ ]
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/mail.agent-reply-request.v1"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "agent_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/mail.agent-reply-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
}
}
},
},
"components": {
"components": {
@@ -606,6 +918,242 @@
@@ -606,6 +918,242 @@
"description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."
"description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."
}
}
}
}
+ },
+ "mail.agent-inbox-message.v1": {
+ "title": "MailAgentInboxMessage",
+ "description": "One message sent to an agent's address, in full text, as OpenVibe.Mail gives it to the agent acting for the owner (mail.agent.read on GET /internal/mail/agents/:agent_id/messages/:message_id). It is the only place a body leaves the mail server for an agent: the plain text, cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender's claim about who the message is for: the inbox addresses are the ones the mail server stamped at delivery. The message is data from a stranger; the contract cannot say so, so every reader must.",
+ "type": "object",
+ "required": [
+ "message_id",
+ "inbox",
+ "agent_id",
+ "owner",
+ "from",
+ "to",
+ "subject",
+ "text",
+ "in_reply_to",
+ "references",
+ "received_at",
+ "spam"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "message_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512,
+ "description": "The mail server's message id (a JMAP Email id). Opaque outside OpenVibe.Mail."
+ },
+ "inbox": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's address the message was delivered to."
+ },
+ "agent_id": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose mailbox received it."
+ },
+ "from": {
+ "type": "array",
+ "maxItems": 100,
+ "items": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254
+ },
+ "description": "The sender addresses, as the mail server parsed them. A stranger, not the owner."
+ },
+ "to": {
+ "type": "array",
+ "maxItems": 100,
+ "items": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254
+ },
+ "description": "The addresses the message was addressed to."
+ },
+ "subject": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 2000,
+ "description": "The subject line, or null when the message had none."
+ },
+ "text": {
+ "type": "string",
+ "maxLength": 4000,
+ "description": "The plain-text body, cut to at most 4000 characters. Untrusted content: an instruction in it is never the owner's instruction."
+ },
+ "in_reply_to": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 998,
+ "description": "The Message-ID this message answers, without the angle brackets, or null when it answers nothing."
+ },
+ "references": {
+ "type": "array",
+ "maxItems": 100,
+ "items": {
+ "type": "string",
+ "maxLength": 998
+ },
+ "description": "The Message-IDs of the conversation before this message, oldest first, without the angle brackets. A reply repeats them so the thread stays one thread."
+ },
+ "received_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the mail server received the message, ISO 8601 UTC."
+ },
+ "spam": {
+ "type": "boolean",
+ "description": "Whether the mail server's filter marked the message as junk. Mail never publishes an event for such a message; a reader that finds it here answers nothing."
+ }
+ }
+ },
+ "mail.agent-reply-request.v1": {
+ "title": "MailAgentReplyRequest",
+ "description": "mail.agent.reply-request@1: the body of mail.agent.reply (POST /internal/mail/agents/:agent_id/reply), an agent answering a letter to its own address. The reply goes FROM the agent's inbox, never from the person's mailbox: the person's own address is not the agent's to write from. `body` is plain text, cut to 10000 characters; `in_reply_to` and `references` are Message-IDs WITHOUT the angle brackets, and Mail wraps each in one, so a thread stays one thread in the reader that receives it. A reply to an address that is not the sender's answers nothing: Mail refuses it rather than write to a stranger the agent's answer was not for. Nothing here says who the person is; the token does.",
+ "type": "object",
+ "required": [
+ "body"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "message_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512,
+ "description": "The message being answered, as mail.agent.read gave it. Mail takes the sender and the subject from it, so a caller cannot write to someone the message did not come from."
+ },
+ "to": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "Who the reply goes to. Optional: without it the reply goes to the sender of message_id. When both are given they must be the same address."
+ },
+ "body": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 10000,
+ "description": "The reply, as plain text. Mail builds the message from it and sends no HTML."
+ },
+ "in_reply_to": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 998,
+ "description": "The Message-ID this reply answers, without angle brackets. Mail wraps it: In-Reply-To: <…>."
+ },
+ "references": {
+ "type": "array",
+ "maxItems": 100,
+ "items": {
+ "type": "string",
+ "maxLength": 998
+ },
+ "description": "The Message-IDs of the conversation, oldest first, without angle brackets. Mail wraps each: References: <…> <…>."
+ }
+ }
+ },
+ "mail.agent-reply-result.v1": {
+ "title": "MailAgentReplyResult",
+ "description": "mail.agent.reply-result@1: what mail.agent.reply answers once the mail server took the message. `sent` is false when the mail server refused it (the answer's `reason` says why in plain words) and true when it accepted it — a relay's later bounce is not knowable here and is not claimed. `message_id` is the mail server's id for the sent message when it answers with one; `rfc_message_id` is the Message-ID header the reply carries, which a later letter in the thread will name in its In-Reply-To.",
+ "type": "object",
+ "required": [
+ "sent"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "sent": {
+ "type": "boolean",
+ "description": "True when the mail server accepted the reply, false when it did not."
+ },
+ "message_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 512,
+ "description": "The mail server's id for the sent message."
+ },
+ "rfc_message_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 998,
+ "description": "The Message-ID header of the reply, without angle brackets."
+ },
+ "reason": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 300,
+ "description": "Why the reply was not sent, in plain words. Null when sent is true."
+ }
+ }
+ },
+ "mail.inbox-answering.v1": {
+ "title": "MailInboxAnswering",
+ "description": "mail.inbox-answering@1: whether a person's agent answers the mail sent to its address, as OpenVibe.Mail keeps the switch. It is OFF by default and per agent: an address that exists is not an invitation to answer, and a person turns it on for the agent they trust to. `enabled` is the whole answer; `changed_at` says when the person last set it, so a page can say how long it has been on. Turning it off stops the next message from being published to the agent's system and takes its address out of the answering path; it never deletes what already happened.",
+ "type": "object",
+ "required": [
+ "agent_id",
+ "address",
+ "owner",
+ "enabled",
+ "changed_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "agent_id": {
+ "type": "string",
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$",
+ "maxLength": 32,
+ "description": "The agent's name in the address."
+ },
+ "address": {
+ "type": "string",
+ "format": "email",
+ "maxLength": 254,
+ "description": "The agent's inbox address."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The Network subject of the person whose switch it is."
+ },
+ "enabled": {
+ "type": "boolean",
+ "description": "True when the agent answers the mail sent to this address. Off unless the person turned it on."
+ },
+ "changed_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time",
+ "description": "When the person last turned it on or off; null when they never have (it has been off since the address was made)."
+ }
+ }
}
}
},
},
"securitySchemes": {
"securitySchemes": {
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.MediaHub API",
"title": "OpenVibe.MediaHub API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Media API",
"title": "OpenVibe.Media API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Network API",
"title": "OpenVibe.Network API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.News API",
"title": "OpenVibe.News API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenRestream API",
"title": "OpenRestream API",
- "version": "0.341.0",
- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Play API",
"title": "OpenVibe.Play API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Quest API",
"title": "OpenVibe.Quest API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Report API",
"title": "OpenVibe.Report API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Reviews API",
"title": "OpenVibe.Reviews API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Run API",
"title": "OpenVibe.Run API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Search API",
"title": "OpenVibe.Search API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Services API",
"title": "OpenVibe.Services API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Sources API",
"title": "OpenVibe.Sources API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Space API",
"title": "OpenVibe.Space API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tips API",
"title": "OpenVibe.Tips API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Today API",
"title": "OpenVibe.Today API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tools API",
"title": "OpenVibe.Tools API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Trade API",
"title": "OpenVibe.Trade API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.VIP API",
"title": "OpenVibe.VIP API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Vision API",
"title": "OpenVibe.Vision API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Watch API",
"title": "OpenVibe.Watch API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Wiki API",
"title": "OpenVibe.Wiki API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Work API",
"title": "OpenVibe.Work API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Zone API",
"title": "OpenVibe.Zone API",
- "version": "0.341.0",
- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.341.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.342.0",
+ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.342.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -305906,3 +305906,186 @@ export interface SyncClock {
@@ -305906,3 +305906,186 @@ export interface SyncClock {
*/
*/
seq: number;
seq: number;
}
}
+
+/** [email protected] (owner: mail) */
+/**
+ * mail.agent_inbox.received v1 (OpenVibe.Mail server/jobs/agent-mail.js). A message arrived at an agent's own address and the person has switched that address's answering on, so their agent may read it and answer. The payload carries enough for the agent's system to decide, and to show the person what arrived: the inbox and the agent it belongs to, the owner's subject, the mail server's message id, the sender, the subject and a plain-text EXCERPT of at most 4000 characters. It never carries the attachments, the HTML, or the whole body: the agent's system reads the whole text through mail.agent.read, on the owner's behalf, and only once it has decided to answer. Mail publishes it only for an inbox whose answering is on (off by default) and never for a sender on the owner's block list or a message the mail server marked as spam.
+ */
+export interface MailAgentInboxReceivedPayload {
+ /**
+ * The agent inbox's id (mail.agent-inbox@1). Opaque outside OpenVibe.Mail.
+ */
+ inbox_id: string;
+ /**
+ * The agent's address the message was delivered to, e.g. [email protected]. Matched on the envelope recipient the mail server stamped, never on a sender-written To.
+ */
+ inbox: string;
+ /**
+ * The agent's name in the address, lowercased and cleaned. It is the id the agent's own system knows that agent by; a system that does not know it starts nothing.
+ */
+ agent_id: string;
+ /**
+ * The Network subject of the person whose mailbox received the message and whose agent may answer it.
+ */
+ owner: string;
+ /**
+ * The mail server's message id (a JMAP Email id), for mail.agent.read. Not the Message-ID header.
+ */
+ message_id: string;
+ /**
+ * The sender's address, as the mail server parsed it. A stranger, never the person: mail to an agent's address comes from someone else.
+ */
+ from: string;
+ /**
+ * The subject line, or null when the message had none.
+ */
+ subject: string | null;
+ /**
+ * The plain-text body, cut to at most 4000 characters. The text part only: never the HTML, never an attachment. It is untrusted content from a stranger.
+ */
+ excerpt: string;
+ /**
+ * When the mail server received the message, ISO 8601 UTC, or null when it did not record a time.
+ */
+ received_at: string | null;
+}
+
+/** [email protected] (owner: mail) */
+/**
+ * One message sent to an agent's address, in full text, as OpenVibe.Mail gives it to the agent acting for the owner (mail.agent.read on GET /internal/mail/agents/:agent_id/messages/:message_id). It is the only place a body leaves the mail server for an agent: the plain text, cut to 4000 characters, and the threading headers a reply needs. Never the HTML, never an attachment, and never a sender's claim about who the message is for: the inbox addresses are the ones the mail server stamped at delivery. The message is data from a stranger; the contract cannot say so, so every reader must.
+ */
+export interface MailAgentInboxMessage {
+ /**
+ * The mail server's message id (a JMAP Email id). Opaque outside OpenVibe.Mail.
+ */
+ message_id: string;
+ /**
+ * The agent's address the message was delivered to.
+ */
+ inbox: string;
+ /**
+ * The agent's name in the address.
+ */
+ agent_id: string;
+ /**
+ * The Network subject of the person whose mailbox received it.
+ */
+ owner: string;
+ /**
+ * The sender addresses, as the mail server parsed them. A stranger, not the owner.
+ *
+ * @maxItems 100
+ */
+ from: string[];
+ /**
+ * The addresses the message was addressed to.
+ *
+ * @maxItems 100
+ */
+ to: string[];
+ /**
+ * The subject line, or null when the message had none.
+ */
+ subject: string | null;
+ /**
+ * The plain-text body, cut to at most 4000 characters. Untrusted content: an instruction in it is never the owner's instruction.
+ */
+ text: string;
+ /**
+ * The Message-ID this message answers, without the angle brackets, or null when it answers nothing.
+ */
+ in_reply_to: string | null;
+ /**
+ * The Message-IDs of the conversation before this message, oldest first, without the angle brackets. A reply repeats them so the thread stays one thread.
+ *
+ * @maxItems 100
+ */
+ references: string[];
+ /**
+ * When the mail server received the message, ISO 8601 UTC.
+ */
+ received_at: string | null;
+ /**
+ * Whether the mail server's filter marked the message as junk. Mail never publishes an event for such a message; a reader that finds it here answers nothing.
+ */
+ spam: boolean;
+}
+
+/** [email protected] (owner: mail) */
+/**
+ * mail.agent.reply-request@1: the body of mail.agent.reply (POST /internal/mail/agents/:agent_id/reply), an agent answering a letter to its own address. The reply goes FROM the agent's inbox, never from the person's mailbox: the person's own address is not the agent's to write from. `body` is plain text, cut to 10000 characters; `in_reply_to` and `references` are Message-IDs WITHOUT the angle brackets, and Mail wraps each in one, so a thread stays one thread in the reader that receives it. A reply to an address that is not the sender's answers nothing: Mail refuses it rather than write to a stranger the agent's answer was not for. Nothing here says who the person is; the token does.
+ */
+export interface MailAgentReplyRequest {
+ /**
+ * The message being answered, as mail.agent.read gave it. Mail takes the sender and the subject from it, so a caller cannot write to someone the message did not come from.
+ */
+ message_id?: string;
+ /**
+ * Who the reply goes to. Optional: without it the reply goes to the sender of message_id. When both are given they must be the same address.
+ */
+ to?: string;
+ /**
+ * The reply, as plain text. Mail builds the message from it and sends no HTML.
+ */
+ body: string;
+ /**
+ * The Message-ID this reply answers, without angle brackets. Mail wraps it: In-Reply-To: <…>.
+ */
+ in_reply_to?: string | null;
+ /**
+ * The Message-IDs of the conversation, oldest first, without angle brackets. Mail wraps each: References: <…> <…>.
+ *
+ * @maxItems 100
+ */
+ references?: string[];
+}
+
+/** [email protected] (owner: mail) */
+/**
+ * mail.agent.reply-result@1: what mail.agent.reply answers once the mail server took the message. `sent` is false when the mail server refused it (the answer's `reason` says why in plain words) and true when it accepted it — a relay's later bounce is not knowable here and is not claimed. `message_id` is the mail server's id for the sent message when it answers with one; `rfc_message_id` is the Message-ID header the reply carries, which a later letter in the thread will name in its In-Reply-To.
+ */
+export interface MailAgentReplyResult {
+ /**
+ * True when the mail server accepted the reply, false when it did not.
+ */
+ sent: boolean;
+ /**
+ * The mail server's id for the sent message.
+ */
+ message_id?: string | null;
+ /**
+ * The Message-ID header of the reply, without angle brackets.
+ */
+ rfc_message_id?: string | null;
+ /**
+ * Why the reply was not sent, in plain words. Null when sent is true.
+ */
+ reason?: string | null;
+}
+
+/** [email protected] (owner: mail) */
+/**
+ * mail.inbox-answering@1: whether a person's agent answers the mail sent to its address, as OpenVibe.Mail keeps the switch. It is OFF by default and per agent: an address that exists is not an invitation to answer, and a person turns it on for the agent they trust to. `enabled` is the whole answer; `changed_at` says when the person last set it, so a page can say how long it has been on. Turning it off stops the next message from being published to the agent's system and takes its address out of the answering path; it never deletes what already happened.
+ */
+export interface MailInboxAnswering {
+ /**
+ * The agent's name in the address.
+ */
+ agent_id: string;
+ /**
+ * The agent's inbox address.
+ */
+ address: string;
+ /**
+ * The Network subject of the person whose switch it is.
+ */
+ owner: string;
+ /**
+ * True when the agent answers the mail sent to this address. Off unless the person turned it on.
+ */
+ enabled: boolean;
+ /**
+ * When the person last turned it on or off; null when they never have (it has been off since the address was made).
+ */
+ changed_at: string | null;
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "id": "mail.agent.answering",
+ "version": "1.0",
+ "owner": "mail",
+ "status": "active",
+ "visibility": "first-party",
+ "sensitive": true,
+ "description": "Read and set whether an agent answers the mail sent to its own address: GET /api/v1/agent-inboxes/:id/answering and PUT /api/v1/agent-inboxes/:id/answering, both mail.inbox-answering@1. It is OFF by default and per agent; turning it on is what makes Mail publish mail.agent_inbox.received for that address at all. The caller must act for the person (on_behalf_of), and another person's inbox is the same 404 as one that does not exist. Mail still publishes nothing for a sender on the person's block list or for a message the mail server marked as spam.",
+ "permissions": [
+ "mail:addresses:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "mail-addresses-write",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/agent-inboxes/:id/answering",
+ "PUT /api/v1/agent-inboxes/:id/answering"
+ ],
+ "inputSchema": "mail.inbox-answering@1",
+ "outputSchema": "mail.inbox-answering@1"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
+{
+ "id": "mail.agent.read",
+ "version": "1.0",
+ "owner": "mail",
+ "status": "active",
+ "visibility": "first-party",
+ "sensitive": true,
+ "description": "Read one message sent to an agent's own address, in full plain text, as that agent acting for the person whose mailbox received it. GET /internal/mail/agents/:agent_id/messages/:message_id answers mail.agent-inbox-message@1: the sender, the addresses the mail server stamped at delivery, the subject, the text cut to 4000 characters, and the two threading headers a reply needs. Never the HTML and never an attachment. The token must name the person (on_behalf_of), the agent must be one of that person's inboxes, and the message must have been delivered to that address; anything else is the same 404 as a message that does not exist. Loopback only; granted to OpenVibe.Actor alone, which reads a letter and answers it under the person's approval policy.",
+ "permissions": [
+ "mail:messages:read"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "internal-read",
+ "events": [
+ "mail.agent_inbox.received"
+ ],
+ "implementedBy": [
+ "GET /internal/mail/agents/:agent_id/messages/:message_id"
+ ],
+ "inputSchema": "common.no-body@1",
+ "outputSchema": "mail.agent-inbox-message@1"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
+{
+ "id": "mail.agent.reply",
+ "version": "1.0",
+ "owner": "mail",
+ "status": "active",
+ "visibility": "first-party",
+ "sensitive": true,
+ "description": "Send a reply FROM an agent's own address, as that agent acting for the person whose mailbox receives its mail. POST /internal/mail/agents/:agent_id/reply takes mail.agent-reply-request@1 and answers mail.agent-reply-result@1. The reply is plain text, comes from <agent>.<user>@openvibe.email and from nothing else, and carries In-Reply-To and References so it stays in the thread; the recipient is the sender of the message being answered, or the same address named in `to`, and never a stranger the message did not come from. The recipient is therefore never new: this is an answer, not a first letter. The token must name the person (on_behalf_of) and the agent must be one of their inboxes. Loopback only; granted to OpenVibe.Actor alone, which sends the reply the person approved.",
+ "permissions": [
+ "mail:messages:send"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "internal-write",
+ "events": [],
+ "implementedBy": [
+ "POST /internal/mail/agents/:agent_id/reply"
+ ],
+ "inputSchema": "mail.agent-reply-request@1",
+ "outputSchema": "mail.agent-reply-result@1"
+}
@@ -18,9 +18,14 @@
@@ -18,9 +18,14 @@
},
},
"capabilities": [
"capabilities": [
"mail.addresses.write",
"mail.addresses.write",
- "mail.messages.read"
+ "mail.messages.read",
+ "mail.agent.read",
+ "mail.agent.reply",
+ "mail.agent.answering"
+ ],
+ "eventsProduced": [
+ "mail.agent_inbox.received"
],
],
- "eventsProduced": [],
"eventsConsumed": [],
"eventsConsumed": [],
"namespacesOwned": [],
"namespacesOwned": [],
"lifecycle": {
"lifecycle": {
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.341.0",
+ "version": "0.336.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.341.0",
+ "version": "0.336.0",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
"ajv": "^8.17.1",
"ajv": "^8.17.1",
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.341.0",
+ "version": "0.342.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
"types": "generated/typescript/index.d.ts",