@nyx5/nyx5 0.2.4 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/SPEC.md CHANGED
@@ -1,59 +1,59 @@
1
- # Nyx5/1 — Correo y Libro para agentes
1
+ # Nyx5/1 — Mail and Libro for agents
2
2
 
3
- Estado: borrador ejecutable v0.4 (septiembre 2026)
4
- Implementación de referencia: este repositorio (Node 20+, sin dependencias)
3
+ Status: executable draft v0.4 (September 2026)
4
+ Reference implementation: this repository (Node 20+, no dependencies)
5
5
 
6
- ## 0. Qué es
6
+ ## 0. What it is
7
7
 
8
- Un solo sistema con dos componentes que comparten identidad, transporte y almacenamiento:
8
+ A single system with two components that share identity, transport and storage:
9
9
 
10
- - **Correo** (secciones 1 a 13): direcciones `agente@dominio`, tarjetas certificadas, sobres firmados y cifrados, buzón que guarda aunque el agente esté apagado. Lo que el email le dio a las personas.
11
- - **Libro** (secciones 14 a 20): el ledger de doble entrada de cada casa, cotizaciones, contratos, mandatos en cadena y estampillas. Lo que el email nunca tuvo: consecuencia económica y un recibo que ninguna parte puede negar.
10
+ - **Mail** (sections 1 to 13): `agent@domain` addresses, certified cards (tarjeta), signed and encrypted envelopes (sobre), a mailbox (buzón) that holds even while the agent is off. What email gave people.
11
+ - **Libro** (sections 14 to 20): the double-entry ledger of each house (casa), quotes (cotización), contracts, chained mandates (mandato) and stamps (estampilla). What email never had: economic consequence and a receipt (recibo) that no party can deny.
12
12
 
13
- No son dos protocolos compatibles. El Libro no tiene login ni API propia: se opera escribiéndole sobres a `libro@<casa>`, y la cadena de confianza del Correo es su autenticación. Sus respuestas son recibos firmados por la casa que llegan al buzón como cualquier carta.
13
+ They are not two compatible protocols. The Libro has no login and no API of its own: it is operated by writing envelopes to `libro@<house>`, and the Mail chain of trust is its authentication. Its responses are receipts signed by the house that arrive in the mailbox like any other letter.
14
14
 
15
- El email logró algo que ningún protocolo de agentes tiene hoy: una dirección universal, un buzón, y una red donde cualquier servidor le escribe a cualquier otro sin pedir permiso. MCP conecta un agente con sus herramientas; A2A conecta agentes que ya se conocen y están en línea. Ninguno da identidad por persona, buzón, confianza verificable entre desconocidos, ni una forma de que un acuerdo tenga peso.
15
+ Email achieved something no agent protocol has today: a universal address, a mailbox, and a network where any server writes to any other without asking permission. MCP connects an agent with its tools; A2A connects agents that already know each other and are online. Neither gives per-person identity, a mailbox, verifiable trust between strangers, nor a way for an agreement to carry weight.
16
16
 
17
- Nyx5/1 cierra esos huecos así:
17
+ Nyx5/1 closes those gaps like this:
18
18
 
19
- | Hueco | Cómo lo cierra Nyx5 |
19
+ | Gap | How Nyx5 closes it |
20
20
  |---|---|
21
- | Identidad por persona, no solo por dominio | Dirección `agente@dominio`. El dominio certifica la clave pública de cada agente. La persona es dueña de su clave; el dominio solo la avala. |
22
- | Buzón (store-and-forward) | Cada dominio tiene una estafeta que acepta, guarda y reintenta. El agente puede estar apagado días; nada se pierde. |
23
- | Confianza y anti-spam | Todo sobre viene firmado por el agente y avalado por su dominio (ancla en DNS). Sin firma verificable no hay entrega. El receptor decide su política: abierto, lista blanca, o estampilla (proof-of-work / pago). |
24
- | Fragmentación | Nyx5 no reemplaza a MCP ni a A2A: es el sobre universal. El contenido puede ser texto, JSON, una tarea A2A o una llamada MCP; la tarjeta del agente publica sus endpoints MCP/A2A. |
25
- | Palabras gratis | Un acuerdo es un asiento en el Libro, no prosa. Escrow retiene hasta que la prueba pasa; la fianza le pone precio a afirmar; el mandato acota cuánto puede gastar cada agente y quién paga al final. |
26
- | Recibo negable | Todo recibo lleva el hash del sobre que lo causó y la firma de quien lo emite. |
21
+ | Per-person identity, not just per-domain | `agent@domain` address. The domain certifies each agent's public key. The person owns their key; the domain only vouches for it. |
22
+ | Mailbox (store-and-forward) | Each domain has an estafeta that accepts, stores and retries. The agent can be off for days; nothing is lost. |
23
+ | Trust and anti-spam | Every envelope comes signed by the agent and vouched for by its domain (anchored in DNS). Without a verifiable signature there is no delivery. The receiver decides its policy: open, allowlist, or stamp (proof-of-work / payment). |
24
+ | Fragmentation | Nyx5 does not replace MCP or A2A: it is the universal envelope. The content can be text, JSON, an A2A task or an MCP call; the agent's card publishes its MCP/A2A endpoints. |
25
+ | Free words | An agreement is an entry (asiento) in the Libro, not prose. Escrow holds until the proof passes; the bond (fianza) puts a price on asserting; the mandate bounds how much each agent may spend and who pays in the end. |
26
+ | Deniable receipt | Every receipt carries the hash of the envelope that caused it and the signature of whoever issues it. |
27
27
 
28
- Y cifrado extremo a extremo por defecto. Las estafetas ven `de`, `para` y el tamaño; nunca el contenido.
28
+ And end-to-end encryption by default. The estafetas see `de`, `para` and the size; never the content.
29
29
 
30
- ## 1. Términos
30
+ ## 1. Terms
31
31
 
32
- - **Agente**: cualquier proceso (o persona operando un cliente) con un par de claves y una dirección.
33
- - **Dirección**: `local@dominio`. Minúsculas, `local` = `[a-z0-9][a-z0-9._-]{0,63}`.
34
- - **Estafeta**: el servidor de un dominio. Publica tarjetas, certifica agentes, recibe, guarda y entrega. Equivale al servidor MX del correo.
35
- - **Tarjeta de dominio**: JSON autofirmado en `/.well-known/nyx5.json`. Declara claves, URL de la estafeta, política y extensiones.
36
- - **Tarjeta de agente**: JSON con las claves y capacidades de un agente, firmado (certificado) por la clave del dominio.
37
- - **Sobre**: la unidad de envío. JSON firmado, opcionalmente cifrado.
38
- - **Resolver**: la lógica que va de una dirección a una tarjeta verificada.
32
+ - **Agent**: any process (or a person operating a client) with a key pair and an address.
33
+ - **Address**: `local@domain`. Lowercase, `local` = `[a-z0-9][a-z0-9._-]{0,63}`.
34
+ - **Estafeta**: a domain's server. It publishes cards, certifies agents, receives, stores and delivers. Equivalent to the MX server in email.
35
+ - **Domain card (tarjeta)**: self-signed JSON at `/.well-known/nyx5.json`. Declares keys, the estafeta URL, policy and extensions.
36
+ - **Agent card (tarjeta)**: JSON with an agent's keys and capabilities, signed (certified) by the domain key.
37
+ - **Envelope (sobre)**: the unit of sending. Signed JSON, optionally encrypted.
38
+ - **Resolver**: the logic that goes from an address to a verified card.
39
39
 
40
- ## 2. Descubrimiento y ancla de confianza
40
+ ## 2. Discovery and trust anchor
41
41
 
42
- Dada `asistente@sigo.uk`, el resolver localiza la estafeta de `sigo.uk` en este orden:
42
+ Given `asistente@sigo.uk`, the resolver locates the estafeta of `sigo.uk` in this order:
43
43
 
44
- 1. **Override local** (`hosts.json`): pruebas y redes privadas. Puede fijar la clave esperada (`sig`).
45
- 2. **DNS**: registro TXT en `_nyx5.sigo.uk`:
44
+ 1. **Local override** (`hosts.json`): tests and private networks. It can pin the expected key (`sig`).
45
+ 2. **DNS**: TXT record at `_nyx5.sigo.uk`:
46
46
  ```
47
- v=nyx51; url=https://mail.sigo.uk; sig=<clave pública Ed25519 del dominio, base64url>
47
+ v=nyx51; url=https://mail.sigo.uk; sig=<domain Ed25519 public key, base64url>
48
48
  ```
49
- `sig` es el ancla: la tarjeta del dominio debe estar firmada por esa clave. Con DNSSEC, la cadena queda completa.
50
- 3. **Well-known sin DNS**: `https://sigo.uk/.well-known/nyx5.json`. Si no hay ancla, el resolver aplica TOFU (confía en el primer uso y pinea la clave; un cambio posterior se rechaza hasta que el operador lo confirme).
49
+ `sig` is the anchor: the domain card must be signed by that key. With DNSSEC, the chain is complete.
50
+ 3. **Well-known without DNS**: `https://sigo.uk/.well-known/nyx5.json`. If there is no anchor, the resolver applies TOFU (trusts on first use and pins the key; a later change is rejected until the operator confirms it).
51
51
 
52
- Luego descarga la tarjeta del dominio y la del agente, y verifica la cadena: **DNS → clave del dominio → tarjeta del agente → firma del sobre**.
52
+ Then it downloads the domain card and the agent card, and verifies the chain: **DNS → domain key → agent card → envelope signature**.
53
53
 
54
- Las tarjetas se cachean (5 min por defecto). Si un sobre llega firmado con una clave que la tarjeta cacheada no reconoce, el receptor refresca la tarjeta una vez antes de rechazar (esto es lo que hace funcionar la rotación de claves sin coordinación).
54
+ Cards are cached (5 min by default). If an envelope arrives signed with a key that the cached card does not recognize, the receiver refreshes the card once before rejecting (this is what makes key rotation work without coordination).
55
55
 
56
- ## 3. Tarjeta de dominio
56
+ ## 3. Domain card
57
57
 
58
58
  ```json
59
59
  {
@@ -68,13 +68,13 @@ Las tarjetas se cachean (5 min por defecto). Si un sobre llega firmado con una c
68
68
  }
69
69
  ```
70
70
 
71
- Reglas:
72
- - `signature.kid` debe estar en `keys`. La firma cubre el JSON canónico sin `signature`.
73
- - `keys` puede listar varias durante una rotación; la primera es la activa.
74
- - `policy.inbound` hoy solo admite `verified` (sin firma no hay entrega). Se reserva para futuros modos.
75
- - `policy.outbound: "sealed"` (opcional) declara que todo lo que sale del dominio va cifrado; los receptores pueden rechazar sobres en claro de ese dominio.
71
+ Rules:
72
+ - `signature.kid` must be in `keys`. The signature covers the canonical JSON without `signature`.
73
+ - `keys` may list several during a rotation; the first is the active one.
74
+ - `policy.inbound` today admits only `verified` (no signature, no delivery). It is reserved for future modes.
75
+ - `policy.outbound: "sealed"` (optional) declares that everything leaving the domain goes encrypted; receivers may reject cleartext envelopes from that domain.
76
76
 
77
- ## 4. Tarjeta de agente
77
+ ## 4. Agent card
78
78
 
79
79
  `GET https://<estafeta>/agents/<local>`
80
80
 
@@ -82,8 +82,8 @@ Reglas:
82
82
  {
83
83
  "nyx5": "1",
84
84
  "address": "asistente@sigo.uk",
85
- "sig": "<Ed25519 pub del agente>",
86
- "enc": "<X25519 pub del agente>",
85
+ "sig": "<agent Ed25519 pub>",
86
+ "enc": "<agent X25519 pub>",
87
87
  "capabilities": {
88
88
  "accepts": ["text/plain", "application/json", "application/a2a-task+json"],
89
89
  "mcp": "https://agents.sigo.uk/asistente/mcp",
@@ -92,30 +92,30 @@ Reglas:
92
92
  "inbox": { "policy": "open" },
93
93
  "valid_from": "2026-09-04T19:00:00Z",
94
94
  "valid_until": null,
95
- "previous": [ { "sig": "<clave anterior>", "until": "2026-09-11T19:00:00Z" } ],
96
- "certification": { "alg": "Ed25519", "kid": "<clave del dominio>", "value": "<base64url>" }
95
+ "previous": [ { "sig": "<previous key>", "until": "2026-09-11T19:00:00Z" } ],
96
+ "certification": { "alg": "Ed25519", "kid": "<domain key>", "value": "<base64url>" }
97
97
  }
98
98
  ```
99
99
 
100
- Tarjeta delegada (un subagente que actúa por otro agente): el nombre es `<nombre>.<padre>`, y la tarjeta trae además
100
+ Delegated card (a subagent acting on behalf of another agent): the name is `<name>.<parent>`, and the card additionally carries
101
101
 
102
102
  ```json
103
103
  "delegation": {
104
- "by": "constructor@sigo.uk", "address": "tester.constructor@sigo.uk", "sig": "<clave del subagente>",
104
+ "by": "constructor@sigo.uk", "address": "tester.constructor@sigo.uk", "sig": "<subagent key>",
105
105
  "scope": { "types": ["message", "result"], "to_domains": ["sigo.uk"], "cap": 100 },
106
- "valid_until": null, "issued": "...", "signature": { "alg": "Ed25519", "kid": "<clave del padre>", "value": "..." }
106
+ "valid_until": null, "issued": "...", "signature": { "alg": "Ed25519", "kid": "<parent key>", "value": "..." }
107
107
  }
108
108
  ```
109
109
 
110
- Reglas:
111
- - `certification` la firma el dominio, no el agente. Cubre todo menos `certification`.
112
- - `delegation` la firma el padre. El dominio certifica la tarjeta igual; el resolver verifica ambas firmas (cadena dominio → padre → hijo). Un hijo no puede tener más `cap` que su padre. La estafeta hace cumplir `scope.types` y `scope.to_domains` al enviar; el Libro hace cumplir `scope.cap` al aceptar, afianzar, mandar y cobrar.
113
- - La clave privada `sig` la genera y guarda el agente; el dominio nunca la ve. Por eso la identidad es de la persona: si te vas de un dominio, te llevas tu clave y la certificas en otro.
114
- - `enc` es opcional. Sin `enc`, los remitentes envían en claro (o rechazan si exigen cifrado).
115
- - `previous`: claves anteriores con fecha de gracia. Una firma con clave anterior vigente es válida.
116
- - `inbox.policy`: ver sección 9.
110
+ Rules:
111
+ - `certification` is signed by the domain, not the agent. It covers everything except `certification`.
112
+ - `delegation` is signed by the parent. The domain certifies the card the same way; the resolver verifies both signatures (chain domain → parent → child). A child cannot have more `cap` than its parent. The estafeta enforces `scope.types` and `scope.to_domains` on send; the Libro enforces `scope.cap` on accept, bond, mandate and charge.
113
+ - The private `sig` key is generated and kept by the agent; the domain never sees it. That is why the identity is the person's: if you leave a domain, you take your key with you and certify it at another.
114
+ - `enc` is optional. Without `enc`, senders send in cleartext (or reject if they require encryption).
115
+ - `previous`: previous keys with a grace date. A signature with a valid previous key is valid.
116
+ - `inbox.policy`: see section 9.
117
117
 
118
- ## 5. El sobre
118
+ ## 5. The envelope
119
119
 
120
120
  ```json
121
121
  {
@@ -137,237 +137,237 @@ Reglas:
137
137
  "pow": { "bits": 16, "nonce": "12345" },
138
138
  "receipt": "delivered",
139
139
  "extensions": { "urn:nyx5:ext:a2a": { "task_id": "..." } },
140
- "signature": { "alg": "Ed25519", "kid": "<sig del agente>", "value": "<base64url>" }
140
+ "signature": { "alg": "Ed25519", "kid": "<agent sig>", "value": "<base64url>" }
141
141
  }
142
142
  ```
143
143
 
144
- Reglas:
145
- - `content` y `encrypted` son excluyentes. `content.media` sigue el modelo MIME; `body` es texto o JSON.
146
- - La **firma** cubre todo el sobre canónico menos `signature`. Se firma después de cifrar: cualquier estafeta verifica autenticidad sin poder leer el contenido.
147
- - El **cifrado** es JWE-like: una clave de contenido aleatoria cifra `content` con AES-256-GCM; esa clave se envuelve para cada destinatario con X25519 efímero + HKDF. El AAD es el canónico de `{id, from, to}`: un sobre no puede ser re-dirigido ni re-firmado por otro sin romper el descifrado.
148
- - **Detalle normativo del KDF** (toda implementación debe copiarlo byte a byte o nada interopera): la KEK de cada destinatario es `HKDF-SHA256(ikm = X25519(epk_priv, enc_dest), salt = los bytes UTF-8 del STRING base64url de epk — no la clave decodificada —, info = "nyx5/1 cek-wrap", 32)`. Y el canónico ordena claves, omite en objetos los valores `undefined`, y serializa como JSON compacto.
149
- - **Adjuntos** viajan por referencia (URL + hash), no incrustados. La estafeta no almacena binarios. El hash hace verificable la descarga.
150
- - `type` es un hint semántico. `task`/`result` para trabajo delegado; `receipt` para acuses; `intro` para presentarse ante buzones con lista blanca (máximo 4 KB); `message` para todo lo demás.
151
- - `thread` e `in_reply_to` dan hilos sin estado en el servidor.
152
- - `expires`: pasado ese instante, ninguna estafeta lo entrega ni reintenta.
153
- - `deliver_after` (opcional, ISO-8601): **entrega diferida.** El sobre espera en la cola de la estafeta emisora hasta ese instante y recién entonces se intenta entregar. Antes de la fecha no aparece en ningún buzón. Un `deliver_after` en el pasado se entrega de inmediato (nunca es error). Si `expires ≤ deliver_after` el sobre se rechaza al enviar (400): vencería antes de poder entregarse. Es el mecanismo de los recordatorios de un agente a sí mismo (memoria entre sesiones) y de los avisos de plazo que programa el Libro.
154
- - Los campos desconocidos se conservan y se firman, pero se ignoran. Así se agregan capacidades sin romper implementaciones viejas.
144
+ Rules:
145
+ - `content` and `encrypted` are mutually exclusive. `content.media` follows the MIME model; `body` is text or JSON.
146
+ - The **signature** covers the whole canonical envelope except `signature`. It is signed after encrypting: any estafeta verifies authenticity without being able to read the content.
147
+ - The **encryption** is JWE-like: a random content key encrypts `content` with AES-256-GCM; that key is wrapped for each recipient with ephemeral X25519 + HKDF. The AAD is the canonical form of `{id, from, to}`: an envelope cannot be re-addressed or re-signed by another without breaking decryption.
148
+ - **Normative KDF detail** (every implementation must copy it byte for byte or nothing interoperates): each recipient's KEK is `HKDF-SHA256(ikm = X25519(epk_priv, enc_dest), salt = the UTF-8 bytes of the base64url STRING of epk — not the decoded key —, info = "nyx5/1 cek-wrap", 32)`. And the canonical form orders keys, omits `undefined` values in objects, and serializes as compact JSON.
149
+ - **Attachments** travel by reference (URL + hash), not embedded. The estafeta does not store binaries. The hash makes the download verifiable.
150
+ - `type` is a semantic hint. `task`/`result` for delegated work; `receipt` for acknowledgements; `intro` to introduce yourself to allowlisted mailboxes (maximum 4 KB); `message` for everything else.
151
+ - `thread` and `in_reply_to` give threads without server state.
152
+ - `expires`: past that instant, no estafeta delivers it or retries.
153
+ - `deliver_after` (optional, ISO-8601): **deferred delivery.** The envelope waits in the sending estafeta's queue until that instant and only then is delivery attempted. Before that date it does not appear in any mailbox. A `deliver_after` in the past is delivered immediately (never an error). If `expires ≤ deliver_after` the envelope is rejected on send (400): it would expire before it could be delivered. It is the mechanism for an agent's reminders to itself (memory between sessions) and for the deadline notices the Libro schedules.
154
+ - Unknown fields are preserved and signed, but ignored. This is how capabilities are added without breaking old implementations.
155
155
 
156
- Tamaño máximo por defecto: 1 MB. Lo declara cada dominio en su tarjeta.
156
+ Default maximum size: 1 MB. Each domain declares it in its card.
157
157
 
158
- ## 6. Transporte entre estafetas
158
+ ## 6. Transport between estafetas
159
159
 
160
- `POST https://<estafeta destino>/inbound` con el sobre como cuerpo JSON y este header:
160
+ `POST https://<destination estafeta>/inbound` with the envelope as the JSON body and this header:
161
161
 
162
162
  ```
163
- X-Nyx5-Relay: nyx51 domain=<dominio emisor>; kid=<clave del dominio>; sig=<firma de "relay:<id>:<dominio destino>">
163
+ X-Nyx5-Relay: nyx51 domain=<sending domain>; kid=<domain key>; sig=<signature of "relay:<id>:<destination domain>">
164
164
  ```
165
165
 
166
- La firma del agente autentica al remitente (como DKIM). La firma de relay autentica a la estafeta emisora (como SPF). Un dominio puede exigir ambas (`require_relay`).
166
+ The agent signature authenticates the sender (like DKIM). The relay signature authenticates the sending estafeta (like SPF). A domain may require both (`require_relay`).
167
167
 
168
- Respuesta:
168
+ Response:
169
169
  ```json
170
170
  { "ok": true, "code": 202, "accepted": ["asistente@beta.example"], "rejected": [ { "to": "...", "code": 403, "reason": "..." } ] }
171
171
  ```
172
172
 
173
- Semántica de códigos (por sobre o por destinatario):
173
+ Semantics of the codes (per envelope or per recipient):
174
174
 
175
- | Código | Significado | Emisor |
175
+ | Code | Meaning | Sender |
176
176
  |---|---|---|
177
- | 200 | duplicado ya recibido (idempotente) | marca entregado |
178
- | 202 | aceptado en buzón | marca entregado |
179
- | 400 | sobre malformado | rebote inmediato |
180
- | 402 | falta estampilla (proof-of-work) | rebote; el cliente puede reintentar con pow |
181
- | 403 | firma inválida, remitente no verificable, política | rebote |
182
- | 404 | destinatario inexistente | rebote |
183
- | 410 | vencido | rebote |
184
- | 413 | demasiado grande | rebote |
185
- | 421, 429, 5xx, red caída | temporal | reintento con backoff exponencial |
186
-
187
- ## 7. Buzón y entrega (store-and-forward)
188
-
189
- 1. El agente entrega su sobre firmado a su propia estafeta (`POST /outbound`).
190
- 2. La estafeta lo encola por dominio destino y responde 202 de inmediato. Con `deliver_after`, el primer intento se agenda para esa fecha (el mismo `next_attempt` de la cola): el sobre espera ahí, sin aparecer en ningún buzón, hasta que llegue el momento.
191
- 3. Un trabajador intenta la entrega. Si falla temporalmente, reintenta con backoff exponencial (1 s, 2 s, 4 s… hasta 60 s) durante hasta 3 días. Luego rebota. Si un sobre vence (`expires`) mientras espera en la cola —por diferimiento o por reintentos a un destino caído—, **rebota al remitente** con la razón; no desaparece mudo.
192
- 4. La estafeta receptora verifica, aplica política y guarda el sobre en el buzón del destinatario.
193
- 5. El destinatario lee por poll (`GET /mailbox/<local>`) o recibe push (webhook firmado por el dominio). El sobre permanece hasta que el agente confirma (`POST /mailbox/<local>/ack`). Un agente apagado una semana recibe todo al volver.
194
- 6. Rebotes y acuses son sobres normales de `postmaster@<dominio>`, firmados con la clave del dominio, con `type: receipt`, `in_reply_to` al sobre original y `sha256` del sobre original. Acuse de entrega solo si el sobre pide `"receipt": "delivered"`. Los recibos que emite un agente (`processed`, etc.) también llevan el `sha256` del sobre: son no repudiables sin ningún registro central.
195
- 7. Idempotencia por `id`: una segunda entrega del mismo sobre devuelve 200 y no duplica.
196
-
197
- ## 8. API agente ↔ estafeta
198
-
199
- Autenticación: `Authorization: Nyx5 <token>.<firma>` donde `token` = base64url del canónico de `{address, ts, nonce, method, path, host}` y `firma` = Ed25519 con la clave del agente. Ventana de 5 minutos, nonce de un solo uso, atado a método, ruta y **casa destino** (`host`): un token capturado no sirve contra otra estafeta.
200
-
201
- | Método | Ruta | Quién | Para |
177
+ | 200 | duplicate already received (idempotent) | marks delivered |
178
+ | 202 | accepted into mailbox | marks delivered |
179
+ | 400 | malformed envelope | immediate bounce |
180
+ | 402 | stamp missing (proof-of-work) | bounce; the client may retry with pow |
181
+ | 403 | invalid signature, sender not verifiable, policy | bounce |
182
+ | 404 | recipient does not exist | bounce |
183
+ | 410 | expired | bounce |
184
+ | 413 | too large | bounce |
185
+ | 421, 429, 5xx, network down | temporary | retry with exponential backoff |
186
+
187
+ ## 7. Mailbox and delivery (store-and-forward)
188
+
189
+ 1. The agent delivers its signed envelope to its own estafeta (`POST /outbound`).
190
+ 2. The estafeta queues it by destination domain and responds 202 immediately. With `deliver_after`, the first attempt is scheduled for that date (the same `next_attempt` of the queue): the envelope waits there, without appearing in any mailbox, until the time comes.
191
+ 3. A worker attempts delivery. If it fails temporarily, it retries with exponential backoff (1 s, 2 s, 4 s… up to 60 s) for up to 3 days. Then it bounces. If an envelope expires (`expires`) while waiting in the queue —whether by deferral or by retries to a downed destination—, it **bounces to the sender** with the reason; it does not vanish silently.
192
+ 4. The receiving estafeta verifies, applies policy and stores the envelope in the recipient's mailbox.
193
+ 5. The recipient reads by poll (`GET /mailbox/<local>`) or receives push (webhook signed by the domain). The envelope stays until the agent acknowledges (`POST /mailbox/<local>/ack`). An agent off for a week receives everything on return.
194
+ 6. Bounces and acknowledgements are ordinary envelopes from `postmaster@<domain>`, signed with the domain key, with `type: receipt`, `in_reply_to` to the original envelope and `sha256` of the original envelope. A delivery acknowledgement only if the envelope requests `"receipt": "delivered"`. The receipts an agent issues (`processed`, etc.) also carry the `sha256` of the envelope: they are non-repudiable without any central registry.
195
+ 7. Idempotency by `id`: a second delivery of the same envelope returns 200 and does not duplicate.
196
+
197
+ ## 8. Agent ↔ estafeta API
198
+
199
+ Authentication: `Authorization: Nyx5 <token>.<signature>` where `token` = base64url of the canonical form of `{address, ts, nonce, method, path, host}` and `signature` = Ed25519 with the agent's key. A 5-minute window, single-use nonce, bound to method, path and **destination house** (`host`): a captured token is useless against another estafeta.
200
+
201
+ | Method | Route | Who | For |
202
202
  |---|---|---|---|
203
- | GET | `/.well-known/nyx5.json` | público | tarjeta del dominio |
204
- | GET | `/agents` | público | directorio de la casa (`?capability=mcp&accepts=<media>&q=<texto>&limit&offset`) |
205
- | GET | `/agents/:local` | público | tarjeta del agente |
206
- | POST | `/agents` | ver sección 8b | registrar/actualizar agente |
207
- | POST | `/invitations` | admin | emitir código de invitación `{ uses, expires, note, welcome }` |
208
- | GET | `/invitations` | admin | listar invitaciones y su uso |
209
- | POST | `/outbound` | agente | enviar |
210
- | POST | `/inbound` | estafetas | recibir |
211
- | GET | `/mailbox/:local` | agente | leer pendientes |
212
- | POST | `/mailbox/:local/ack` | agente | confirmar procesados |
213
- | GET | `/outbox/:local` | agente | estado de envíos |
214
- | GET | `/health` | público | salud |
215
-
216
- ## 8b. Servicio de registro
217
-
218
- Cómo entra un agente a una casa lo decide la tarjeta del dominio (`policy.registration`):
219
-
220
- | Modo | Quién inscribe | Cómo |
203
+ | GET | `/.well-known/nyx5.json` | public | domain card |
204
+ | GET | `/agents` | public | house directory (`?capability=mcp&accepts=<media>&q=<text>&limit&offset`) |
205
+ | GET | `/agents/:local` | public | agent card |
206
+ | POST | `/agents` | see section 8b | register/update agent |
207
+ | POST | `/invitations` | admin | issue invitation code `{ uses, expires, note, welcome }` |
208
+ | GET | `/invitations` | admin | list invitations and their use |
209
+ | POST | `/outbound` | agent | send |
210
+ | POST | `/inbound` | estafetas | receive |
211
+ | GET | `/mailbox/:local` | agent | read pending |
212
+ | POST | `/mailbox/:local/ack` | agent | confirm processed |
213
+ | GET | `/outbox/:local` | agent | status of sends |
214
+ | GET | `/health` | public | health |
215
+
216
+ ## 8b. Registration service
217
+
218
+ How an agent enters a house is decided by the domain card (`policy.registration`):
219
+
220
+ | Mode | Who enrolls | How |
221
221
  |---|---|---|
222
- | `admin` (por defecto) | solo la casa | `POST /agents` con `Authorization: Bearer <token de la casa>` |
223
- | `invite` | quien tenga un código | la casa emite códigos con usos y vencimiento; el agente lo presenta en `invite` |
224
- | `open` | cualquiera | primer llegado, primer servido; límite de altas por minuto |
222
+ | `admin` (default) | only the house | `POST /agents` with `Authorization: Bearer <house token>` |
223
+ | `invite` | anyone holding a code | the house issues codes with uses and expiry; the agent presents it in `invite` |
224
+ | `open` | anyone | first come, first served; a cap on registrations per minute |
225
225
 
226
- En `invite` y `open` el cuerpo va **firmado con la misma clave que se inscribe** (`signature.kid == sig`, con `ts` dentro de 5 minutos): prueba de posesión. Nadie puede registrar una clave que no controla. Un nombre ya tomado solo lo actualiza su dueño (autenticación firmada, incluso al rotar claves: el cuerpo lleva las nuevas, la autenticación se firma con las viejas) o la casa. Nombres reservados: `postmaster`, `libro`, `casa`, `admin`, `root`, `abuse`, `security`, `hostmaster`, `noreply`, `support`, `estafeta`, `nyx5`, `verifica`, `tareas`, `indice`. Los subagentes se inscriben con la firma del padre (sección 4).
226
+ In `invite` and `open` the body goes **signed with the same key being enrolled** (`signature.kid == sig`, with `ts` within 5 minutes): proof of possession. No one can register a key they do not control. A name already taken can only be updated by its owner (signed authentication, even when rotating keys: the body carries the new ones, the authentication is signed with the old ones) or by the house. Reserved names: `postmaster`, `libro`, `casa`, `admin`, `root`, `abuse`, `security`, `hostmaster`, `noreply`, `support`, `estafeta`, `nyx5`, `verifica`, `tareas`, `indice`. Subagents are enrolled with the parent's signature (section 4).
227
227
 
228
- El **directorio** (`GET /agents`) es la lista pública de las tarjetas de la casa que **pidieron figurar** (`capabilities.listed: true`): claves, capacidades, política de buzón, si es delegado y por quién. Sin webhooks ni datos privados. El default es no aparecer: un agente no figura en el directorio ni en ningún índice sin haberlo pedido. El lookup directo por dirección (`GET /agents/<local>`) resuelve a cualquier agente que ya conoces, listado o no. Sirve para encontrar quién ofrece qué dentro de una casa; entre casas, el descubrimiento sigue siendo por dirección (sección 2): no hay un registro global, y ese hueco está declarado en la sección 21.
228
+ The **directory** (`GET /agents`) is the public list of the house's cards that **asked to be listed** (`capabilities.listed: true`): keys, capabilities, mailbox policy, whether it is delegated and by whom. No webhooks or private data. The default is not to appear: an agent does not figure in the directory or in any index without having asked. The direct lookup by address (`GET /agents/<local>`) resolves to any agent you already know, listed or not. It serves to find who offers what within a house; between houses, discovery is still by address (section 2): there is no global registry, and that gap is declared in section 21.
229
229
 
230
- Cada alta es un evento registrado (`registered_via`: admin, self, delegation, open, invite:<código>) y, si la casa da regalo de bienvenida, un asiento en el Libro.
230
+ Each registration is a recorded event (`registered_via`: admin, self, delegation, open, invite:<code>) and, if the house gives a welcome gift, an entry in the Libro.
231
231
 
232
- ## 9. Políticas de entrada
232
+ ## 9. Inbound policies
233
233
 
234
- La estafeta receptora rechaza sin excepción sobres sin firma verificable. Sobre eso, cada agente elige:
234
+ The receiving estafeta rejects without exception envelopes without a verifiable signature. On top of that, each agent chooses:
235
235
 
236
- - `open`: acepta cualquier remitente verificado. Límite de tasa por dominio emisor (120/min por defecto).
237
- - `allowlist`: solo direcciones o dominios listados. Un desconocido tiene dos formas de entrar: un `intro` de hasta 4 KB (el agente decide si lo agrega a la lista), o un **aval con fianza** (`urn:nyx5:ext:aval`): un tercero **de la allowlist** lo respalda con una fianza en la casa del receptor. El sobre lleva `extensions["urn:nyx5:ext:aval"] = { voucher, bond }`; la estafeta comprueba que la fianza exista y esté activa, que la puso el avalador (que debe estar en la allowlist), que avala a este remitente (`vouchee`), y que tiene al receptor como beneficiario y verificador. Si la presentación resulta basura, el receptor ejecuta la fianza (`forfeit`, §16): avalar deja de ser gratis.
238
- - `pow`: exige proof-of-work (hashcash, `pow_bits` bits de ceros iniciales en SHA-256 de `id:nonce`). Los de la allowlist quedan exentos. Con 16 bits, un envío cuesta ~65k hashes: gratis para uno, caro para un millón.
239
- - `stamp`: exige estampilla pagada en el Libro. La tarjeta publica `{ policy: "stamp", price: 5, house?: "sigo.uk" }`; el sobre lleva `stamp: { house, amount }` firmado como parte del sobre; la estafeta receptora cobra en su Libro al aceptar (sección 19). Sin saldo, 402 y rebote.
240
- - `blocklist`: siempre se aplica antes que lo demás.
236
+ - `open`: accepts any verified sender. Rate limit per sending domain (120/min by default).
237
+ - `allowlist`: only listed addresses or domains. A stranger has two ways in: an `intro` of up to 4 KB (the agent decides whether to add it to the list), or a **vouch with bond** (`urn:nyx5:ext:aval`): a third party **from the allowlist** backs it with a bond in the receiver's house. The envelope carries `extensions["urn:nyx5:ext:aval"] = { voucher, bond }`; the estafeta checks that the bond exists and is active, that it was posted by the voucher (which must be in the allowlist), that it vouches for this sender (`vouchee`), and that it has the receiver as beneficiary and verifier. If the introduction turns out to be junk, the receiver forfeits the bond (`forfeit`, §16): vouching stops being free.
238
+ - `pow`: requires proof-of-work (hashcash, `pow_bits` bits of leading zeros in SHA-256 of `id:nonce`). Those in the allowlist are exempt. At 16 bits, a send costs ~65k hashes: free for one, expensive for a million.
239
+ - `stamp`: requires a stamp paid in the Libro. The card publishes `{ policy: "stamp", price: 5, house?: "sigo.uk" }`; the envelope carries `stamp: { house, amount }` signed as part of the envelope; the receiving estafeta charges in its Libro on accept (section 19). Without balance, 402 and bounce.
240
+ - `blocklist`: always applied before anything else.
241
241
 
242
- ## 10. Extensiones
242
+ ## 10. Extensions
243
243
 
244
- Una extensión es una URI. El dominio y el agente declaran las que soportan; un sobre puede llevar datos bajo `extensions[uri]`. Implementaciones que no la conocen ignoran esos datos sin fallar.
244
+ An extension is a URI. The domain and the agent declare the ones they support; an envelope may carry data under `extensions[uri]`. Implementations that do not know it ignore that data without failing.
245
245
 
246
- - `urn:nyx5:ext:mcp`: el agente publica `capabilities.mcp` (URL de su servidor MCP). Un sobre `type: task` con `media: application/mcp-call+json` y `body: {tool, arguments}` es una llamada MCP asíncrona con buzón. La referencia incluye el puente inverso: un servidor MCP por stdio (`nyx5 mcp`) que expone `nyx5_send`, `nyx5_inbox`, `nyx5_ack`, `nyx5_resolve` a cualquier cliente MCP (Claude Desktop, Claude Code, Cursor).
247
- - `urn:nyx5:ext:a2a`: `capabilities.a2a` apunta a la Agent Card A2A. Un sobre con `media: application/a2a-task+json` transporta una tarea A2A; el `task_id` viaja en `extensions`. Así A2A gana buzón y direccionamiento por persona sin cambiar su spec.
248
- - `urn:nyx5:ext:email`: la casa es pasarela de correo. `nombre@dominio` es a la vez dirección Nyx5 y de correo. **Entrada**: un email real entra al buzón como un sobre **sin firma**, con el remitente real y el asunto en `extensions["urn:nyx5:ext:email"]`, marcado `from_verified: false` y `via: "email"`. Nunca se disfraza de sobre firmado (invariante 1): se abre explícitamente como lo que es, un mensaje externo no verificable. **Salida**: un agente le escribe a una dirección de correo cualquiera (`POST /email/out`, autenticado); el mensaje sale con `Reply-To` igual a la dirección Nyx5 del agente, así la respuesta del humano vuelve a su buzón por la entrada. Es el arranque en frío: llega la carta antes de que exista la decisión de adoptar; cuando el humano quiere firma, cifrado y Libro, se registra. La entrada corre en el borde (Cloudflare Email Routing → Email Worker); la salida usa un proveedor HTTP (el envelope-from debe ser un dominio verificado en él). Sin proveedor configurado, la salida queda **pendiente**: el puente no inventa un canal que no tiene.
249
- - `urn:nyx5:ext:indice`: la casa opera un índice federado de agentes (§13).
250
- - `urn:nyx5:ext:libro`: la casa opera un Libro (secciones 14 a 20). Lo declara la tarjeta del dominio y la tarjeta de `libro@<dominio>` publica el fee y las operaciones.
251
- - `urn:nyx5:ext:aval`: un sobre de un desconocido a un buzón con lista blanca lo lleva para presentar su aval: `{ voucher, bond }`. El avalador respalda con una fianza (op `bond` con `vouchee`) en la casa del receptor; la política de entrada (§9) la exige válida antes de aceptar.
252
- - `urn:nyx5:ext:person`: la tarjeta del agente puede declarar `person: {name, verified_by}` para agentes que actúan por una persona identificada, con verificación delegada (por ejemplo, un dominio que solo certifica clientes con identidad verificada).
246
+ - `urn:nyx5:ext:mcp`: the agent publishes `capabilities.mcp` (the URL of its MCP server). An envelope `type: task` with `media: application/mcp-call+json` and `body: {tool, arguments}` is an asynchronous MCP call with a mailbox. The reference includes the reverse bridge: an MCP server over stdio (`nyx5 mcp`) that exposes `nyx5_send`, `nyx5_inbox`, `nyx5_ack`, `nyx5_resolve` to any MCP client (Claude Desktop, Claude Code, Cursor).
247
+ - `urn:nyx5:ext:a2a`: `capabilities.a2a` points to the A2A Agent Card. An envelope with `media: application/a2a-task+json` transports an A2A task; the `task_id` travels in `extensions`. This way A2A gains a mailbox and per-person addressing without changing its spec.
248
+ - `urn:nyx5:ext:email`: the house is a mail gateway. `name@domain` is at once a Nyx5 and a mail address. **Inbound**: a real email enters the mailbox as an envelope **without a signature**, with the real sender and the subject in `extensions["urn:nyx5:ext:email"]`, marked `from_verified: false` and `via: "email"`. It is never disguised as a signed envelope (invariant 1): it is opened explicitly as what it is, an unverifiable external message. **Outbound**: an agent writes to any mail address whatsoever (`POST /email/out`, authenticated); the message goes out with `Reply-To` equal to the agent's Nyx5 address, so the human's reply comes back to its mailbox through the inbound path. It is the cold start: the letter arrives before the decision to adopt exists; when the human wants signature, encryption and Libro, they register. Inbound runs at the edge (Cloudflare Email Routing → Email Worker); outbound uses an HTTP provider (the envelope-from must be a domain verified with it). Without a configured provider, outbound stays **pending**: the bridge does not invent a channel it does not have.
249
+ - `urn:nyx5:ext:indice`: the house operates a federated index of agents (§13).
250
+ - `urn:nyx5:ext:libro`: the house operates a Libro (sections 14 to 20). It is declared by the domain card and the card of `libro@<domain>` publishes the fee and the operations.
251
+ - `urn:nyx5:ext:aval`: an envelope from a stranger to an allowlisted mailbox carries it to present its vouch (aval): `{ voucher, bond }`. The voucher backs it with a bond (op `bond` with `vouchee`) in the receiver's house; the inbound policy (§9) requires it valid before accepting.
252
+ - `urn:nyx5:ext:person`: the agent card may declare `person: {name, verified_by}` for agents acting on behalf of an identified person, with delegated verification (for example, a domain that only certifies clients with verified identity).
253
253
 
254
- ## 11. Versionado
254
+ ## 11. Versioning
255
255
 
256
- - `nyx5: "1"` en tarjetas y sobres. Un cambio incompatible es `"2"`; las estafetas pueden hablar ambas.
257
- - Campos nuevos dentro de la versión 1 son siempre opcionales y se ignoran si no se conocen.
258
- - Algoritmos: `alg` explícito en firma y cifrado. Agregar uno nuevo no rompe nada; retirar uno se anuncia en la tarjeta del dominio.
256
+ - `nyx5: "1"` in cards and envelopes. An incompatible change is `"2"`; estafetas may speak both.
257
+ - New fields within version 1 are always optional and ignored if not known.
258
+ - Algorithms: explicit `alg` in signature and encryption. Adding a new one breaks nothing; retiring one is announced in the domain card.
259
259
 
260
- ## 12. Modelo de amenazas
260
+ ## 12. Threat model
261
261
 
262
- | Amenaza | Mitigación |
262
+ | Threat | Mitigation |
263
263
  |---|---|
264
- | Suplantar a un agente | Firma Ed25519 verificada contra la tarjeta certificada por su dominio. |
265
- | Suplantar a un dominio | Ancla en DNS (con DNSSEC) o pin TOFU; cambio de clave sin anuncio se rechaza. |
266
- | Leer el contenido en tránsito o en la estafeta | Cifrado extremo a extremo; las estafetas solo ven metadatos. |
267
- | Re-dirigir o re-firmar un sobre ajeno | AAD del cifrado incluye `id/from/to`. |
268
- | Repetir un sobre | Deduplicación por `id`; `expires`. |
269
- | Repetir un token de auth | Nonce único, ventana de 5 min, atado a método y ruta. |
270
- | Spam masivo | Firma obligatoria (cuesta un dominio), límite de tasa por dominio, allowlist/intro, proof-of-work o estampilla. |
271
- | Estafeta emisora falsa usando sobres robados | Firma de relay del dominio emisor; `require_relay`. |
272
- | Pérdida por caída del destino | Cola persistente con reintentos y rebote final al remitente. |
273
- | Clave de agente comprometida | Rotación con período de gracia; `valid_until`; blocklist inmediata en el dominio. |
274
-
275
- ## 13. El índice federado (extensión `urn:nyx5:ext:indice`)
276
-
277
- El directorio (§8b) es por casa. Para "encuentra un agente que haga X en cualquier casa" existe el
278
- índice federado: una casa cualquiera que decide operar un buscador. No es infraestructura del
279
- protocolo: es un servicio que cualquiera monta, como un buscador sobre la web.
280
-
281
- - **Alta**: `POST /index/houses { domain }`. La verificación ES la puerta: el índice resuelve la
282
- tarjeta del dominio por la cadena normal (§2) y solo lista lo que firma como casa Nyx5.
283
- - **Opt-in**: un agente aparece en el directorio (§8b) —y por lo tanto en cualquier índice que lo
284
- rastree— **solo si su tarjeta declara `capabilities.listed: true`**. El default es no figurar: nadie
285
- se lista sin pedirlo. No listar no es esconderse: el lookup directo por dirección (`GET /agents/<local>`)
286
- sigue resolviendo a cualquier agente que ya conoces; lo opt-in es la *enumeración*, no el alcance.
287
- - **Rastreo**: el índice lee periódicamente `GET /agents` de cada casa listada (que ya devuelve solo
288
- los agentes con `listed: true`), re-verifica la tarjeta del dominio en cada pasada, y descarta toda
289
- tarjeta cuya certificación no firme el dominio de origen. Lo que el dominio no certificó no entra al índice.
290
- - **Búsqueda**: `GET /index/agents?q&capability&accepts&house&limit&offset`. La respuesta viaja
291
- firmada por la casa del índice, con cada tarjeta acompañada de su casa de origen (`_house`).
292
- - **Confianza**: el índice es una PISTA, no una autoridad. Quien usa un resultado re-verifica la
293
- tarjeta por la cadena normal (DNS -> dominio -> agente) antes de actuar. Un índice malicioso
294
- puede omitir o desordenar, pero no puede falsificar una tarjeta ni un sobre.
295
- - Cualquier casa puede operar su propio índice y federarse leyendo los de otras (las respuestas
296
- firmadas lo permiten); ningún índice es el índice.
297
-
298
- ## 14. El Libro: kernel
299
-
300
- Cada casa (dominio) lleva un ledger de doble entrada. Cuentas:
301
-
302
- - `agente@dominio`: cualquier agente verificable por el Correo, de esta casa o de otra. Un foráneo tiene cuenta aquí sin registrarse: su identidad ya viene probada.
303
- - `casa@<dominio>`: la distribuidora. Emite tokens (carga saldo), cobra fees. Es la única cuenta que puede quedar en negativo: su saldo negativo es lo que la casa debe.
304
- - `escrow:<contrato>`: fondos retenidos por un contrato.
305
-
306
- Un **asiento** es `{ id, n, at, house, concept, lines: [{ account, delta }], meta, refs, signature }`. Las líneas suman cero. Lo firma la casa. `refs` apunta a los sobres que lo causaron (`op`, `op_sha256`, `quote`, `quote_sha256`, `contract`). La suma de todos los saldos de una casa es siempre 0.
307
-
308
- Siete primitivas, y nada más:
309
-
310
- | Primitiva | Asiento | Fee |
264
+ | Impersonate an agent | Ed25519 signature verified against the card certified by its domain. |
265
+ | Impersonate a domain | DNS anchor (with DNSSEC) or TOFU pin; a key change without announcement is rejected. |
266
+ | Read the content in transit or at the estafeta | End-to-end encryption; the estafetas only see metadata. |
267
+ | Re-address or re-sign someone else's envelope | The encryption AAD includes `id/from/to`. |
268
+ | Replay an envelope | Deduplication by `id`; `expires`. |
269
+ | Replay an auth token | Unique nonce, 5-min window, bound to method and path. |
270
+ | Mass spam | Mandatory signature (costs a domain), rate limit per domain, allowlist/intro, proof-of-work or stamp. |
271
+ | Fake sending estafeta using stolen envelopes | Relay signature of the sending domain; `require_relay`. |
272
+ | Loss from destination downtime | Persistent queue with retries and a final bounce to the sender. |
273
+ | Compromised agent key | Rotation with a grace period; `valid_until`; immediate blocklist at the domain. |
274
+
275
+ ## 13. The federated index (extension `urn:nyx5:ext:indice`)
276
+
277
+ The directory (§8b) is per house. For "find an agent that does X in any house" there is the
278
+ federated index: any house that decides to operate a search engine. It is not protocol
279
+ infrastructure: it is a service anyone stands up, like a search engine over the web.
280
+
281
+ - **Registration**: `POST /index/houses { domain }`. Verification IS the gate: the index resolves the
282
+ domain card by the normal chain (§2) and only lists what signs as a Nyx5 house.
283
+ - **Opt-in**: an agent appears in the directory (§8b) —and therefore in any index that
284
+ crawls it— **only if its card declares `capabilities.listed: true`**. The default is not to figure: no one
285
+ is listed without asking. Not listing is not hiding: the direct lookup by address (`GET /agents/<local>`)
286
+ still resolves to any agent you already know; what is opt-in is the *enumeration*, not the reach.
287
+ - **Crawling**: the index periodically reads `GET /agents` of each listed house (which already returns only
288
+ the agents with `listed: true`), re-verifies the domain card on each pass, and discards any
289
+ card whose certification is not signed by the origin domain. What the domain did not certify does not enter the index.
290
+ - **Search**: `GET /index/agents?q&capability&accepts&house&limit&offset`. The response travels
291
+ signed by the index's house, with each card accompanied by its origin house (`_house`).
292
+ - **Trust**: the index is a HINT, not an authority. Whoever uses a result re-verifies the
293
+ card by the normal chain (DNS -> domain -> agent) before acting. A malicious index
294
+ may omit or reorder, but cannot forge a card or an envelope.
295
+ - Any house may operate its own index and federate by reading others' (the signed
296
+ responses allow it); no index is the index.
297
+
298
+ ## 14. The Libro: kernel
299
+
300
+ Each house (domain) keeps a double-entry ledger. Accounts:
301
+
302
+ - `agente@dominio`: any agent verifiable by Mail, from this house or another. A foreigner has an account here without registering: its identity is already proven.
303
+ - `casa@<dominio>`: the distributor. Issues tokens (loads balance), charges fees. It is the only account that may go negative: its negative balance is what the house owes.
304
+ - `escrow:<contrato>`: funds held by a contract.
305
+
306
+ An **entry (asiento)** is `{ id, n, at, house, concept, lines: [{ account, delta }], meta, refs, signature }`. The lines sum to zero. The house signs it. `refs` points to the envelopes that caused it (`op`, `op_sha256`, `quote`, `quote_sha256`, `contract`). The sum of all balances of a house is always 0.
307
+
308
+ Seven primitives, and nothing else:
309
+
310
+ | Primitive | Entry | Fee |
311
311
  |---|---|---|
312
- | cotizar | ninguno: es un documento firmado por el vendedor | — |
313
- | cobrar | comprador − X · vendedor + (X − fee) · casa + fee | sí |
314
- | retener | pagador − X · escrow + X | no |
315
- | liberar | escrow − X · beneficiario + (X − fee) · casa + fee | sí |
316
- | devolver | escrow − X · pagador + X | no |
317
- | repartir | N líneas que suman 0 (el fee es un reparto) | — |
318
- | afianzar | retener con salida distinta: liberar (vuelve) o ejecutar (va al beneficiario) | no |
312
+ | quote | none: it is a document signed by the seller | — |
313
+ | charge | buyer − X · seller + (X − fee) · house + fee | yes |
314
+ | hold | payer − X · escrow + X | no |
315
+ | release | escrow − X · beneficiary + (X − fee) · house + fee | yes |
316
+ | refund | escrow − X · payer + X | no |
317
+ | split | N lines summing to 0 (the fee is a split) | — |
318
+ | bond | hold with a different exit: release (returns) or forfeit (goes to the beneficiary) | no |
319
319
 
320
- Transversales: idempotencia por `id` de sobre (una operación reentregada devuelve el mismo resultado sin repetir el asiento) y `meta` (contexto legible por máquina en cada asiento). Los montos son enteros (tokens).
320
+ Cross-cutting: idempotency by envelope `id` (a re-delivered operation returns the same result without repeating the entry) and `meta` (machine-readable context in each entry). Amounts are integers (tokens).
321
321
 
322
- ## 15. Cotizaciones
322
+ ## 15. Quotes
323
323
 
324
- Una cotización es un **documento firmado por el vendedor**, independiente del sobre que la transporta:
324
+ A quote (cotización) is a **document signed by the seller**, independent of the envelope that transports it:
325
325
 
326
326
  ```json
327
327
  { "tipo": "cotizacion", "id": "uuid", "house": "sigo.uk", "seller": "verifica@sigo.uk", "buyer": "nicolas@sigo.uk",
328
328
  "contract": "spot | escrow | metered", "price": 40, "currency": "tok", "concept": "verificación de despliegue",
329
329
  "terms": { "acceptance": "lighthouse >= 90", "deadline": "2026-09-15" }, "arbiter": null,
330
330
  "referrer": { "address": "socio@otra.casa", "share": 1500 },
331
- "issued": "...", "expires": null, "signature": { "alg": "Ed25519", "kid": "<sig del vendedor>", "value": "..." } }
331
+ "issued": "...", "expires": null, "signature": { "alg": "Ed25519", "kid": "<seller sig>", "value": "..." } }
332
332
  ```
333
333
 
334
- Viaja al comprador dentro de un sobre con `media: application/nyx5.cotizacion+json`, cifrado. La casa la ve recién cuando el comprador la acepta. El Libro verifica: firma del vendedor (vía resolver), `buyer` igual al que acepta, `house` igual a la propia, vigencia, y que no haya sido aceptada antes (409).
334
+ It travels to the buyer inside an envelope with `media: application/nyx5.cotizacion+json`, encrypted. The house sees it only when the buyer accepts it. The Libro verifies: seller's signature (via resolver), `buyer` equal to the one who accepts, `house` equal to its own, validity, and that it has not been accepted before (409).
335
335
 
336
- **Comisión de referido** (`referrer`, opcional): el vendedor firma en la cotización que le paga `share` (en basis points) a quien trajo el trato. La comisión **sale de lo que recibe el vendedor**, no se suma al precio: el comprador paga igual y la casa cobra igual. Al liquidar (el `transfer` del spot o el `release` del escrow), el asiento pasa a cuatro líneas —comprador, vendedor, casa, referidor— y sigue sumando cero. El Libro exige `share` entero y `> 0`, que `fee + share ≤ 10000` bps (el vendedor nunca queda en negativo), y que el referidor no sea el propio vendedor. La distribución se paga sola: nadie la factura aparte, se asienta en el mismo movimiento.
336
+ **Referral commission** (`referrer`, optional): the seller signs in the quote that it pays `share` (in basis points) to whoever brought the deal. The commission **comes out of what the seller receives**, it is not added to the price: the buyer pays the same and the house charges the same. On settlement (the spot `transfer` or the escrow `release`), the entry becomes four lines —buyer, seller, house, referrer— and still sums to zero. The Libro requires `share` to be an integer and `> 0`, that `fee + share ≤ 10000` bps (the seller never goes negative), and that the referrer is not the seller itself. The distribution pays itself: no one invoices it separately, it is posted in the same movement.
337
337
 
338
- ## 16. Operaciones
338
+ ## 16. Operations
339
339
 
340
- Se envían como sobre a `libro@<casa>` con `type: task`, `media: application/nyx5.libro+json`, sin cifrar (la casa debe leerlo), `body: { op, ... }`. La respuesta llega al buzón de cada parte como `type: receipt` de `libro@<casa>` con `media: application/nyx5.recibo+json`. Si la operación falla, el remitente recibe un rebote del postmaster con el código y la razón.
340
+ They are sent as an envelope to `libro@<house>` with `type: task`, `media: application/nyx5.libro+json`, unencrypted (the house must read it), `body: { op, ... }`. The response arrives in each party's mailbox as `type: receipt` from `libro@<house>` with `media: application/nyx5.recibo+json`. If the operation fails, the sender receives a bounce from the postmaster with the code and the reason.
341
341
 
342
- | op | quién | efecto |
342
+ | op | who | effect |
343
343
  |---|---|---|
344
- | `accept { quote }` | comprador | crea el contrato; spot: cobra; escrow: retiene; metered: crea mandato |
345
- | `deliver { contract, evidence_sha256, note }` | vendedor (escrow) | `held → delivered`, registra el hash de la evidencia |
346
- | `release { contract }` | comprador o árbitro (escrow); verificador o árbitro (fianza); afianzado solo si venció | escrow → vendedor con fee; fianza → vuelve al afianzado |
347
- | `refund { contract, note }` | vendedor o árbitro; comprador solo si aún no hay entrega | escrow → comprador sin fee |
348
- | `bond { amount, claim, verifier, beneficiary?, arbiter?, evidence_sha256?, expires? }` | el que afirma | retiene el monto junto a la afirmación |
349
- | `forfeit { contract, reason }` | verificador o árbitro | fianza → beneficiario (por defecto la casa) |
350
- | `mandate { grantee, cap, scope?, expires?, parent? }` | mandante | autoridad de gasto; con `parent`, sub-mandato acotado |
351
- | `charge { mandate, amount, concept }` | mandatario | paga el mandante raíz; toda la cadena descuenta |
352
- | `revoke { mandate }` | mandante o superior | revoca en cascada |
353
- | `balance`, `statement { limit }`, `contract { contract }` | el propio | lectura, respuesta por recibo |
344
+ | `accept { quote }` | buyer | creates the contract; spot: charges; escrow: holds; metered: creates a mandate |
345
+ | `deliver { contract, evidence_sha256, note }` | seller (escrow) | `held → delivered`, records the evidence hash |
346
+ | `release { contract }` | buyer or arbiter (escrow); verifier or arbiter (bond); the bondholder only if expired | escrow → seller with fee; bond → returns to the bondholder |
347
+ | `refund { contract, note }` | seller or arbiter; buyer only if there is no delivery yet | escrow → buyer without fee |
348
+ | `bond { amount, claim, verifier, beneficiary?, arbiter?, evidence_sha256?, expires? }` | the one who asserts | holds the amount alongside the assertion |
349
+ | `forfeit { contract, reason }` | verifier or arbiter | bond → beneficiary (by default the house) |
350
+ | `mandate { grantee, cap, scope?, expires?, parent? }` | grantor | spending authority; with `parent`, a bounded sub-mandate |
351
+ | `charge { mandate, amount, concept }` | mandatee | the root grantor pays; the whole chain decrements |
352
+ | `revoke { mandate }` | grantor or superior | revokes in cascade |
353
+ | `balance`, `statement { limit }`, `contract { contract }` | oneself | read, response by receipt |
354
354
 
355
- Lecturas directas sin correo: `GET /libro/cuenta/:address` y `GET /libro/contrato/:id` con la misma autenticación firmada (también para foráneos). Administración: `POST /libro/topup` y `GET /libro/diario` con token de la casa.
355
+ Direct reads without mail: `GET /libro/cuenta/:address` and `GET /libro/contrato/:id` with the same signed authentication (also for foreigners). Administration: `POST /libro/topup` and `GET /libro/diario` with the house token.
356
356
 
357
- ## 17. Contratos
357
+ ## 17. Contracts
358
358
 
359
- Un contrato es una máquina de estados sobre las primitivas. El kernel no sabe qué contrato sirve.
359
+ A contract is a state machine over the primitives. The kernel does not know which contract it serves.
360
360
 
361
- | Contrato | Estados | Mecánica |
361
+ | Contract | States | Mechanics |
362
362
  |---|---|---|
363
- | spot | `settled` | cotizar → aceptar = cobrar |
364
- | escrow | `held → delivered → released \| refunded` | retener al aceptar; liberar si la prueba pasa; devolver si falla; árbitro pactado en la cotización |
365
- | bond (fianza) | `posted → released \| forfeited` | el que afirma deposita; el verificador libera o ejecuta; vencida, el afianzado la recupera |
366
- | metered | `active` + mandato | aceptar crea un mandato con tope = precio; el vendedor cobra bajo él |
363
+ | spot | `settled` | quote → accept = charge |
364
+ | escrow | `held → delivered → released \| refunded` | hold on accept; release if the proof passes; refund if it fails; arbiter agreed in the quote |
365
+ | bond (fianza) | `posted → released \| forfeited` | the one who asserts deposits; the verifier releases or forfeits; expired, the bondholder recovers it |
366
+ | metered | `active` + mandate | accept creates a mandate with cap = price; the seller charges under it |
367
367
 
368
- Registro del contrato: `{ id, kind, house, seller, buyer, verifier?, arbiter?, amount, concept, terms, state, quote_id, quote_sha256, accept_sha256, evidence_sha256?, history: [{ at, op, by, asiento, ... }] }`. Toda vista pública de un contrato lleva además `acp`, el mismo ciclo de trabajo que ERC-8183 usa on-chain, para que quien ya integró ese vocabulario entienda esto sin traducir:
368
+ Contract record: `{ id, kind, house, seller, buyer, verifier?, arbiter?, amount, concept, terms, state, quote_id, quote_sha256, accept_sha256, evidence_sha256?, history: [{ at, op, by, asiento, ... }] }`. Reputation is not built: it is a query over these records (escrows released vs refunded, bonds intact vs forfeited), and each point cost tokens. Every public view of a contract also carries `acp`, the same work cycle ERC-8183 uses on-chain, so that whoever already integrated that vocabulary understands this without translating:
369
369
 
370
- | `state` interno | `acp.phase` | `acp.outcome` |
370
+ | internal `state` | `acp.phase` | `acp.outcome` |
371
371
  |---|---|---|
372
372
  | `accepted` | `Open` | — |
373
373
  | `held`, `posted`, `active` | `Funded` | — |
@@ -377,28 +377,28 @@ Registro del contrato: `{ id, kind, house, seller, buyer, verifier?, arbiter?, a
377
377
  | `settled` | `Terminal` | `paid` |
378
378
  | `forfeited` | `Terminal` | `forfeited` |
379
379
 
380
- Los estados internos no cambian: `acp` es una vista derivada. Nyx5 habla ese vocabulario sin cadena, sin gas y sin billetera. La reputación no se construye: es una consulta sobre estos registros (escrows liberados vs devueltos, fianzas intactas vs ejecutadas), y cada punto costó tokens.
380
+ Internal states do not change: `acp` is a derived view. Nyx5 speaks that vocabulary with no chain, no gas and no wallet.
381
381
 
382
- Bounties, suscripciones, subastas, referidos y disputas son composiciones de las mismas primitivas; se agregan a `contratos.js` cuando una transacción real las pida.
382
+ Bounties, subscriptions, auctions, referrals and disputes are compositions of the same primitives; they are added to `contratos.js` when a real transaction asks for them.
383
383
 
384
- ## 18. Mandatos en cadena
384
+ ## 18. Chained mandates
385
385
 
386
- Un mandato es `{ id, grantor, grantee, cap, spent, scope: { concepts? }, expires, parent, root, chain, state }`. El mandatario puede sub-delegar un mandato con `cap ≤ cap − spent` del padre y `expires ≤` el del padre. Un cobro bajo cualquier eslabón lo paga el mandante **raíz**, descuenta `spent` en toda la cadena, y el recibo llega a todos los que están en ella. Revocar un mandato revoca todo lo que cuelga. Es un poder notarial anidado y auditable: cada token que se mueve tiene su cadena de autoridad completa en el asiento (`meta.chain`).
386
+ A mandate is `{ id, grantor, grantee, cap, spent, scope: { concepts? }, expires, parent, root, chain, state }`. The mandatee may sub-delegate a mandate with `cap ≤ cap − spent` of the parent and `expires ≤` the parent's. A charge under any link is paid by the **root** grantor, decrements `spent` throughout the chain, and the receipt reaches everyone in it. Revoking a mandate revokes everything hanging from it. It is a nested, auditable power of attorney: every token that moves has its full chain of authority in the entry (`meta.chain`).
387
387
 
388
- Dos delegaciones distintas, ambas encadenadas: la **tarjeta delegada** (sección 4) dice quién es un subagente y qué puede enviar; el **mandato** dice cuánto puede gastar y quién paga. Un subagente con `scope.cap` no puede aceptar, afianzar, mandar ni cobrar por encima de ese tope, tenga el mandato que tenga.
388
+ Two distinct delegations, both chained: the **delegated card** (section 4) says who a subagent is and what it may send; the **mandate** says how much it may spend and who pays. A subagent with `scope.cap` cannot accept, bond, mandate or charge above that cap, whatever mandate it holds.
389
389
 
390
- ## 19. Estampillas
390
+ ## 19. Stamps
391
391
 
392
- Un buzón con `inbox: { policy: "stamp", price, house? }` cobra por recibir. El sobre lleva `stamp: { house, amount }` dentro de lo firmado; la estafeta receptora ejecuta `cobrar(remitente → destinatario)` en su Libro al aceptar el sobre y guarda el `id` del asiento junto al sobre. Sin saldo en esa casa, 402 y rebote. Es el anti-spam con precio real: escribirle a un desconocido cuesta, y lo cobra el desconocido.
392
+ A mailbox with `inbox: { policy: "stamp", price, house? }` charges to receive. The envelope carries `stamp: { house, amount }` within the signed part; the receiving estafeta executes `charge(sender → recipient)` in its Libro on accepting the envelope and stores the entry `id` alongside the envelope. Without balance in that house, 402 and bounce. It is anti-spam with a real price: writing to a stranger costs, and the stranger charges it.
393
393
 
394
- ## 20. Recibos
394
+ ## 20. Receipts
395
395
 
396
- Todo recibo del Libro contiene `{ of, op, op_sha256, from, contract? | mandate? | asiento?, cotizacion_sha256?, chain? }`, va firmado por la casa y se entrega a todas las partes. Junto con el sobre original (firmado por quien operó) y la cotización (firmada por el vendedor), forma una prueba de tres firmas que ninguna parte puede fabricar ni negar. Ese es el instrumento: el chat entre agentes es barato; el recibo es caro y verificable.
396
+ Every Libro receipt contains `{ of, op, op_sha256, from, contract? | mandate? | asiento?, cotizacion_sha256?, chain? }`, is signed by the house and delivered to all parties. Together with the original envelope (signed by whoever operated) and the quote (signed by the seller), it forms a three-signature proof that no party can fabricate or deny. That is the instrument: the chat between agents is cheap; the receipt is expensive and verifiable.
397
397
 
398
- ## 21. Historial: la reputación es una consulta al libro
398
+ ## 21. History: reputation is a query on the ledger
399
399
 
400
- `GET /agents/<local>/historial` — **público, sin autenticación**. Existe justamente para que un
401
- desconocido decida antes de contratar, igual que la tarjeta.
400
+ `GET /agents/<local>/historial` — **public, no authentication**. It exists precisely so a stranger
401
+ can decide before hiring, exactly like the card.
402
402
 
403
403
  ```json
404
404
  {
@@ -413,74 +413,77 @@ desconocido decida antes de contratar, igual que la tarjeta.
413
413
  }
414
414
  ```
415
415
 
416
- Reglas que lo hacen difícil de inflar:
416
+ (Field names stay in Spanish because they are the protocol's domain nouns, like `sobre` and `libro`.
417
+ `vendiendo` = selling, `comprando` = buying, `afirmando` = asserting, `avalando` = vouching,
418
+ `resumen` = summary, `cumplimiento` = delivery rate, `veracidad` = truthfulness.)
417
419
 
418
- 1. **Solo cuentan los contratos cuyo asiento ya movió tokens** (los estados terminales de §17). Un
419
- contrato abierto no dice nada de nadie, y un agente Sybil sin saldo no tiene historial: para
420
- tener uno hay que haber puesto tokens en juego.
421
- 2. **Cero de cero es `null`, no 100 %.** `cumplimiento` y `veracidad` valen `null` cuando no hay
422
- nada que promediar. Un recién llegado no aparece perfecto: aparece sin historial.
423
- 3. **No expone contenido ni contrapartes**: cuántas, de qué tipo y cuántos tokens. Nada más.
424
- 4. **`tokens_en_juego_ahora`** son las fianzas vigentes: lo que ese agente tiene apostado en este
425
- momento a que lo que afirmó es cierto.
420
+ What makes it hard to inflate:
426
421
 
427
- ## 22. Verificación: `verifica@<casa>`
422
+ 1. **Only contracts whose entry already moved tokens are counted** (the terminal states of §17). An
423
+ open contract says nothing about anyone, and a Sybil agent with no balance has no history: to
424
+ have one, you must have put tokens at stake.
425
+ 2. **Zero out of zero is `null`, not 100 %.** `cumplimiento` and `veracidad` are `null` when there
426
+ is nothing to average. A newcomer does not look perfect: they look like they have no history.
427
+ 3. **It exposes no content and no counterparties**: how many, of what kind, how many tokens. Nothing else.
428
+ 4. **`tokens_en_juego_ahora`** are the standing bonds: what that agent has wagered right now on
429
+ what it asserted being true.
428
430
 
429
- Una casa puede operar un evaluador de referencia. Es un agente de sistema con la clave del dominio,
430
- y **solo actúa sobre contratos que lo nombran árbitro y declaran su prueba** en `terms.verify`.
431
+ ## 22. Verification: `verifica@<house>`
431
432
 
432
- Tres pruebas deterministas, y ninguna más:
433
+ A house may run a reference evaluator. It is a system agent holding the domain key, and it **only
434
+ acts on contracts that name it arbiter and declare its test** in `terms.verify`.
433
435
 
434
- | `type` | Comprueba | Campos |
436
+ Three deterministic tests, and no more:
437
+
438
+ | `type` | Checks | Fields |
435
439
  |---|---|---|
436
- | `http_status` | una URL **https** responde el código esperado | `url`, `expect` (200 por defecto) |
437
- | `sha256` | el contenido de una URL, o el `evidence_sha256` que declaró la entrega, hashea a lo esperado | `expect` (64 hex), `url` opcional |
438
- | `exit_0` | un comando termina con código 0 | `argv` (array; **nunca** una línea de shell) |
439
-
440
- - **El veredicto conjunto pasa solo si TODAS pasan.**
441
- - Si alguna prueba **no pudo correr** (red caída, timeout, falta la evidencia), el veredicto queda
442
- **indeciso** y no se decide nada: el escrow se queda como está. Un fallo de red no es una
443
- afirmación falsa, y castigar a quien no se pudo comprobar destruye la credibilidad del sistema.
444
- - La decisión viaja como un sobre firmado a `libro@` y entra por la misma puerta que la de
445
- cualquier agente (invariante: el Libro no se opera por dentro). El veredicto queda escrito en el
446
- contrato, así que el porqué es auditable.
447
- - **Sin juicio de modelo**, a propósito: un verificador que se equivoca castiga a un inocente. Si
448
- una prueba no puede decidir sola y sin ambigüedad, este verificador no la acepta.
449
- - `exit_0` necesita shell, que no existe en un runtime de borde. La casa declara en la tarjeta de
450
- `verifica@` qué pruebas puede correr, en vez de prometer lo que no hace.
451
-
452
- ## 23. Trabajo sembrado: `tareas@<casa>`
453
-
454
- El arranque en frío no se resuelve con más oferta. Un agente que se une y no tiene nada que hacer se
455
- va, y unirse queda como una llave sin puerta. Una casa puede publicar trabajo pagado y ser el primer
456
- comprador.
457
-
458
- `GET /tareas` — **público**. Devuelve el mostrador, el árbitro, el tope por agente y día, y cada
459
- tarea con precio, enunciado y **su prueba entera**: nadie debería aceptar un trato cuyo criterio no
460
- puede leer.
461
-
462
- El agente cotiza a `tareas@<casa>` como `escrow`, con `arbiter` = el verificador de la casa y
463
- `terms` **exactamente iguales a los publicados**. La casa compara contra su catálogo, no contra lo
464
- que dice la cotización de sí misma; cualquier diferencia se rechaza. Nada se negocia.
465
-
466
- Defensas contra Sybil, que es el riesgo obvio de pagar por entrar:
467
-
468
- - tope por agente y por día, y tope global de la casa;
469
- - una tarea en curso por agente: hay que terminarla antes de tomar otra;
470
- - cada tarea se paga **una sola vez por agente**, aunque cambie el día;
471
- - pago **solo contra verificación determinista** (§22), nunca por juicio ni por afirmación.
472
-
473
- Sin cupo, la casa responde `409` y no `429`: un `429` es transitorio y la estafeta lo reintentaría
474
- durante días, dejando al agente esperando sin saber por qué.
475
-
476
- ## 24. Lo que Nyx5/1 no resuelve todavía (y no finge resolver)
477
-
478
- - **Reputación entre dominios**: hoy cada receptor decide solo. Una red de reputación compartida (como las listas negras del email) es trabajo futuro.
479
- - **Privacidad de metadatos**: las estafetas ven quién le escribe a quién. Resolverlo requiere enrutamiento tipo mixnet, fuera de alcance.
480
- - **Custodia de claves para personas**: la referencia guarda la clave en un archivo. Para humanos hace falta integrar passkeys/WebAuthn o llaves de hardware.
481
- - **Identidad legal**: `agente@dominio` prueba control del dominio, no quién es la persona. La extensión `person` es un gancho, no una solución.
482
- - **Adopción**: el protocolo vale lo que valga el número de estafetas. Un solo dominio corriendo Nyx5 es una demo; cien es una red.
483
- - **Registro global**: resuelto parcialmente por el índice federado (§13): cualquier casa puede operar un buscador verificante, y un agente entra a él solo si pide figurar (`listed`, opt-in). Sigue sin existir un índice "oficial" — a propósito: ningún índice es el índice.
484
- - **Libros federados**: cada casa tiene su Libro; los tokens de una casa no se mueven a otra. Un foráneo transa en tu casa con una cuenta en tu casa. Conectar libros entre casas es construir un sistema de compensación (SWIFT); queda deliberadamente fuera.
485
- - **Incentivo real**: entre agentes de un mismo dueño, el token mide pero no incentiva. El incentivo se prueba con el primer tercero que acepta tokens porque puede liquidarlos.
486
- - **Lo regulatorio** de emitir crédito en circuito cerrado y pagar a terceros es de cada casa, no del protocolo.
440
+ | `http_status` | an **https** URL answers the expected code | `url`, `expect` (200 by default) |
441
+ | `sha256` | the body of a URL, or the `evidence_sha256` the delivery declared, hashes to the expected value | `expect` (64 hex), optional `url` |
442
+ | `exit_0` | a command exits with code 0 | `argv` (array; **never** a shell line) |
443
+
444
+ - **The joint verdict passes only if ALL of them pass.**
445
+ - If any test **could not run** (network down, timeout, missing evidence), the verdict is
446
+ **undecided** and nothing is decided: the escrow stays as it was. A network failure is not a false
447
+ claim, and punishing someone you could not check destroys the system's credibility.
448
+ - The decision travels as a signed envelope to `libro@` and enters through the same door as any
449
+ agent's (invariant: the Libro is never operated from the inside). The verdict is written into the
450
+ contract, so the reason is auditable.
451
+ - **No model judgement**, deliberately: a verifier that gets it wrong punishes an innocent. If a
452
+ test cannot decide on its own and without ambiguity, this verifier does not accept it.
453
+ - `exit_0` needs a shell, which an edge runtime does not have. The house declares in `verifica@`'s
454
+ card which tests it can actually run, instead of promising what it does not do.
455
+
456
+ ## 23. Seeded work: `tareas@<house>`
457
+
458
+ Cold start is not solved with more supply. An agent that joins and has nothing to do leaves, and
459
+ joining stays a key with no door. A house may publish paid work and be the first buyer.
460
+
461
+ `GET /tareas` — **public**. Returns the desk, the arbiter, the per-agent daily cap, and each task
462
+ with its price, its statement and **its full test**: nobody should accept a deal whose criterion
463
+ they cannot read.
464
+
465
+ The agent quotes `tareas@<house>` as an `escrow`, with `arbiter` = the house verifier and `terms`
466
+ **exactly equal to the published ones**. The house compares against its catalogue, never against
467
+ what the quote says about itself; any difference is rejected. Nothing is negotiated.
468
+
469
+ Sybil defenses, which is the obvious risk of paying people to show up:
470
+
471
+ - per-agent and per-day cap, plus a global house cap;
472
+ - one task in flight per agent: finish it before taking another;
473
+ - each task pays **once per agent**, even on a different day;
474
+ - payment **only against deterministic verification** (§22), never by judgement or by assertion.
475
+
476
+ With no quota left the house answers `409`, not `429`: a `429` is transient and the estafeta would
477
+ retry it for days, leaving the agent waiting without knowing why.
478
+
479
+ ## 24. What Nyx5/1 does not yet solve (and does not pretend to)
480
+
481
+ - **Cross-domain reputation**: today each receiver decides alone. A shared reputation network (like email's blacklists) is future work.
482
+ - **Metadata privacy**: the estafetas see who writes to whom. Solving it requires mixnet-style routing, out of scope.
483
+ - **Key custody for persons**: the reference stores the key in a file. For humans it needs integrating passkeys/WebAuthn or hardware keys.
484
+ - **Legal identity**: `agent@domain` proves control of the domain, not who the person is. The `person` extension is a hook, not a solution.
485
+ - **Adoption**: the protocol is worth as much as the number of estafetas. A single domain running Nyx5 is a demo; a hundred is a network.
486
+ - **Global registry**: partially solved by the federated index (§13): any house may operate a verifying search engine, and an agent enters it only if it asks to be listed (`listed`, opt-in). There is still no "official" index — on purpose: no index is the index.
487
+ - **Federated ledgers**: each house has its Libro; the tokens of one house do not move to another. A foreigner transacts in your house with an account in your house. Connecting ledgers between houses is building a clearing system (SWIFT); it is deliberately left out.
488
+ - **Real incentive**: among agents of the same owner, the token measures but does not incentivize. The incentive is proven with the first third party that accepts tokens because it can settle them.
489
+ - **The regulatory side** of issuing closed-circuit credit and paying third parties belongs to each house, not the protocol.