openvibers/openvibe.contracts Commits
Pooled machines: bot.machine-pool@1 and the AI offer's pool part (0.309.0) (#316)
Changes
@@@ -1,5 +1,14 @@# Changelog++## 0.309.0 — 2026-11-07++++- Add `bot.machine-pool@1` (the pooled machines design, 2026-11-06): several of one owner's machines on the same local network that serve one model together through llama.cpp RPC (`rpc-server` on the members, `llama-server --rpc` on the head). OpenVibe.Network holds the record: the owner proposes it on /machines with two to eight of their own machines (the default head has the most free VRAM), and each machine reads it with its own node token and approves it on itself. A member's `certificate` is null until it approves; then it is that machine's self-signed Ed25519 public certificate, which the other members pin for the pool's private link. The private key stays on the machine: a certificate slot holding anything with `PRIVATE KEY` in it is refused, and so is any field the schema does not name. A member's `address` is a private RFC 1918 address and prefix (never 0.0.0.0, loopback or a public address) and its `public_ip` is the address Network saw it from. The rules a schema cannot say are written in the description and checked by Network and Node: the head is a member, every member is the owner's today, all share one public address and one private subnet, the head's direct link probe to each passes, every key is its own, and any change of membership, owner, head or key revokes the pool so every machine approves a new one.++- Add `ai.offer@1`: one community AI offer as Bot reports it to Network and AI reads it back (the fields Network already stores: machine, owner, models, hours, concurrency, credit price, audience, readiness and health), with the new optional `pool`.++- Add `ai.offer-pool@1`, the `pool` part of the AI offer: `{ machines, head }`, two to eight machine ids and the head, which is the offer's own machine. Network adds it from its approved pool record, never from what a machine reports, and leaves a member's own offer out while it is in a pool. It names machines only: no address, key or certificate reaches AI. One price, audience, hours, idle-only and verification apply to the whole pool; AI verifies a pool's answers as it would one machine's, keys that verification on the exact membership, keeps a new or failed pool to the free tier only, and labels it "Community pool (N machines)".++- `network.node.self.manage` names the five pool routes a machine calls with its own token (announce, read, approve, renew readiness, leave) in `implementedBy`.++- Valid and invalid fixtures cover a pool waiting for approvals, an approved pool of three, a single-machine offer, a pool's offer and one still waiting, a group offer, a missing head or owner, a one-machine pool, a repeated member, a private key in the certificate slot, a public, loopback or wildcard address, a port under 1024, and an address, certificate or key smuggled into a field the schema does not name.++++## 0.308.0 — 2026-11-07- Add `ai.memory-export@1` (Memory M5): the one portable memory file. It carries `format: openvibe.memory-export@1`, `version: 1`, `exported_at` and every item's text, kind, scope, source, confidence and source reference. It deliberately has no ids, owners, merge links or conflict pair, so a file can be imported into another account without carrying anyone's identity, and a profile is derived from the items and rebuilt, never imported. OpenVibe.AI's `GET /api/v1/memory/export` writes it and `POST /api/v1/memory/import` accepts the same document; both redact again.@@@ -11,6 +11,7 @@"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases","contracts": "openvibe-contracts (this package: package.json's version, released as the matching tag)","features": [++ "bot.machine-pool@1, ai.offer@1 and ai.offer-pool@1 (the pooled machines design): several of one owner's machines on one local network serving one model through llama.cpp RPC, each approving on itself with its own public certificate, and the community AI offer with the pool part Network adds to the head's offer","chat.play-request@1 and codes.sandbox-session@1 (the Agent Streams plan, S6): the queue a chat plays room keeps and the sandbox desk that works it, with the owner's time box, cap and Go, and the scratch site that lives 24 hours","the capabilities chat.play_queue.read and chat.play_queue.write, for Codes acting for the stream's owner","chat.agent-digest@1, chat.agent-poll@1 and live.agent-stream-control@1 (the Agent Streams plan, S5): the digest a Co-pilot room gives an agent, the poll an agent asks that room to run, and the four controls the owner and the moderators have over a live agent stream",nnew file mode 100644@@@ -0,0 +1,30 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/ai/offer-pool.v1.json",++ "title": "AiOfferPool",++ "description": "ai.offer-pool@1 (the pooled machines design, 2026-11-06): the `pool` part of a community AI offer (ai.offer@1) served by several of one owner's machines together (bot.machine-pool@1). Network adds it from its own approved pool record, never from what a machine reports: the offer is the head's, `head` equals the offer's `machine_id`, and while a machine is in a pool it advertises no offer of its own. It names machines only; no address, key or certificate reaches AI. AI routes the request to the head, runs the same verification as for one machine (canaries, the model fingerprint, spot re-runs) on the pool's answers, keys that verification on this exact membership (another member or head is a new, unverified pool), keeps a pool that is new or failed to the free tier only, and labels its answers \"Community pool (N machines)\".",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "machines",++ "head"++ ],++ "properties": {++ "machines": {++ "type": "array",++ "minItems": 2,++ "maxItems": 8,++ "uniqueItems": true,++ "description": "The pool's machines, head included (Bot device ids), two to eight.",++ "items": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "head": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine that answers: one of `machines`, and the offer's own `machine_id`."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,146 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/ai/offer.v1.json",++ "title": "AiOffer",++ "description": "ai.offer@1: one community AI offer, a person's machine (OpenVibe.Node's ai plugin, \"Offer to the network\") serving its local models to requests that opt in to community capacity. OpenVibe.Bot reports these fields (POST /internal/ai/offers/report on Network, network.resource.report; a report with any other field is refused whole), and OpenVibe.AI reads them from Network (GET /internal/ai/offers, network.registry.read, { offers, generated_at, count }). Network adds `pool` (ai.offer-pool@1) to the head's offer when the machine is the head of an approved pool (bot.machine-pool@1), and leaves a pool member's own offer out of the list while it is in a pool. For a pool the hours, audience, price, readiness, idle-only and verification apply to the whole pool: it is ready only while every member has approved, renewed its readiness in the last few seconds, and is still the owner's. Nothing here is public: AI shows Exchange a hashed offer id and no owner or machine id.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "offer_id",++ "machine_id",++ "owner",++ "models",++ "hours",++ "concurrency",++ "price",++ "audience",++ "group",++ "ready",++ "health"++ ],++ "properties": {++ "offer_id": {++ "type": "string",++ "pattern": "^ai:dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "`ai:<machine_id>`: one offer per machine."++ },++ "machine_id": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine that answers (for a pool, its head)."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine's owner, who earns the offer's credits (a self-served run earns none)."++ },++ "models": {++ "type": "array",++ "minItems": 1,++ "maxItems": 40,++ "description": "The models offered, as the machine's model server names them.",++ "items": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ }++ },++ "hours": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "start",++ "end",++ "tz"++ ],++ "description": "The local-time window the offer is open; start equal to end is all day, and an overnight window wraps.",++ "properties": {++ "start": {++ "type": "string",++ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"++ },++ "end": {++ "type": "string",++ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"++ },++ "tz": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "description": "An IANA time zone, such as Europe/Paris, or UTC."++ }++ }++ },++ "concurrency": {++ "type": "integer",++ "minimum": 1,++ "maximum": 8,++ "description": "How many requests may run at once; another is refused as busy, never queued."++ },++ "price": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "in_per_million",++ "out_per_million"++ ],++ "description": "Credits per million input and output tokens; 0 and 0 is a volunteer, who earns kudos. One price for a pool.",++ "properties": {++ "in_per_million": {++ "type": "number",++ "minimum": 0,++ "maximum": 1000000++ },++ "out_per_million": {++ "type": "number",++ "minimum": 0,++ "maximum": 1000000++ }++ }++ },++ "audience": {++ "enum": [++ "everyone",++ "followers",++ "group"++ ],++ "description": "Who may use it: everyone, the owner's followers, or one group (`group`)."++ },++ "group": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 80,++ "description": "The group's id when the audience is `group`, otherwise null."++ },++ "ready": {++ "type": "boolean",++ "description": "Whether the machine (for a pool, every member) can answer now: online, inside its hours, not paused by idle-only or a kill switch."++ },++ "health": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "status"++ ],++ "properties": {++ "status": {++ "enum": [++ "up",++ "degraded",++ "down"++ ]++ },++ "checked_at": {++ "type": "string",++ "format": "date-time"++ }++ }++ },++ "pool": {++ "$ref": "offer-pool.v1.json",++ "description": "Present when the offer is served by a pool of the owner's machines (ai.offer-pool@1)."++ }++ }++}nnew file mode 100644@@@ -0,0 +1,119 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/bot/machine-pool.v1.json",++ "title": "BotMachinePool",++ "description": "bot.machine-pool@1 (the pooled machines design, 2026-11-06): several of one owner's machines on the same local network that serve one model together through llama.cpp RPC, `rpc-server` on the members and `llama-server --rpc` on the head. OpenVibe.Network holds the record: the owner proposes it on /machines (POST /api/v1/machine-pools, two to eight of their own machines and an optional head; the default head has the most free VRAM), and each machine reads it with its own node token (GET /api/v1/node/self/pools/:id, network.node.self.manage) and approves it locally (POST /api/v1/node/self/pools/:id/approve with { certificate }). A machine's `certificate` is null until it approves on that machine: the Node generates an Ed25519 key there, keeps the private key, and uploads only its self-signed public certificate, which the other members pin for the pool's private link. A pool with any null certificate never serves. The record never carries a private key or a prompt. What a schema cannot say, Network and Node check at run time: the members are distinct and the head is one of them; every member has the pool's owner, today, through Bot; every member was seen from the same public address with a private address in the same subnet; the head's direct link probe to each member passes; each machine's certificate is its own; and any change of membership, owner, head or key revokes the pool, so all machines approve a new one. A machine that leaves (removed, signed out, a different owner) drops its link and its key at once.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "owner",++ "head",++ "machines"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^pool_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The pool's id (ULID, Crockford base32). A pool is never edited: a change is a new pool with a new id."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The person every machine in the pool belongs to. Pools of different owners are not allowed."++ },++ "head": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine that runs `llama-server --rpc`, sees the prompt and answers; it must be one of `machines`. The others receive tensors only."++ },++ "machines": {++ "type": "array",++ "minItems": 2,++ "maxItems": 8,++ "description": "The members, head included, two to eight.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "owner",++ "address",++ "public_ip",++ "port",++ "free_vram",++ "free_ram",++ "hardware",++ "certificate"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine's owner when it announced itself; it must equal the pool's owner."++ },++ "address": {++ "type": "string",++ "pattern": "^(10\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])|172\\.(1[6-9]|2[0-9]|3[01])|192\\.168)\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])/([89]|[12][0-9]|30)$",++ "maxLength": 32,++ "description": "The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address."++ },++ "public_ip": {++ "type": "string",++ "maxLength": 45,++ "anyOf": [++ {++ "format": "ipv4"++ },++ {++ "format": "ipv6"++ }++ ],++ "description": "The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head."++ },++ "port": {++ "type": "integer",++ "minimum": 1024,++ "maximum": 65535,++ "description": "The TCP port of the machine's private link on `address`."++ },++ "free_vram": {++ "type": "integer",++ "minimum": 0,++ "maximum": 16777216,++ "description": "Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it."++ },++ "free_ram": {++ "type": "integer",++ "minimum": 0,++ "maximum": 16777216,++ "description": "Free system memory when it announced itself, in MB."++ },++ "hardware": {++ "type": "string",++ "maxLength": 120,++ "description": "A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model."++ },++ "certificate": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 8192,++ "pattern": "^-----BEGIN CERTIFICATE-----",++ "not": {++ "type": "string",++ "pattern": "PRIVATE KEY"++ },++ "description": "The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key."++ }++ }++ }++ }++ }++}@@@ -9636,6 +9636,33 @@"visibility": "first-party","compatibility": "backward","status": "active"++ },++ {++ "id": "bot.machine-pool",++ "version": "1.0.0",++ "owner": "bot",++ "schema": "bot/machine-pool.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "ai.offer-pool",++ "version": "1.0.0",++ "owner": "ai",++ "schema": "ai/offer-pool.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"++ },++ {++ "id": "ai.offer",++ "version": "1.0.0",++ "owner": "ai",++ "schema": "ai/offer.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active"}]}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "address": "192.168.1.20/24"++}nnew file mode 100644@@@ -0,0 +1,10 @@++{++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "certificates": [++ "-----BEGIN CERTIFICATE-----\nMIIBRDCB96ADAgECAhQ1F6qS8nQmfA4Z1EQWbuTK6c+/CDAFBgMrZXAwGDEWMBQG\nA1UEAwwNT3BlblZpYmUtcG9vbDAeFw0yNjExMDcwMjE1NThaFw0zNjExMDQwMjE1\nNThaMBgxFjAUBgNVBAMMDU9wZW5WaWJlLXBvb2wwKjAFBgMrZXADIQBzzRaEd6ZR\nqYbsbYK3W8CCJPIAbsNTlIXZYgPEC9yf76NTMFEwHQYDVR0OBBYEFPiGTnP9vRST\nUlo0W1Eh0xcOxA49MB8GA1UdIwQYMBaAFPiGTnP9vRSTUlo0W1Eh0xcOxA49MA8G\nA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EAOlCHoX3ONMZYTHx4GSAlxP4EQase+99L\nGykZvgPSVDs2alKLXW5fBxvn7OcEJ3g/EMmk9iZ+AL+CmLxdcYBLCw==\n-----END CERTIFICATE-----\n"++ ]++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ]++}nnew file mode 100644@@@ -0,0 +1,6 @@++{++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++}nnew file mode 100644@@@ -0,0 +1,8 @@++{++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D3"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++}nnew file mode 100644@@@ -0,0 +1,33 @@++{++ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "models": [++ "llama-3.3-70b-instruct-q4_k_m"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "everyone",++ "group": null,++ "ready": true,++ "health": {++ "status": "up",++ "checked_at": "2026-11-07T10:00:00.000Z"++ },++ "pool": {++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++ },++ "private_key": "not-permitted"++}nnew file mode 100644@@@ -0,0 +1,31 @@++{++ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "models": [++ "llama-3.3-70b-instruct-q4_k_m"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "everyone",++ "group": null,++ "ready": true,++ "health": {++ "status": "up",++ "checked_at": "2026-11-07T10:00:00.000Z"++ },++ "pool": {++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++ }++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "offer_id": "ai:everything",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "models": [++ "qwen3:8b"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "everyone",++ "group": null,++ "ready": true,++ "health": {++ "status": "up",++ "checked_at": "2026-11-07T10:00:00.000Z"++ }++}nnew file mode 100644@@@ -0,0 +1,31 @@++{++ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "models": [++ "llama-3.3-70b-instruct-q4_k_m"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "everyone",++ "group": null,++ "ready": true,++ "health": {++ "status": "up",++ "checked_at": "2026-11-07T10:00:00.000Z"++ },++ "pool": {++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++ }++}nnew file mode 100644@@@ -0,0 +1,33 @@++{++ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "models": [++ "llama-3.3-70b-instruct-q4_k_m"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "everyone",++ "group": null,++ "ready": true,++ "health": {++ "status": "up",++ "checked_at": "2026-11-07T10:00:00.000Z"++ },++ "pool": {++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "address": "192.168.1.20/24"++ }++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "models": [++ "qwen3:8b"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "group",++ "group": "grp_friends",++ "ready": true,++ "health": {++ "status": "up",++ "checked_at": "2026-11-07T10:00:00.000Z"++ }++}nnew file mode 100644@@@ -0,0 +1,31 @@++{++ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "models": [++ "llama-3.3-70b-instruct-q4_k_m"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "everyone",++ "group": null,++ "ready": false,++ "health": {++ "status": "down"++ },++ "pool": {++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++ }++}nnew file mode 100644@@@ -0,0 +1,32 @@++{++ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "models": [++ "llama-3.3-70b-instruct-q4_k_m"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "everyone",++ "group": null,++ "ready": true,++ "health": {++ "status": "up",++ "checked_at": "2026-11-07T10:00:00.000Z"++ },++ "pool": {++ "machines": [++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"++ ],++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"++ }++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "models": [++ "qwen3:8b"++ ],++ "hours": {++ "start": "22:00",++ "end": "08:00",++ "tz": "Europe/Paris"++ },++ "concurrency": 1,++ "price": {++ "in_per_million": 0.2,++ "out_per_million": 0.6++ },++ "audience": "everyone",++ "group": null,++ "ready": true,++ "health": {++ "status": "up",++ "checked_at": "2026-11-07T10:00:00.000Z"++ }++}nnew file mode 100644@@@ -0,0 +1,30 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.21/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ }++ ],++ "private_key": "not-permitted"++}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "127.0.0.1/8",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,30 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.21/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null,++ "node_credential": "not-permitted"++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,28 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.21/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,18 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.21/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": "-----BEGIN CERTIFICATE-----\nthe PRIVATE KEY pasted here by mistake\n-----END CERTIFICATE-----\n"++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.21/24",++ "public_ip": "203.0.113.7",++ "port": 80,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "8.8.8.8/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "0.0.0.0/0",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,40 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": "-----BEGIN CERTIFICATE-----\nMIIBRDCB96ADAgECAhQ1F6qS8nQmfA4Z1EQWbuTK6c+/CDAFBgMrZXAwGDEWMBQG\nA1UEAwwNT3BlblZpYmUtcG9vbDAeFw0yNjExMDcwMjE1NThaFw0zNjExMDQwMjE1\nNThaMBgxFjAUBgNVBAMMDU9wZW5WaWJlLXBvb2wwKjAFBgMrZXADIQBzzRaEd6ZR\nqYbsbYK3W8CCJPIAbsNTlIXZYgPEC9yf76NTMFEwHQYDVR0OBBYEFPiGTnP9vRST\nUlo0W1Eh0xcOxA49MB8GA1UdIwQYMBaAFPiGTnP9vRSTUlo0W1Eh0xcOxA49MA8G\nA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EAOlCHoX3ONMZYTHx4GSAlxP4EQase+99L\nGykZvgPSVDs2alKLXW5fBxvn7OcEJ3g/EMmk9iZ+AL+CmLxdcYBLCw==\n-----END CERTIFICATE-----\n"++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.21/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": "-----BEGIN CERTIFICATE-----\nMIIBRDCB96ADAgECAhRrJ/6HQgidfd9Sah9rLZOC0022ejAFBgMrZXAwGDEWMBQG\nA1UEAwwNT3BlblZpYmUtcG9vbDAeFw0yNjExMDcwMjE2MjRaFw0zNjExMDQwMjE2\nMjRaMBgxFjAUBgNVBAMMDU9wZW5WaWJlLXBvb2wwKjAFBgMrZXADIQBIJ8mF2e9W\nbILuPZQVwA2/LgC2VFtQAnpPDXExV2jXYaNTMFEwHQYDVR0OBBYEFKi5Za/SzebG\nkYOs4rzWz72zsM55MB8GA1UdIwQYMBaAFKi5Za/SzebGkYOs4rzWz72zsM55MA8G\nA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EAtZp/I6vCQ72SrCrQeH4QCz+sXqwnn24U\np9v1GeWXRE26rNmM3/ZQ4J9Vqmb/inSL5fMSKw9MJG+yZMShheRiDA==\n-----END CERTIFICATE-----\n"++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D3",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.22/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 8000,++ "free_ram": 32000,++ "hardware": "x86_64",++ "certificate": "-----BEGIN CERTIFICATE-----\nMIIBRDCB96ADAgECAhQqwkAcayM2me9QLHZC1hfsr6SzhTAFBgMrZXAwGDEWMBQG\nA1UEAwwNT3BlblZpYmUtcG9vbDAeFw0yNjExMDcwMjE2MjRaFw0zNjExMDQwMjE2\nMjRaMBgxFjAUBgNVBAMMDU9wZW5WaWJlLXBvb2wwKjAFBgMrZXADIQDpnjnjucPk\nMQo1LhbrbSQyafLHqnODj0osY1fgTX0OnKNTMFEwHQYDVR0OBBYEFNhCSBHW/m2E\naFc9D6a7JI0pgTs8MB8GA1UdIwQYMBaAFNhCSBHW/m2EaFc9D6a7JI0pgTs8MA8G\nA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EA9/RQDBo4SEF1PnY2eSnS1TcK5pL/qQ2y\nnOXOtppCWn8tcnR4or3aIqO+Ie/8nhFQlkwCfSZ9tcc2JuZi2PGDDg==\n-----END CERTIFICATE-----\n"++ }++ ]++}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "machines": [++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.20/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 24000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ },++ {++ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",++ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",++ "address": "192.168.1.21/24",++ "public_ip": "203.0.113.7",++ "port": 50053,++ "free_vram": 12000,++ "free_ram": 32000,++ "hardware": "NVIDIA GeForce RTX 4090",++ "certificate": null++ }++ ]++}@@@ -106348,6 +106348,316 @@}}}++ },++ "bot.machine-pool": {++ "version": "1.0.0",++ "owner": "bot",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/bot/machine-pool.v1.json",++ "title": "BotMachinePool",++ "description": "bot.machine-pool@1 (the pooled machines design, 2026-11-06): several of one owner's machines on the same local network that serve one model together through llama.cpp RPC, `rpc-server` on the members and `llama-server --rpc` on the head. OpenVibe.Network holds the record: the owner proposes it on /machines (POST /api/v1/machine-pools, two to eight of their own machines and an optional head; the default head has the most free VRAM), and each machine reads it with its own node token (GET /api/v1/node/self/pools/:id, network.node.self.manage) and approves it locally (POST /api/v1/node/self/pools/:id/approve with { certificate }). A machine's `certificate` is null until it approves on that machine: the Node generates an Ed25519 key there, keeps the private key, and uploads only its self-signed public certificate, which the other members pin for the pool's private link. A pool with any null certificate never serves. The record never carries a private key or a prompt. What a schema cannot say, Network and Node check at run time: the members are distinct and the head is one of them; every member has the pool's owner, today, through Bot; every member was seen from the same public address with a private address in the same subnet; the head's direct link probe to each member passes; each machine's certificate is its own; and any change of membership, owner, head or key revokes the pool, so all machines approve a new one. A machine that leaves (removed, signed out, a different owner) drops its link and its key at once.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "owner",++ "head",++ "machines"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^pool_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The pool's id (ULID, Crockford base32). A pool is never edited: a change is a new pool with a new id."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The person every machine in the pool belongs to. Pools of different owners are not allowed."++ },++ "head": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine that runs `llama-server --rpc`, sees the prompt and answers; it must be one of `machines`. The others receive tensors only."++ },++ "machines": {++ "type": "array",++ "minItems": 2,++ "maxItems": 8,++ "description": "The members, head included, two to eight.",++ "items": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "id",++ "owner",++ "address",++ "public_ip",++ "port",++ "free_vram",++ "free_ram",++ "hardware",++ "certificate"++ ],++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine's owner when it announced itself; it must equal the pool's owner."++ },++ "address": {++ "type": "string",++ "pattern": "^(10\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])|172\\.(1[6-9]|2[0-9]|3[01])|192\\.168)\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])/([89]|[12][0-9]|30)$",++ "maxLength": 32,++ "description": "The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address."++ },++ "public_ip": {++ "type": "string",++ "maxLength": 45,++ "anyOf": [++ {++ "format": "ipv4"++ },++ {++ "format": "ipv6"++ }++ ],++ "description": "The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head."++ },++ "port": {++ "type": "integer",++ "minimum": 1024,++ "maximum": 65535,++ "description": "The TCP port of the machine's private link on `address`."++ },++ "free_vram": {++ "type": "integer",++ "minimum": 0,++ "maximum": 16777216,++ "description": "Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it."++ },++ "free_ram": {++ "type": "integer",++ "minimum": 0,++ "maximum": 16777216,++ "description": "Free system memory when it announced itself, in MB."++ },++ "hardware": {++ "type": "string",++ "maxLength": 120,++ "description": "A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model."++ },++ "certificate": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 8192,++ "pattern": "^-----BEGIN CERTIFICATE-----",++ "not": {++ "type": "string",++ "pattern": "PRIVATE KEY"++ },++ "description": "The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key."++ }++ }++ }++ }++ }++ }++ },++ "ai.offer-pool": {++ "version": "1.0.0",++ "owner": "ai",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/ai/offer-pool.v1.json",++ "title": "AiOfferPool",++ "description": "ai.offer-pool@1 (the pooled machines design, 2026-11-06): the `pool` part of a community AI offer (ai.offer@1) served by several of one owner's machines together (bot.machine-pool@1). Network adds it from its own approved pool record, never from what a machine reports: the offer is the head's, `head` equals the offer's `machine_id`, and while a machine is in a pool it advertises no offer of its own. It names machines only; no address, key or certificate reaches AI. AI routes the request to the head, runs the same verification as for one machine (canaries, the model fingerprint, spot re-runs) on the pool's answers, keys that verification on this exact membership (another member or head is a new, unverified pool), keeps a pool that is new or failed to the free tier only, and labels its answers \"Community pool (N machines)\".",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "machines",++ "head"++ ],++ "properties": {++ "machines": {++ "type": "array",++ "minItems": 2,++ "maxItems": 8,++ "uniqueItems": true,++ "description": "The pool's machines, head included (Bot device ids), two to eight.",++ "items": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "head": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine that answers: one of `machines`, and the offer's own `machine_id`."++ }++ }++ }++ },++ "ai.offer": {++ "version": "1.0.0",++ "owner": "ai",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/ai/offer.v1.json",++ "title": "AiOffer",++ "description": "ai.offer@1: one community AI offer, a person's machine (OpenVibe.Node's ai plugin, \"Offer to the network\") serving its local models to requests that opt in to community capacity. OpenVibe.Bot reports these fields (POST /internal/ai/offers/report on Network, network.resource.report; a report with any other field is refused whole), and OpenVibe.AI reads them from Network (GET /internal/ai/offers, network.registry.read, { offers, generated_at, count }). Network adds `pool` (ai.offer-pool@1) to the head's offer when the machine is the head of an approved pool (bot.machine-pool@1), and leaves a pool member's own offer out of the list while it is in a pool. For a pool the hours, audience, price, readiness, idle-only and verification apply to the whole pool: it is ready only while every member has approved, renewed its readiness in the last few seconds, and is still the owner's. Nothing here is public: AI shows Exchange a hashed offer id and no owner or machine id.",++ "type": "object",++ "additionalProperties": false,++ "required": [++ "offer_id",++ "machine_id",++ "owner",++ "models",++ "hours",++ "concurrency",++ "price",++ "audience",++ "group",++ "ready",++ "health"++ ],++ "properties": {++ "offer_id": {++ "type": "string",++ "pattern": "^ai:dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "`ai:<machine_id>`: one offer per machine."++ },++ "machine_id": {++ "type": "string",++ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine that answers (for a pool, its head)."++ },++ "owner": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "The machine's owner, who earns the offer's credits (a self-served run earns none)."++ },++ "models": {++ "type": "array",++ "minItems": 1,++ "maxItems": 40,++ "description": "The models offered, as the machine's model server names them.",++ "items": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ }++ },++ "hours": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "start",++ "end",++ "tz"++ ],++ "description": "The local-time window the offer is open; start equal to end is all day, and an overnight window wraps.",++ "properties": {++ "start": {++ "type": "string",++ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"++ },++ "end": {++ "type": "string",++ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"++ },++ "tz": {++ "type": "string",++ "minLength": 1,++ "maxLength": 64,++ "description": "An IANA time zone, such as Europe/Paris, or UTC."++ }++ }++ },++ "concurrency": {++ "type": "integer",++ "minimum": 1,++ "maximum": 8,++ "description": "How many requests may run at once; another is refused as busy, never queued."++ },++ "price": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "in_per_million",++ "out_per_million"++ ],++ "description": "Credits per million input and output tokens; 0 and 0 is a volunteer, who earns kudos. One price for a pool.",++ "properties": {++ "in_per_million": {++ "type": "number",++ "minimum": 0,++ "maximum": 1000000++ },++ "out_per_million": {++ "type": "number",++ "minimum": 0,++ "maximum": 1000000++ }++ }++ },++ "audience": {++ "enum": [++ "everyone",++ "followers",++ "group"++ ],++ "description": "Who may use it: everyone, the owner's followers, or one group (`group`)."++ },++ "group": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 80,++ "description": "The group's id when the audience is `group`, otherwise null."++ },++ "ready": {++ "type": "boolean",++ "description": "Whether the machine (for a pool, every member) can answer now: online, inside its hours, not paused by idle-only or a kill switch."++ },++ "health": {++ "type": "object",++ "additionalProperties": false,++ "required": [++ "status"++ ],++ "properties": {++ "status": {++ "enum": [++ "up",++ "degraded",++ "down"++ ]++ },++ "checked_at": {++ "type": "string",++ "format": "date-time"++ }++ }++ },++ "pool": {++ "$ref": "offer-pool.v1.json",++ "description": "Present when the offer is served by a pool of the owner's machines (ai.offer-pool@1)."++ }++ }++ }}}}@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Actor API",-- "version": "0.308.0",-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.309.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,7 +145,7 @@"service": "network","name": "OpenVibe.Network","origin": "https://openvibe.network",-- "operations": 55,++ "operations": 60,"capabilities": 35},{@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Inventory API",-- "version": "0.308.0",-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.MediaHub API",-- "version": "0.308.0",-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.309.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"@@@ -1004,7 +1004,7 @@"put": {"operationId": "put_api_v1_node_self_capabilities","summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",-- "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's.",++ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.","tags": ["network.node"],@@@ -1043,7 +1043,242 @@"post": {"operationId": "post_api_v1_node_self_credential","summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",-- "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's.",++ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",++ "tags": [++ "network.node"++ ],++ "x-openvibe-capabilities": [++ "network.node.self.manage"++ ],++ "x-openvibe-visibility": [++ "internal"++ ],++ "x-openvibe-quota-class": "admin",++ "security": [++ {++ "openvibeToken": [++ "network.node.self.manage"++ ]++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success"++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/node/self/pools/{id}": {++ "get": {++ "operationId": "get_api_v1_node_self_pools_id",++ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",++ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",++ "tags": [++ "network.node"++ ],++ "x-openvibe-capabilities": [++ "network.node.self.manage"++ ],++ "x-openvibe-visibility": [++ "internal"++ ],++ "x-openvibe-quota-class": "admin",++ "security": [++ {++ "openvibeToken": [++ "network.node.self.manage"++ ]++ }++ ],++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success"++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/node/self/pools/{id}/approve": {++ "post": {++ "operationId": "post_api_v1_node_self_pools_id_approve",++ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",++ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",++ "tags": [++ "network.node"++ ],++ "x-openvibe-capabilities": [++ "network.node.self.manage"++ ],++ "x-openvibe-visibility": [++ "internal"++ ],++ "x-openvibe-quota-class": "admin",++ "security": [++ {++ "openvibeToken": [++ "network.node.self.manage"++ ]++ }++ ],++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success"++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/node/self/pools/{id}/leave": {++ "post": {++ "operationId": "post_api_v1_node_self_pools_id_leave",++ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",++ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",++ "tags": [++ "network.node"++ ],++ "x-openvibe-capabilities": [++ "network.node.self.manage"++ ],++ "x-openvibe-visibility": [++ "internal"++ ],++ "x-openvibe-quota-class": "admin",++ "security": [++ {++ "openvibeToken": [++ "network.node.self.manage"++ ]++ }++ ],++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success"++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/node/self/pools/{id}/status": {++ "post": {++ "operationId": "post_api_v1_node_self_pools_id_status",++ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",++ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",++ "tags": [++ "network.node"++ ],++ "x-openvibe-capabilities": [++ "network.node.self.manage"++ ],++ "x-openvibe-visibility": [++ "internal"++ ],++ "x-openvibe-quota-class": "admin",++ "security": [++ {++ "openvibeToken": [++ "network.node.self.manage"++ ]++ }++ ],++ "parameters": [++ {++ "name": "id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success"++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },++ "/api/v1/node/self/pools/announce": {++ "post": {++ "operationId": "post_api_v1_node_self_pools_announce",++ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",++ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.","tags": ["network.node"],@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.News API",-- "version": "0.308.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.309.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"@@@ -295149,3 +295149,1743 @@ export interface ChatParty {created_at: string;ended_at?: string | null;}++++/** [email protected] (owner: bot) */++/**++ * bot.machine-pool@1 (the pooled machines design, 2026-11-06): several of one owner's machines on the same local network that serve one model together through llama.cpp RPC, `rpc-server` on the members and `llama-server --rpc` on the head. OpenVibe.Network holds the record: the owner proposes it on /machines (POST /api/v1/machine-pools, two to eight of their own machines and an optional head; the default head has the most free VRAM), and each machine reads it with its own node token (GET /api/v1/node/self/pools/:id, network.node.self.manage) and approves it locally (POST /api/v1/node/self/pools/:id/approve with { certificate }). A machine's `certificate` is null until it approves on that machine: the Node generates an Ed25519 key there, keeps the private key, and uploads only its self-signed public certificate, which the other members pin for the pool's private link. A pool with any null certificate never serves. The record never carries a private key or a prompt. What a schema cannot say, Network and Node check at run time: the members are distinct and the head is one of them; every member has the pool's owner, today, through Bot; every member was seen from the same public address with a private address in the same subnet; the head's direct link probe to each member passes; each machine's certificate is its own; and any change of membership, owner, head or key revokes the pool, so all machines approve a new one. A machine that leaves (removed, signed out, a different owner) drops its link and its key at once.++ */++export interface BotMachinePool {++ /**++ * The pool's id (ULID, Crockford base32). A pool is never edited: a change is a new pool with a new id.++ */++ id: string;++ /**++ * The person every machine in the pool belongs to. Pools of different owners are not allowed.++ */++ owner: string;++ /**++ * The machine that runs `llama-server --rpc`, sees the prompt and answers; it must be one of `machines`. The others receive tensors only.++ */++ head: string;++ /**++ * The members, head included, two to eight.++ *++ * @minItems 2++ * @maxItems 8++ */++ machines:++ | [++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ }++ ]++ | [++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ }++ ]++ | [++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ }++ ]++ | [++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ }++ ]++ | [++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ }++ ]++ | [++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ }++ ]++ | [++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ },++ {++ /**++ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.++ */++ id: string;++ /**++ * The machine's owner when it announced itself; it must equal the pool's owner.++ */++ owner: string;++ /**++ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.++ */++ address: string;++ /**++ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.++ */++ public_ip: (++ | {++ [k: string]: unknown | undefined;++ }++ | {++ [k: string]: unknown | undefined;++ }++ ) &++ string;++ /**++ * The TCP port of the machine's private link on `address`.++ */++ port: number;++ /**++ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.++ */++ free_vram: number;++ /**++ * Free system memory when it announced itself, in MB.++ */++ free_ram: number;++ /**++ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.++ */++ hardware: string;++ /**++ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.++ */++ certificate: string | null;++ }++ ];++}++++/** [email protected] (owner: ai) */++/**++ * ai.offer-pool@1 (the pooled machines design, 2026-11-06): the `pool` part of a community AI offer (ai.offer@1) served by several of one owner's machines together (bot.machine-pool@1). Network adds it from its own approved pool record, never from what a machine reports: the offer is the head's, `head` equals the offer's `machine_id`, and while a machine is in a pool it advertises no offer of its own. It names machines only; no address, key or certificate reaches AI. AI routes the request to the head, runs the same verification as for one machine (canaries, the model fingerprint, spot re-runs) on the pool's answers, keys that verification on this exact membership (another member or head is a new, unverified pool), keeps a pool that is new or failed to the free tier only, and labels its answers "Community pool (N machines)".++ */++export interface AiOfferPool {++ /**++ * The pool's machines, head included (Bot device ids), two to eight.++ *++ * @minItems 2++ * @maxItems 8++ */++ machines:++ | [string, string]++ | [string, string, string]++ | [string, string, string, string]++ | [string, string, string, string, string]++ | [string, string, string, string, string, string]++ | [string, string, string, string, string, string, string]++ | [string, string, string, string, string, string, string, string];++ /**++ * The machine that answers: one of `machines`, and the offer's own `machine_id`.++ */++ head: string;++}++++/** [email protected] (owner: ai) */++/**++ * ai.offer@1: one community AI offer, a person's machine (OpenVibe.Node's ai plugin, "Offer to the network") serving its local models to requests that opt in to community capacity. OpenVibe.Bot reports these fields (POST /internal/ai/offers/report on Network, network.resource.report; a report with any other field is refused whole), and OpenVibe.AI reads them from Network (GET /internal/ai/offers, network.registry.read, { offers, generated_at, count }). Network adds `pool` (ai.offer-pool@1) to the head's offer when the machine is the head of an approved pool (bot.machine-pool@1), and leaves a pool member's own offer out of the list while it is in a pool. For a pool the hours, audience, price, readiness, idle-only and verification apply to the whole pool: it is ready only while every member has approved, renewed its readiness in the last few seconds, and is still the owner's. Nothing here is public: AI shows Exchange a hashed offer id and no owner or machine id.++ */++export interface AiOffer {++ /**++ * `ai:<machine_id>`: one offer per machine.++ */++ offer_id: string;++ /**++ * The machine that answers (for a pool, its head).++ */++ machine_id: string;++ /**++ * The machine's owner, who earns the offer's credits (a self-served run earns none).++ */++ owner: string;++ /**++ * The models offered, as the machine's model server names them.++ *++ * @minItems 1++ * @maxItems 40++ */++ models: [string, ...string[]];++ /**++ * The local-time window the offer is open; start equal to end is all day, and an overnight window wraps.++ */++ hours: {++ start: string;++ end: string;++ /**++ * An IANA time zone, such as Europe/Paris, or UTC.++ */++ tz: string;++ };++ /**++ * How many requests may run at once; another is refused as busy, never queued.++ */++ concurrency: number;++ /**++ * Credits per million input and output tokens; 0 and 0 is a volunteer, who earns kudos. One price for a pool.++ */++ price: {++ in_per_million: number;++ out_per_million: number;++ };++ /**++ * Who may use it: everyone, the owner's followers, or one group (`group`).++ */++ audience: "everyone" | "followers" | "group";++ /**++ * The group's id when the audience is `group`, otherwise null.++ */++ group: string | null;++ /**++ * Whether the machine (for a pool, every member) can answer now: online, inside its hours, not paused by idle-only or a kill switch.++ */++ ready: boolean;++ health: {++ status: "up" | "degraded" | "down";++ checked_at?: string;++ };++ pool?: AiOfferPool;++}@@@ -4,7 +4,7 @@"owner": "network","status": "active","visibility": "internal",-- "description": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",++ "description": "A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.","permissions": ["nodes:self"],@@@ -15,6 +15,11 @@"events": [],"implementedBy": ["PUT /api/v1/node/self/capabilities",-- "POST /api/v1/node/self/credential"++ "POST /api/v1/node/self/credential",++ "POST /api/v1/node/self/pools/announce",++ "GET /api/v1/node/self/pools/:id",++ "POST /api/v1/node/self/pools/:id/approve",++ "POST /api/v1/node/self/pools/:id/status",++ "POST /api/v1/node/self/pools/:id/leave"]}@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.308.0",++ "version": "0.309.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.308.0",++ "version": "0.309.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.308.0",++ "version": "0.309.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",@@@ -12,8 +12,9 @@ const pkg = require(path.join(ROOT, 'package.json'));const versions = [...text.matchAll(/^## (\d+)\.(\d+)\.(\d+)\b/gm)].map((m) => [+m[1], +m[2], +m[3]]);const [major, minor] = pkg.version.split('.').map(Number);--// Minor versions that were never released (no tag), so they have no entry. 306 is the pooled-machines branch (it--// carries its own 0.306.0 entry and has not merged); 307 is reserved by work in flight, so Memory M5 takes 308.++// Minor versions that were never released (no tag), so they have no entry. 306 and 307 were reserved for the pooled++// machines and consent branches, which merged after Memory M5 took 308: they became 0.309.0 and 0.310.0, and the two++// numbers stay unused (a tag below the newest one would read as a downgrade to the pin bot).const NEVER_RELEASED = new Set([293, 306, 307]);const FIRST_MINOR = 30;
@@ -1,5 +1,14 @@
@@ -1,5 +1,14 @@
# Changelog
# Changelog
+## 0.309.0 — 2026-11-07
+
+- Add `bot.machine-pool@1` (the pooled machines design, 2026-11-06): several of one owner's machines on the same local network that serve one model together through llama.cpp RPC (`rpc-server` on the members, `llama-server --rpc` on the head). OpenVibe.Network holds the record: the owner proposes it on /machines with two to eight of their own machines (the default head has the most free VRAM), and each machine reads it with its own node token and approves it on itself. A member's `certificate` is null until it approves; then it is that machine's self-signed Ed25519 public certificate, which the other members pin for the pool's private link. The private key stays on the machine: a certificate slot holding anything with `PRIVATE KEY` in it is refused, and so is any field the schema does not name. A member's `address` is a private RFC 1918 address and prefix (never 0.0.0.0, loopback or a public address) and its `public_ip` is the address Network saw it from. The rules a schema cannot say are written in the description and checked by Network and Node: the head is a member, every member is the owner's today, all share one public address and one private subnet, the head's direct link probe to each passes, every key is its own, and any change of membership, owner, head or key revokes the pool so every machine approves a new one.
+- Add `ai.offer@1`: one community AI offer as Bot reports it to Network and AI reads it back (the fields Network already stores: machine, owner, models, hours, concurrency, credit price, audience, readiness and health), with the new optional `pool`.
+- Add `ai.offer-pool@1`, the `pool` part of the AI offer: `{ machines, head }`, two to eight machine ids and the head, which is the offer's own machine. Network adds it from its approved pool record, never from what a machine reports, and leaves a member's own offer out while it is in a pool. It names machines only: no address, key or certificate reaches AI. One price, audience, hours, idle-only and verification apply to the whole pool; AI verifies a pool's answers as it would one machine's, keys that verification on the exact membership, keeps a new or failed pool to the free tier only, and labels it "Community pool (N machines)".
+- `network.node.self.manage` names the five pool routes a machine calls with its own token (announce, read, approve, renew readiness, leave) in `implementedBy`.
+- Valid and invalid fixtures cover a pool waiting for approvals, an approved pool of three, a single-machine offer, a pool's offer and one still waiting, a group offer, a missing head or owner, a one-machine pool, a repeated member, a private key in the certificate slot, a public, loopback or wildcard address, a port under 1024, and an address, certificate or key smuggled into a field the schema does not name.
+
+
## 0.308.0 — 2026-11-07
## 0.308.0 — 2026-11-07
- Add `ai.memory-export@1` (Memory M5): the one portable memory file. It carries `format: openvibe.memory-export@1`, `version: 1`, `exported_at` and every item's text, kind, scope, source, confidence and source reference. It deliberately has no ids, owners, merge links or conflict pair, so a file can be imported into another account without carrying anyone's identity, and a profile is derived from the items and rebuilt, never imported. OpenVibe.AI's `GET /api/v1/memory/export` writes it and `POST /api/v1/memory/import` accepts the same document; both redact again.
- Add `ai.memory-export@1` (Memory M5): the one portable memory file. It carries `format: openvibe.memory-export@1`, `version: 1`, `exported_at` and every item's text, kind, scope, source, confidence and source reference. It deliberately has no ids, owners, merge links or conflict pair, so a file can be imported into another account without carrying anyone's identity, and a profile is derived from the items and rebuilt, never imported. OpenVibe.AI's `GET /api/v1/memory/export` writes it and `POST /api/v1/memory/import` accepts the same document; both redact again.
@@ -11,6 +11,7 @@
@@ -11,6 +11,7 @@
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
"contracts": "openvibe-contracts (this package: package.json's version, released as the matching tag)",
"contracts": "openvibe-contracts (this package: package.json's version, released as the matching tag)",
"features": [
"features": [
+ "bot.machine-pool@1, ai.offer@1 and ai.offer-pool@1 (the pooled machines design): several of one owner's machines on one local network serving one model through llama.cpp RPC, each approving on itself with its own public certificate, and the community AI offer with the pool part Network adds to the head's offer",
"chat.play-request@1 and codes.sandbox-session@1 (the Agent Streams plan, S6): the queue a chat plays room keeps and the sandbox desk that works it, with the owner's time box, cap and Go, and the scratch site that lives 24 hours",
"chat.play-request@1 and codes.sandbox-session@1 (the Agent Streams plan, S6): the queue a chat plays room keeps and the sandbox desk that works it, with the owner's time box, cap and Go, and the scratch site that lives 24 hours",
"the capabilities chat.play_queue.read and chat.play_queue.write, for Codes acting for the stream's owner",
"the capabilities chat.play_queue.read and chat.play_queue.write, for Codes acting for the stream's owner",
"chat.agent-digest@1, chat.agent-poll@1 and live.agent-stream-control@1 (the Agent Streams plan, S5): the digest a Co-pilot room gives an agent, the poll an agent asks that room to run, and the four controls the owner and the moderators have over a live agent stream",
"chat.agent-digest@1, chat.agent-poll@1 and live.agent-stream-control@1 (the Agent Streams plan, S5): the digest a Co-pilot room gives an agent, the poll an agent asks that room to run, and the four controls the owner and the moderators have over a live agent stream",
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/ai/offer-pool.v1.json",
+ "title": "AiOfferPool",
+ "description": "ai.offer-pool@1 (the pooled machines design, 2026-11-06): the `pool` part of a community AI offer (ai.offer@1) served by several of one owner's machines together (bot.machine-pool@1). Network adds it from its own approved pool record, never from what a machine reports: the offer is the head's, `head` equals the offer's `machine_id`, and while a machine is in a pool it advertises no offer of its own. It names machines only; no address, key or certificate reaches AI. AI routes the request to the head, runs the same verification as for one machine (canaries, the model fingerprint, spot re-runs) on the pool's answers, keys that verification on this exact membership (another member or head is a new, unverified pool), keeps a pool that is new or failed to the free tier only, and labels its answers \"Community pool (N machines)\".",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "machines",
+ "head"
+ ],
+ "properties": {
+ "machines": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 8,
+ "uniqueItems": true,
+ "description": "The pool's machines, head included (Bot device ids), two to eight.",
+ "items": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "head": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine that answers: one of `machines`, and the offer's own `machine_id`."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,146 @@
@@ -0,0 +1,146 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/ai/offer.v1.json",
+ "title": "AiOffer",
+ "description": "ai.offer@1: one community AI offer, a person's machine (OpenVibe.Node's ai plugin, \"Offer to the network\") serving its local models to requests that opt in to community capacity. OpenVibe.Bot reports these fields (POST /internal/ai/offers/report on Network, network.resource.report; a report with any other field is refused whole), and OpenVibe.AI reads them from Network (GET /internal/ai/offers, network.registry.read, { offers, generated_at, count }). Network adds `pool` (ai.offer-pool@1) to the head's offer when the machine is the head of an approved pool (bot.machine-pool@1), and leaves a pool member's own offer out of the list while it is in a pool. For a pool the hours, audience, price, readiness, idle-only and verification apply to the whole pool: it is ready only while every member has approved, renewed its readiness in the last few seconds, and is still the owner's. Nothing here is public: AI shows Exchange a hashed offer id and no owner or machine id.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "offer_id",
+ "machine_id",
+ "owner",
+ "models",
+ "hours",
+ "concurrency",
+ "price",
+ "audience",
+ "group",
+ "ready",
+ "health"
+ ],
+ "properties": {
+ "offer_id": {
+ "type": "string",
+ "pattern": "^ai:dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "`ai:<machine_id>`: one offer per machine."
+ },
+ "machine_id": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine that answers (for a pool, its head)."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine's owner, who earns the offer's credits (a self-served run earns none)."
+ },
+ "models": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 40,
+ "description": "The models offered, as the machine's model server names them.",
+ "items": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ }
+ },
+ "hours": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "start",
+ "end",
+ "tz"
+ ],
+ "description": "The local-time window the offer is open; start equal to end is all day, and an overnight window wraps.",
+ "properties": {
+ "start": {
+ "type": "string",
+ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
+ },
+ "end": {
+ "type": "string",
+ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
+ },
+ "tz": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "description": "An IANA time zone, such as Europe/Paris, or UTC."
+ }
+ }
+ },
+ "concurrency": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 8,
+ "description": "How many requests may run at once; another is refused as busy, never queued."
+ },
+ "price": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "in_per_million",
+ "out_per_million"
+ ],
+ "description": "Credits per million input and output tokens; 0 and 0 is a volunteer, who earns kudos. One price for a pool.",
+ "properties": {
+ "in_per_million": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 1000000
+ },
+ "out_per_million": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 1000000
+ }
+ }
+ },
+ "audience": {
+ "enum": [
+ "everyone",
+ "followers",
+ "group"
+ ],
+ "description": "Who may use it: everyone, the owner's followers, or one group (`group`)."
+ },
+ "group": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 80,
+ "description": "The group's id when the audience is `group`, otherwise null."
+ },
+ "ready": {
+ "type": "boolean",
+ "description": "Whether the machine (for a pool, every member) can answer now: online, inside its hours, not paused by idle-only or a kill switch."
+ },
+ "health": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status"
+ ],
+ "properties": {
+ "status": {
+ "enum": [
+ "up",
+ "degraded",
+ "down"
+ ]
+ },
+ "checked_at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ },
+ "pool": {
+ "$ref": "offer-pool.v1.json",
+ "description": "Present when the offer is served by a pool of the owner's machines (ai.offer-pool@1)."
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,119 @@
@@ -0,0 +1,119 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/bot/machine-pool.v1.json",
+ "title": "BotMachinePool",
+ "description": "bot.machine-pool@1 (the pooled machines design, 2026-11-06): several of one owner's machines on the same local network that serve one model together through llama.cpp RPC, `rpc-server` on the members and `llama-server --rpc` on the head. OpenVibe.Network holds the record: the owner proposes it on /machines (POST /api/v1/machine-pools, two to eight of their own machines and an optional head; the default head has the most free VRAM), and each machine reads it with its own node token (GET /api/v1/node/self/pools/:id, network.node.self.manage) and approves it locally (POST /api/v1/node/self/pools/:id/approve with { certificate }). A machine's `certificate` is null until it approves on that machine: the Node generates an Ed25519 key there, keeps the private key, and uploads only its self-signed public certificate, which the other members pin for the pool's private link. A pool with any null certificate never serves. The record never carries a private key or a prompt. What a schema cannot say, Network and Node check at run time: the members are distinct and the head is one of them; every member has the pool's owner, today, through Bot; every member was seen from the same public address with a private address in the same subnet; the head's direct link probe to each member passes; each machine's certificate is its own; and any change of membership, owner, head or key revokes the pool, so all machines approve a new one. A machine that leaves (removed, signed out, a different owner) drops its link and its key at once.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "owner",
+ "head",
+ "machines"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^pool_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The pool's id (ULID, Crockford base32). A pool is never edited: a change is a new pool with a new id."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The person every machine in the pool belongs to. Pools of different owners are not allowed."
+ },
+ "head": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine that runs `llama-server --rpc`, sees the prompt and answers; it must be one of `machines`. The others receive tensors only."
+ },
+ "machines": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 8,
+ "description": "The members, head included, two to eight.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "owner",
+ "address",
+ "public_ip",
+ "port",
+ "free_vram",
+ "free_ram",
+ "hardware",
+ "certificate"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine's owner when it announced itself; it must equal the pool's owner."
+ },
+ "address": {
+ "type": "string",
+ "pattern": "^(10\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])|172\\.(1[6-9]|2[0-9]|3[01])|192\\.168)\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])/([89]|[12][0-9]|30)$",
+ "maxLength": 32,
+ "description": "The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address."
+ },
+ "public_ip": {
+ "type": "string",
+ "maxLength": 45,
+ "anyOf": [
+ {
+ "format": "ipv4"
+ },
+ {
+ "format": "ipv6"
+ }
+ ],
+ "description": "The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head."
+ },
+ "port": {
+ "type": "integer",
+ "minimum": 1024,
+ "maximum": 65535,
+ "description": "The TCP port of the machine's private link on `address`."
+ },
+ "free_vram": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 16777216,
+ "description": "Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it."
+ },
+ "free_ram": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 16777216,
+ "description": "Free system memory when it announced itself, in MB."
+ },
+ "hardware": {
+ "type": "string",
+ "maxLength": 120,
+ "description": "A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model."
+ },
+ "certificate": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 8192,
+ "pattern": "^-----BEGIN CERTIFICATE-----",
+ "not": {
+ "type": "string",
+ "pattern": "PRIVATE KEY"
+ },
+ "description": "The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key."
+ }
+ }
+ }
+ }
+ }
+}
@@ -9636,6 +9636,33 @@
@@ -9636,6 +9636,33 @@
"visibility": "first-party",
"visibility": "first-party",
"compatibility": "backward",
"compatibility": "backward",
"status": "active"
"status": "active"
+ },
+ {
+ "id": "bot.machine-pool",
+ "version": "1.0.0",
+ "owner": "bot",
+ "schema": "bot/machine-pool.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "ai.offer-pool",
+ "version": "1.0.0",
+ "owner": "ai",
+ "schema": "ai/offer-pool.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
+ },
+ {
+ "id": "ai.offer",
+ "version": "1.0.0",
+ "owner": "ai",
+ "schema": "ai/offer.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active"
}
}
]
]
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "address": "192.168.1.20/24"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+{
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "certificates": [
+ "-----BEGIN CERTIFICATE-----\nMIIBRDCB96ADAgECAhQ1F6qS8nQmfA4Z1EQWbuTK6c+/CDAFBgMrZXAwGDEWMBQG\nA1UEAwwNT3BlblZpYmUtcG9vbDAeFw0yNjExMDcwMjE1NThaFw0zNjExMDQwMjE1\nNThaMBgxFjAUBgNVBAMMDU9wZW5WaWJlLXBvb2wwKjAFBgMrZXADIQBzzRaEd6ZR\nqYbsbYK3W8CCJPIAbsNTlIXZYgPEC9yf76NTMFEwHQYDVR0OBBYEFPiGTnP9vRST\nUlo0W1Eh0xcOxA49MB8GA1UdIwQYMBaAFPiGTnP9vRSTUlo0W1Eh0xcOxA49MA8G\nA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EAOlCHoX3ONMZYTHx4GSAlxP4EQase+99L\nGykZvgPSVDs2alKLXW5fBxvn7OcEJ3g/EMmk9iZ+AL+CmLxdcYBLCw==\n-----END CERTIFICATE-----\n"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
+{
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
+{
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D3"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
+{
+ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "models": [
+ "llama-3.3-70b-instruct-q4_k_m"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "everyone",
+ "group": null,
+ "ready": true,
+ "health": {
+ "status": "up",
+ "checked_at": "2026-11-07T10:00:00.000Z"
+ },
+ "pool": {
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+ },
+ "private_key": "not-permitted"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
+{
+ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "models": [
+ "llama-3.3-70b-instruct-q4_k_m"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "everyone",
+ "group": null,
+ "ready": true,
+ "health": {
+ "status": "up",
+ "checked_at": "2026-11-07T10:00:00.000Z"
+ },
+ "pool": {
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "offer_id": "ai:everything",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "models": [
+ "qwen3:8b"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "everyone",
+ "group": null,
+ "ready": true,
+ "health": {
+ "status": "up",
+ "checked_at": "2026-11-07T10:00:00.000Z"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
+{
+ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "models": [
+ "llama-3.3-70b-instruct-q4_k_m"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "everyone",
+ "group": null,
+ "ready": true,
+ "health": {
+ "status": "up",
+ "checked_at": "2026-11-07T10:00:00.000Z"
+ },
+ "pool": {
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
+{
+ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "models": [
+ "llama-3.3-70b-instruct-q4_k_m"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "everyone",
+ "group": null,
+ "ready": true,
+ "health": {
+ "status": "up",
+ "checked_at": "2026-11-07T10:00:00.000Z"
+ },
+ "pool": {
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "address": "192.168.1.20/24"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "models": [
+ "qwen3:8b"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "group",
+ "group": "grp_friends",
+ "ready": true,
+ "health": {
+ "status": "up",
+ "checked_at": "2026-11-07T10:00:00.000Z"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
+{
+ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "models": [
+ "llama-3.3-70b-instruct-q4_k_m"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "everyone",
+ "group": null,
+ "ready": false,
+ "health": {
+ "status": "down"
+ },
+ "pool": {
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
+{
+ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "models": [
+ "llama-3.3-70b-instruct-q4_k_m"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "everyone",
+ "group": null,
+ "ready": true,
+ "health": {
+ "status": "up",
+ "checked_at": "2026-11-07T10:00:00.000Z"
+ },
+ "pool": {
+ "machines": [
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2"
+ ],
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "offer_id": "ai:dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machine_id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "models": [
+ "qwen3:8b"
+ ],
+ "hours": {
+ "start": "22:00",
+ "end": "08:00",
+ "tz": "Europe/Paris"
+ },
+ "concurrency": 1,
+ "price": {
+ "in_per_million": 0.2,
+ "out_per_million": 0.6
+ },
+ "audience": "everyone",
+ "group": null,
+ "ready": true,
+ "health": {
+ "status": "up",
+ "checked_at": "2026-11-07T10:00:00.000Z"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.21/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ }
+ ],
+ "private_key": "not-permitted"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "127.0.0.1/8",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.21/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null,
+ "node_credential": "not-permitted"
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.21/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.21/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": "-----BEGIN CERTIFICATE-----\nthe PRIVATE KEY pasted here by mistake\n-----END CERTIFICATE-----\n"
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.21/24",
+ "public_ip": "203.0.113.7",
+ "port": 80,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "8.8.8.8/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "0.0.0.0/0",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": "-----BEGIN CERTIFICATE-----\nMIIBRDCB96ADAgECAhQ1F6qS8nQmfA4Z1EQWbuTK6c+/CDAFBgMrZXAwGDEWMBQG\nA1UEAwwNT3BlblZpYmUtcG9vbDAeFw0yNjExMDcwMjE1NThaFw0zNjExMDQwMjE1\nNThaMBgxFjAUBgNVBAMMDU9wZW5WaWJlLXBvb2wwKjAFBgMrZXADIQBzzRaEd6ZR\nqYbsbYK3W8CCJPIAbsNTlIXZYgPEC9yf76NTMFEwHQYDVR0OBBYEFPiGTnP9vRST\nUlo0W1Eh0xcOxA49MB8GA1UdIwQYMBaAFPiGTnP9vRSTUlo0W1Eh0xcOxA49MA8G\nA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EAOlCHoX3ONMZYTHx4GSAlxP4EQase+99L\nGykZvgPSVDs2alKLXW5fBxvn7OcEJ3g/EMmk9iZ+AL+CmLxdcYBLCw==\n-----END CERTIFICATE-----\n"
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.21/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": "-----BEGIN CERTIFICATE-----\nMIIBRDCB96ADAgECAhRrJ/6HQgidfd9Sah9rLZOC0022ejAFBgMrZXAwGDEWMBQG\nA1UEAwwNT3BlblZpYmUtcG9vbDAeFw0yNjExMDcwMjE2MjRaFw0zNjExMDQwMjE2\nMjRaMBgxFjAUBgNVBAMMDU9wZW5WaWJlLXBvb2wwKjAFBgMrZXADIQBIJ8mF2e9W\nbILuPZQVwA2/LgC2VFtQAnpPDXExV2jXYaNTMFEwHQYDVR0OBBYEFKi5Za/SzebG\nkYOs4rzWz72zsM55MB8GA1UdIwQYMBaAFKi5Za/SzebGkYOs4rzWz72zsM55MA8G\nA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EAtZp/I6vCQ72SrCrQeH4QCz+sXqwnn24U\np9v1GeWXRE26rNmM3/ZQ4J9Vqmb/inSL5fMSKw9MJG+yZMShheRiDA==\n-----END CERTIFICATE-----\n"
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D3",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.22/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 8000,
+ "free_ram": 32000,
+ "hardware": "x86_64",
+ "certificate": "-----BEGIN CERTIFICATE-----\nMIIBRDCB96ADAgECAhQqwkAcayM2me9QLHZC1hfsr6SzhTAFBgMrZXAwGDEWMBQG\nA1UEAwwNT3BlblZpYmUtcG9vbDAeFw0yNjExMDcwMjE2MjRaFw0zNjExMDQwMjE2\nMjRaMBgxFjAUBgNVBAMMDU9wZW5WaWJlLXBvb2wwKjAFBgMrZXADIQDpnjnjucPk\nMQo1LhbrbSQyafLHqnODj0osY1fgTX0OnKNTMFEwHQYDVR0OBBYEFNhCSBHW/m2E\naFc9D6a7JI0pgTs8MB8GA1UdIwQYMBaAFNhCSBHW/m2EaFc9D6a7JI0pgTs8MA8G\nA1UdEwEB/wQFMAMBAf8wBQYDK2VwA0EA9/RQDBo4SEF1PnY2eSnS1TcK5pL/qQ2y\nnOXOtppCWn8tcnR4or3aIqO+Ie/8nhFQlkwCfSZ9tcc2JuZi2PGDDg==\n-----END CERTIFICATE-----\n"
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "id": "pool_01J8Z3Q4R5S6T7V8W9X0Y1Z2P1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "head": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "machines": [
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D1",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.20/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 24000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ },
+ {
+ "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2D2",
+ "owner": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A1",
+ "address": "192.168.1.21/24",
+ "public_ip": "203.0.113.7",
+ "port": 50053,
+ "free_vram": 12000,
+ "free_ram": 32000,
+ "hardware": "NVIDIA GeForce RTX 4090",
+ "certificate": null
+ }
+ ]
+}
@@ -106348,6 +106348,316 @@
@@ -106348,6 +106348,316 @@
}
}
}
}
}
}
+ },
+ "bot.machine-pool": {
+ "version": "1.0.0",
+ "owner": "bot",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/bot/machine-pool.v1.json",
+ "title": "BotMachinePool",
+ "description": "bot.machine-pool@1 (the pooled machines design, 2026-11-06): several of one owner's machines on the same local network that serve one model together through llama.cpp RPC, `rpc-server` on the members and `llama-server --rpc` on the head. OpenVibe.Network holds the record: the owner proposes it on /machines (POST /api/v1/machine-pools, two to eight of their own machines and an optional head; the default head has the most free VRAM), and each machine reads it with its own node token (GET /api/v1/node/self/pools/:id, network.node.self.manage) and approves it locally (POST /api/v1/node/self/pools/:id/approve with { certificate }). A machine's `certificate` is null until it approves on that machine: the Node generates an Ed25519 key there, keeps the private key, and uploads only its self-signed public certificate, which the other members pin for the pool's private link. A pool with any null certificate never serves. The record never carries a private key or a prompt. What a schema cannot say, Network and Node check at run time: the members are distinct and the head is one of them; every member has the pool's owner, today, through Bot; every member was seen from the same public address with a private address in the same subnet; the head's direct link probe to each member passes; each machine's certificate is its own; and any change of membership, owner, head or key revokes the pool, so all machines approve a new one. A machine that leaves (removed, signed out, a different owner) drops its link and its key at once.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "owner",
+ "head",
+ "machines"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^pool_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The pool's id (ULID, Crockford base32). A pool is never edited: a change is a new pool with a new id."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The person every machine in the pool belongs to. Pools of different owners are not allowed."
+ },
+ "head": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine that runs `llama-server --rpc`, sees the prompt and answers; it must be one of `machines`. The others receive tensors only."
+ },
+ "machines": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 8,
+ "description": "The members, head included, two to eight.",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "owner",
+ "address",
+ "public_ip",
+ "port",
+ "free_vram",
+ "free_ram",
+ "hardware",
+ "certificate"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine's owner when it announced itself; it must equal the pool's owner."
+ },
+ "address": {
+ "type": "string",
+ "pattern": "^(10\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])|172\\.(1[6-9]|2[0-9]|3[01])|192\\.168)\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])/([89]|[12][0-9]|30)$",
+ "maxLength": 32,
+ "description": "The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address."
+ },
+ "public_ip": {
+ "type": "string",
+ "maxLength": 45,
+ "anyOf": [
+ {
+ "format": "ipv4"
+ },
+ {
+ "format": "ipv6"
+ }
+ ],
+ "description": "The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head."
+ },
+ "port": {
+ "type": "integer",
+ "minimum": 1024,
+ "maximum": 65535,
+ "description": "The TCP port of the machine's private link on `address`."
+ },
+ "free_vram": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 16777216,
+ "description": "Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it."
+ },
+ "free_ram": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 16777216,
+ "description": "Free system memory when it announced itself, in MB."
+ },
+ "hardware": {
+ "type": "string",
+ "maxLength": 120,
+ "description": "A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model."
+ },
+ "certificate": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 8192,
+ "pattern": "^-----BEGIN CERTIFICATE-----",
+ "not": {
+ "type": "string",
+ "pattern": "PRIVATE KEY"
+ },
+ "description": "The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key."
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "ai.offer-pool": {
+ "version": "1.0.0",
+ "owner": "ai",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/ai/offer-pool.v1.json",
+ "title": "AiOfferPool",
+ "description": "ai.offer-pool@1 (the pooled machines design, 2026-11-06): the `pool` part of a community AI offer (ai.offer@1) served by several of one owner's machines together (bot.machine-pool@1). Network adds it from its own approved pool record, never from what a machine reports: the offer is the head's, `head` equals the offer's `machine_id`, and while a machine is in a pool it advertises no offer of its own. It names machines only; no address, key or certificate reaches AI. AI routes the request to the head, runs the same verification as for one machine (canaries, the model fingerprint, spot re-runs) on the pool's answers, keys that verification on this exact membership (another member or head is a new, unverified pool), keeps a pool that is new or failed to the free tier only, and labels its answers \"Community pool (N machines)\".",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "machines",
+ "head"
+ ],
+ "properties": {
+ "machines": {
+ "type": "array",
+ "minItems": 2,
+ "maxItems": 8,
+ "uniqueItems": true,
+ "description": "The pool's machines, head included (Bot device ids), two to eight.",
+ "items": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "head": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine that answers: one of `machines`, and the offer's own `machine_id`."
+ }
+ }
+ }
+ },
+ "ai.offer": {
+ "version": "1.0.0",
+ "owner": "ai",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/ai/offer.v1.json",
+ "title": "AiOffer",
+ "description": "ai.offer@1: one community AI offer, a person's machine (OpenVibe.Node's ai plugin, \"Offer to the network\") serving its local models to requests that opt in to community capacity. OpenVibe.Bot reports these fields (POST /internal/ai/offers/report on Network, network.resource.report; a report with any other field is refused whole), and OpenVibe.AI reads them from Network (GET /internal/ai/offers, network.registry.read, { offers, generated_at, count }). Network adds `pool` (ai.offer-pool@1) to the head's offer when the machine is the head of an approved pool (bot.machine-pool@1), and leaves a pool member's own offer out of the list while it is in a pool. For a pool the hours, audience, price, readiness, idle-only and verification apply to the whole pool: it is ready only while every member has approved, renewed its readiness in the last few seconds, and is still the owner's. Nothing here is public: AI shows Exchange a hashed offer id and no owner or machine id.",
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "offer_id",
+ "machine_id",
+ "owner",
+ "models",
+ "hours",
+ "concurrency",
+ "price",
+ "audience",
+ "group",
+ "ready",
+ "health"
+ ],
+ "properties": {
+ "offer_id": {
+ "type": "string",
+ "pattern": "^ai:dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "`ai:<machine_id>`: one offer per machine."
+ },
+ "machine_id": {
+ "type": "string",
+ "pattern": "^dev_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine that answers (for a pool, its head)."
+ },
+ "owner": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "The machine's owner, who earns the offer's credits (a self-served run earns none)."
+ },
+ "models": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 40,
+ "description": "The models offered, as the machine's model server names them.",
+ "items": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ }
+ },
+ "hours": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "start",
+ "end",
+ "tz"
+ ],
+ "description": "The local-time window the offer is open; start equal to end is all day, and an overnight window wraps.",
+ "properties": {
+ "start": {
+ "type": "string",
+ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
+ },
+ "end": {
+ "type": "string",
+ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
+ },
+ "tz": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64,
+ "description": "An IANA time zone, such as Europe/Paris, or UTC."
+ }
+ }
+ },
+ "concurrency": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 8,
+ "description": "How many requests may run at once; another is refused as busy, never queued."
+ },
+ "price": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "in_per_million",
+ "out_per_million"
+ ],
+ "description": "Credits per million input and output tokens; 0 and 0 is a volunteer, who earns kudos. One price for a pool.",
+ "properties": {
+ "in_per_million": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 1000000
+ },
+ "out_per_million": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 1000000
+ }
+ }
+ },
+ "audience": {
+ "enum": [
+ "everyone",
+ "followers",
+ "group"
+ ],
+ "description": "Who may use it: everyone, the owner's followers, or one group (`group`)."
+ },
+ "group": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 80,
+ "description": "The group's id when the audience is `group`, otherwise null."
+ },
+ "ready": {
+ "type": "boolean",
+ "description": "Whether the machine (for a pool, every member) can answer now: online, inside its hours, not paused by idle-only or a kill switch."
+ },
+ "health": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "status"
+ ],
+ "properties": {
+ "status": {
+ "enum": [
+ "up",
+ "degraded",
+ "down"
+ ]
+ },
+ "checked_at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ },
+ "pool": {
+ "$ref": "offer-pool.v1.json",
+ "description": "Present when the offer is served by a pool of the owner's machines (ai.offer-pool@1)."
+ }
+ }
+ }
}
}
}
}
}
}
@@ -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.308.0",
- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.309.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,7 +145,7 @@
@@ -145,7 +145,7 @@
"service": "network",
"service": "network",
"name": "OpenVibe.Network",
"name": "OpenVibe.Network",
"origin": "https://openvibe.network",
"origin": "https://openvibe.network",
- "operations": 55,
+ "operations": 60,
"capabilities": 35
"capabilities": 35
},
},
{
{
@@ -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.308.0",
- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.MediaHub API",
"title": "OpenVibe.MediaHub API",
- "version": "0.308.0",
- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.309.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"
@@ -1004,7 +1004,7 @@
@@ -1004,7 +1004,7 @@
"put": {
"put": {
"operationId": "put_api_v1_node_self_capabilities",
"operationId": "put_api_v1_node_self_capabilities",
"summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
"summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
- "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
+ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",
"tags": [
"tags": [
"network.node"
"network.node"
],
],
@@ -1043,7 +1043,242 @@
@@ -1043,7 +1043,242 @@
"post": {
"post": {
"operationId": "post_api_v1_node_self_credential",
"operationId": "post_api_v1_node_self_credential",
"summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
"summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
- "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
+ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",
+ "tags": [
+ "network.node"
+ ],
+ "x-openvibe-capabilities": [
+ "network.node.self.manage"
+ ],
+ "x-openvibe-visibility": [
+ "internal"
+ ],
+ "x-openvibe-quota-class": "admin",
+ "security": [
+ {
+ "openvibeToken": [
+ "network.node.self.manage"
+ ]
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success"
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/node/self/pools/{id}": {
+ "get": {
+ "operationId": "get_api_v1_node_self_pools_id",
+ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
+ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",
+ "tags": [
+ "network.node"
+ ],
+ "x-openvibe-capabilities": [
+ "network.node.self.manage"
+ ],
+ "x-openvibe-visibility": [
+ "internal"
+ ],
+ "x-openvibe-quota-class": "admin",
+ "security": [
+ {
+ "openvibeToken": [
+ "network.node.self.manage"
+ ]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success"
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/node/self/pools/{id}/approve": {
+ "post": {
+ "operationId": "post_api_v1_node_self_pools_id_approve",
+ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
+ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",
+ "tags": [
+ "network.node"
+ ],
+ "x-openvibe-capabilities": [
+ "network.node.self.manage"
+ ],
+ "x-openvibe-visibility": [
+ "internal"
+ ],
+ "x-openvibe-quota-class": "admin",
+ "security": [
+ {
+ "openvibeToken": [
+ "network.node.self.manage"
+ ]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success"
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/node/self/pools/{id}/leave": {
+ "post": {
+ "operationId": "post_api_v1_node_self_pools_id_leave",
+ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
+ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",
+ "tags": [
+ "network.node"
+ ],
+ "x-openvibe-capabilities": [
+ "network.node.self.manage"
+ ],
+ "x-openvibe-visibility": [
+ "internal"
+ ],
+ "x-openvibe-quota-class": "admin",
+ "security": [
+ {
+ "openvibeToken": [
+ "network.node.self.manage"
+ ]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success"
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/node/self/pools/{id}/status": {
+ "post": {
+ "operationId": "post_api_v1_node_self_pools_id_status",
+ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
+ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",
+ "tags": [
+ "network.node"
+ ],
+ "x-openvibe-capabilities": [
+ "network.node.self.manage"
+ ],
+ "x-openvibe-visibility": [
+ "internal"
+ ],
+ "x-openvibe-quota-class": "admin",
+ "security": [
+ {
+ "openvibeToken": [
+ "network.node.self.manage"
+ ]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success"
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/node/self/pools/announce": {
+ "post": {
+ "operationId": "post_api_v1_node_self_pools_announce",
+ "summary": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
+ "description": "**network.node.self.manage** (internal): A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",
"tags": [
"tags": [
"network.node"
"network.node"
],
],
@@ -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.308.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.309.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.308.0",
- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.308.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.309.0",
+ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.309.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"
@@ -295149,3 +295149,1743 @@ export interface ChatParty {
@@ -295149,3 +295149,1743 @@ export interface ChatParty {
created_at: string;
created_at: string;
ended_at?: string | null;
ended_at?: string | null;
}
}
+
+/** [email protected] (owner: bot) */
+/**
+ * bot.machine-pool@1 (the pooled machines design, 2026-11-06): several of one owner's machines on the same local network that serve one model together through llama.cpp RPC, `rpc-server` on the members and `llama-server --rpc` on the head. OpenVibe.Network holds the record: the owner proposes it on /machines (POST /api/v1/machine-pools, two to eight of their own machines and an optional head; the default head has the most free VRAM), and each machine reads it with its own node token (GET /api/v1/node/self/pools/:id, network.node.self.manage) and approves it locally (POST /api/v1/node/self/pools/:id/approve with { certificate }). A machine's `certificate` is null until it approves on that machine: the Node generates an Ed25519 key there, keeps the private key, and uploads only its self-signed public certificate, which the other members pin for the pool's private link. A pool with any null certificate never serves. The record never carries a private key or a prompt. What a schema cannot say, Network and Node check at run time: the members are distinct and the head is one of them; every member has the pool's owner, today, through Bot; every member was seen from the same public address with a private address in the same subnet; the head's direct link probe to each member passes; each machine's certificate is its own; and any change of membership, owner, head or key revokes the pool, so all machines approve a new one. A machine that leaves (removed, signed out, a different owner) drops its link and its key at once.
+ */
+export interface BotMachinePool {
+ /**
+ * The pool's id (ULID, Crockford base32). A pool is never edited: a change is a new pool with a new id.
+ */
+ id: string;
+ /**
+ * The person every machine in the pool belongs to. Pools of different owners are not allowed.
+ */
+ owner: string;
+ /**
+ * The machine that runs `llama-server --rpc`, sees the prompt and answers; it must be one of `machines`. The others receive tensors only.
+ */
+ head: string;
+ /**
+ * The members, head included, two to eight.
+ *
+ * @minItems 2
+ * @maxItems 8
+ */
+ machines:
+ | [
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ }
+ ]
+ | [
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ }
+ ]
+ | [
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ }
+ ]
+ | [
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ }
+ ]
+ | [
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ }
+ ]
+ | [
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ }
+ ]
+ | [
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ },
+ {
+ /**
+ * The machine (Bot's device id), resolved by Network from the machine's own node token, never taken from the body.
+ */
+ id: string;
+ /**
+ * The machine's owner when it announced itself; it must equal the pool's owner.
+ */
+ owner: string;
+ /**
+ * The machine's private IPv4 address and prefix on the local network (RFC 1918 only, a /8 to a /30), such as 192.168.1.2/24, configured on one of its own interfaces. The private link listens only here; never 0.0.0.0, loopback or a public address.
+ */
+ address: string;
+ /**
+ * The public address Network saw the announcement come from (never the body's claim). Every member must share it with the head.
+ */
+ public_ip: (
+ | {
+ [k: string]: unknown | undefined;
+ }
+ | {
+ [k: string]: unknown | undefined;
+ }
+ ) &
+ string;
+ /**
+ * The TCP port of the machine's private link on `address`.
+ */
+ port: number;
+ /**
+ * Free GPU memory when it announced itself, in MB. The head's default and each member's share of the pool's credits follow it.
+ */
+ free_vram: number;
+ /**
+ * Free system memory when it announced itself, in MB.
+ */
+ free_ram: number;
+ /**
+ * A short hardware name the fit table matches measured speeds on, such as x86_64 or the GPU model.
+ */
+ hardware: string;
+ /**
+ * The machine's self-signed Ed25519 public certificate (PEM) for this pool's private link, or null until the machine approves the pool on itself. Never a private key.
+ */
+ certificate: string | null;
+ }
+ ];
+}
+
+/** [email protected] (owner: ai) */
+/**
+ * ai.offer-pool@1 (the pooled machines design, 2026-11-06): the `pool` part of a community AI offer (ai.offer@1) served by several of one owner's machines together (bot.machine-pool@1). Network adds it from its own approved pool record, never from what a machine reports: the offer is the head's, `head` equals the offer's `machine_id`, and while a machine is in a pool it advertises no offer of its own. It names machines only; no address, key or certificate reaches AI. AI routes the request to the head, runs the same verification as for one machine (canaries, the model fingerprint, spot re-runs) on the pool's answers, keys that verification on this exact membership (another member or head is a new, unverified pool), keeps a pool that is new or failed to the free tier only, and labels its answers "Community pool (N machines)".
+ */
+export interface AiOfferPool {
+ /**
+ * The pool's machines, head included (Bot device ids), two to eight.
+ *
+ * @minItems 2
+ * @maxItems 8
+ */
+ machines:
+ | [string, string]
+ | [string, string, string]
+ | [string, string, string, string]
+ | [string, string, string, string, string]
+ | [string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string, string];
+ /**
+ * The machine that answers: one of `machines`, and the offer's own `machine_id`.
+ */
+ head: string;
+}
+
+/** [email protected] (owner: ai) */
+/**
+ * ai.offer@1: one community AI offer, a person's machine (OpenVibe.Node's ai plugin, "Offer to the network") serving its local models to requests that opt in to community capacity. OpenVibe.Bot reports these fields (POST /internal/ai/offers/report on Network, network.resource.report; a report with any other field is refused whole), and OpenVibe.AI reads them from Network (GET /internal/ai/offers, network.registry.read, { offers, generated_at, count }). Network adds `pool` (ai.offer-pool@1) to the head's offer when the machine is the head of an approved pool (bot.machine-pool@1), and leaves a pool member's own offer out of the list while it is in a pool. For a pool the hours, audience, price, readiness, idle-only and verification apply to the whole pool: it is ready only while every member has approved, renewed its readiness in the last few seconds, and is still the owner's. Nothing here is public: AI shows Exchange a hashed offer id and no owner or machine id.
+ */
+export interface AiOffer {
+ /**
+ * `ai:<machine_id>`: one offer per machine.
+ */
+ offer_id: string;
+ /**
+ * The machine that answers (for a pool, its head).
+ */
+ machine_id: string;
+ /**
+ * The machine's owner, who earns the offer's credits (a self-served run earns none).
+ */
+ owner: string;
+ /**
+ * The models offered, as the machine's model server names them.
+ *
+ * @minItems 1
+ * @maxItems 40
+ */
+ models: [string, ...string[]];
+ /**
+ * The local-time window the offer is open; start equal to end is all day, and an overnight window wraps.
+ */
+ hours: {
+ start: string;
+ end: string;
+ /**
+ * An IANA time zone, such as Europe/Paris, or UTC.
+ */
+ tz: string;
+ };
+ /**
+ * How many requests may run at once; another is refused as busy, never queued.
+ */
+ concurrency: number;
+ /**
+ * Credits per million input and output tokens; 0 and 0 is a volunteer, who earns kudos. One price for a pool.
+ */
+ price: {
+ in_per_million: number;
+ out_per_million: number;
+ };
+ /**
+ * Who may use it: everyone, the owner's followers, or one group (`group`).
+ */
+ audience: "everyone" | "followers" | "group";
+ /**
+ * The group's id when the audience is `group`, otherwise null.
+ */
+ group: string | null;
+ /**
+ * Whether the machine (for a pool, every member) can answer now: online, inside its hours, not paused by idle-only or a kill switch.
+ */
+ ready: boolean;
+ health: {
+ status: "up" | "degraded" | "down";
+ checked_at?: string;
+ };
+ pool?: AiOfferPool;
+}
@@ -4,7 +4,7 @@
@@ -4,7 +4,7 @@
"owner": "network",
"owner": "network",
"status": "active",
"status": "active",
"visibility": "internal",
"visibility": "internal",
- "description": "A paired machine presents its own capabilities and rotates its own credential, never another machine's.",
+ "description": "A paired machine presents its own capabilities and rotates its own credential, never another machine's. It also announces itself for its owner's machine pools (bot.machine-pool@1), reads, approves and renews the pools it is a member of, and leaves them; it never acts for another machine.",
"permissions": [
"permissions": [
"nodes:self"
"nodes:self"
],
],
@@ -15,6 +15,11 @@
@@ -15,6 +15,11 @@
"events": [],
"events": [],
"implementedBy": [
"implementedBy": [
"PUT /api/v1/node/self/capabilities",
"PUT /api/v1/node/self/capabilities",
- "POST /api/v1/node/self/credential"
+ "POST /api/v1/node/self/credential",
+ "POST /api/v1/node/self/pools/announce",
+ "GET /api/v1/node/self/pools/:id",
+ "POST /api/v1/node/self/pools/:id/approve",
+ "POST /api/v1/node/self/pools/:id/status",
+ "POST /api/v1/node/self/pools/:id/leave"
]
]
}
}
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.308.0",
+ "version": "0.309.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.308.0",
+ "version": "0.309.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.308.0",
+ "version": "0.309.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",
@@ -12,8 +12,9 @@ const pkg = require(path.join(ROOT, 'package.json'));
@@ -12,8 +12,9 @@ const pkg = require(path.join(ROOT, 'package.json'));
const versions = [...text.matchAll(/^## (\d+)\.(\d+)\.(\d+)\b/gm)].map((m) => [+m[1], +m[2], +m[3]]);
const versions = [...text.matchAll(/^## (\d+)\.(\d+)\.(\d+)\b/gm)].map((m) => [+m[1], +m[2], +m[3]]);
const [major, minor] = pkg.version.split('.').map(Number);
const [major, minor] = pkg.version.split('.').map(Number);
-// Minor versions that were never released (no tag), so they have no entry. 306 is the pooled-machines branch (it
-// carries its own 0.306.0 entry and has not merged); 307 is reserved by work in flight, so Memory M5 takes 308.
+// Minor versions that were never released (no tag), so they have no entry. 306 and 307 were reserved for the pooled
+// machines and consent branches, which merged after Memory M5 took 308: they became 0.309.0 and 0.310.0, and the two
+// numbers stay unused (a tag below the newest one would read as a downgrade to the pin bot).
const NEVER_RELEASED = new Set([293, 306, 307]);
const NEVER_RELEASED = new Set([293, 306, 307]);
const FIRST_MINOR = 30;
const FIRST_MINOR = 30;