@jossuealcala/madre 1.0.0 → 1.0.2

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.
Files changed (174) hide show
  1. package/ADDITIONAL-TERMS.md +93 -0
  2. package/CHANGELOG.en.md +1945 -0
  3. package/CHANGELOG.md +78 -1
  4. package/CONTRIBUTING.md +5 -1
  5. package/LICENSE +661 -202
  6. package/NOTICE +34 -3
  7. package/README.en.md +245 -0
  8. package/README.md +23 -13
  9. package/TRADEMARKS.en.md +50 -0
  10. package/TRADEMARKS.md +82 -0
  11. package/bin/madre.mjs +2 -0
  12. package/docs/INTERNALS.md +8 -2
  13. package/docs/REFERENCE.md +17 -7
  14. package/docs/en/INTERNALS.md +103 -0
  15. package/docs/en/REFERENCE.md +339 -0
  16. package/docs/en/SDK.md +306 -0
  17. package/docs/en/training/README.md +59 -0
  18. package/docs/madre-banner.png +0 -0
  19. package/docs/training/README.md +20 -8
  20. package/docs/training/train.sh +2 -1
  21. package/package.json +14 -5
  22. package/public/abduction.js +2 -0
  23. package/public/app.js +2066 -488
  24. package/public/attribution.js +71 -0
  25. package/public/brands.js +3 -1
  26. package/public/editor.js +2 -0
  27. package/public/es.js +1706 -1226
  28. package/public/i18n.js +25 -1
  29. package/public/index.html +13 -10
  30. package/public/inquiry.js +2 -0
  31. package/public/loader.js +2 -0
  32. package/public/macroverso.js +24 -2
  33. package/public/nostromo-engine.js +2 -0
  34. package/public/resay.js +6 -0
  35. package/public/review-ask.js +2 -0
  36. package/public/routing.js +23 -1
  37. package/public/salas-mac.css +539 -28
  38. package/public/salas-mac.html +30 -22
  39. package/public/salas-mac.js +1498 -144
  40. package/public/salas.css +2 -0
  41. package/public/salas.html +1 -0
  42. package/public/salas.js +4 -2
  43. package/public/styles.css +1123 -20
  44. package/public/syntax.js +2 -0
  45. package/public/touch.js +2 -0
  46. package/public/tour-chapters.js +164 -52
  47. package/public/tour.js +85 -12
  48. package/public/troubleshooting.js +20 -18
  49. package/src/adapters/claude.mjs +2 -0
  50. package/src/adapters/codex.mjs +2 -0
  51. package/src/adapters/gemini.mjs +3 -1
  52. package/src/adapters/madre.mjs +3 -1
  53. package/src/adapters/opencode.mjs +7 -3
  54. package/src/adapters/process.mjs +2 -0
  55. package/src/asking.mjs +2 -0
  56. package/src/auth-probe.mjs +32 -7
  57. package/src/bridge/devices.mjs +2 -0
  58. package/src/bridge/handoff.mjs +2 -0
  59. package/src/bridge/host.mjs +2 -0
  60. package/src/bridge/network.mjs +2 -0
  61. package/src/bridge/policy.mjs +3 -1
  62. package/src/bridge/qr.mjs +2 -0
  63. package/src/bridge/server.mjs +2 -0
  64. package/src/capabilities.mjs +2 -0
  65. package/src/chats.mjs +2 -0
  66. package/src/checkpoint.mjs +2 -0
  67. package/src/choices.mjs +2 -0
  68. package/src/cli-args.mjs +2 -0
  69. package/src/cold.mjs +2 -0
  70. package/src/commands.mjs +2 -0
  71. package/src/config.mjs +2 -0
  72. package/src/conversation-context.mjs +15 -1
  73. package/src/credentials.mjs +112 -3
  74. package/src/dataset.mjs +2 -0
  75. package/src/directives.mjs +8 -6
  76. package/src/distiller.mjs +2 -0
  77. package/src/embeddings.mjs +2 -0
  78. package/src/enlaces.mjs +6 -4
  79. package/src/event-store.mjs +2 -0
  80. package/src/exam.mjs +6 -4
  81. package/src/extensions.mjs +33 -10
  82. package/src/eyecat-watch.mjs +2 -0
  83. package/src/eyecat.mjs +2 -0
  84. package/src/file-ops.mjs +2 -0
  85. package/src/files.mjs +32 -0
  86. package/src/github.mjs +2 -0
  87. package/src/heartbeat.mjs +57 -0
  88. package/src/i18n.mjs +15 -1
  89. package/src/image-studio.mjs +2 -0
  90. package/src/json-file.mjs +2 -0
  91. package/src/launch.mjs +2 -0
  92. package/src/lease.mjs +5 -1
  93. package/src/lobby-work.mjs +2 -0
  94. package/src/local-ai.mjs +50 -0
  95. package/src/looks.mjs +40 -5
  96. package/src/maturity.mjs +3 -1
  97. package/src/mcp/connect.mjs +345 -0
  98. package/src/mcp/github-server.mjs +2 -0
  99. package/src/mcp/image-server.mjs +2 -0
  100. package/src/mcp/memory-server.mjs +2 -0
  101. package/src/mcp/proxy.mjs +153 -0
  102. package/src/mcp/smtp-server.mjs +2 -0
  103. package/src/memory-dashboard.mjs +2 -0
  104. package/src/memory-tools.mjs +2 -0
  105. package/src/memory.mjs +2 -0
  106. package/src/models.mjs +83 -3
  107. package/src/modules/ahp.mjs +2 -0
  108. package/src/modules/ash-policy.mjs +2 -0
  109. package/src/modules/ash.mjs +3 -1
  110. package/src/modules/bishop-plan.mjs +5 -3
  111. package/src/modules/bishop.mjs +13 -11
  112. package/src/modules/choices.mjs +2 -0
  113. package/src/modules/correo.mjs +2 -0
  114. package/src/modules/enlaces.mjs +2 -0
  115. package/src/modules/git-pulse.mjs +2 -0
  116. package/src/modules/github.mjs +2 -0
  117. package/src/modules/helpers.mjs +2 -0
  118. package/src/modules/image-studio.mjs +3 -1
  119. package/src/modules/index.mjs +4 -1
  120. package/src/modules/intents-calibration.mjs +2 -0
  121. package/src/modules/intents-desk.mjs +4 -2
  122. package/src/modules/intents-observe.mjs +2 -0
  123. package/src/modules/intents-policy.mjs +4 -1
  124. package/src/modules/intents-try.mjs +2 -0
  125. package/src/modules/intents.mjs +8 -6
  126. package/src/modules/mcp-connect.mjs +293 -0
  127. package/src/modules/ollama.mjs +17 -3
  128. package/src/modules/playwright.mjs +25 -10
  129. package/src/modules/ripley.mjs +2 -0
  130. package/src/modules/runs.mjs +5 -3
  131. package/src/modules/sdk.mjs +2 -0
  132. package/src/modules/updates.mjs +2 -0
  133. package/src/mother.mjs +2 -0
  134. package/src/ollama.mjs +2 -0
  135. package/src/outbound.mjs +24 -5
  136. package/src/override.mjs +2 -0
  137. package/src/ports.mjs +2 -0
  138. package/src/prices.mjs +2 -0
  139. package/src/privacy.mjs +2 -0
  140. package/src/quota-monitor.mjs +2 -0
  141. package/src/quota-sources.mjs +2 -0
  142. package/src/request-guard.mjs +2 -0
  143. package/src/review-ask.mjs +2 -0
  144. package/src/room/archivist.mjs +2 -0
  145. package/src/room/attachments.mjs +2 -0
  146. package/src/room/budget.mjs +2 -0
  147. package/src/room/context.mjs +2 -0
  148. package/src/room/control.mjs +7 -1
  149. package/src/room/copilot.mjs +76 -0
  150. package/src/room/economy.mjs +2 -0
  151. package/src/room/escalation.mjs +3 -0
  152. package/src/room/ghost.mjs +2 -0
  153. package/src/room/guard.mjs +2 -0
  154. package/src/room/prompt.mjs +13 -4
  155. package/src/room/returns.mjs +82 -0
  156. package/src/room/runs.mjs +4 -0
  157. package/src/room/vectors.mjs +2 -0
  158. package/src/room.mjs +264 -45
  159. package/src/router.mjs +2 -0
  160. package/src/runs.mjs +2 -0
  161. package/src/runtime-detection.mjs +2 -0
  162. package/src/salas.mjs +2 -0
  163. package/src/sentinel-errors.mjs +2 -0
  164. package/src/server-sentinel.mjs +2 -0
  165. package/src/server.mjs +485 -55
  166. package/src/setup.mjs +2 -0
  167. package/src/smtp.mjs +2 -0
  168. package/src/tour.mjs +26 -9
  169. package/src/updates.mjs +2 -0
  170. package/src/usage-sentinel.mjs +2 -0
  171. package/src/vault.mjs +2 -0
  172. package/src/verdict.mjs +3 -1
  173. package/src/whats-new.mjs +12 -10
  174. package/docs/madre-banner.svg +0 -25
package/docs/REFERENCE.md CHANGED
@@ -77,13 +77,17 @@ Cada mensaje sale con un modo. Tu modo es el techo de cualquier plan que ese men
77
77
 
78
78
  **EDITAR por dentro.** Antes del turno, un commit real bajo `refs/madre/checkpoints/` que no toca tu rama, tu índice ni tu stash. Durante el turno, `.git/`, `.pulse/`, `.madre/`, los `.env` y `.claude/settings.local.json` quedan en solo lectura a nivel de sistema de archivos y recuperan sus permisos al terminar. Después, la lista de archivos añadidos, modificados y borrados, y `DESHACER` restaura el punto de restauración. Desbloquear `#3` pide el nombre del proyecto; desbloquear `#4` lo pide dos veces. En `#4` cada CLI recibe su herramienta de comandos (Codex sin sandbox de red, Claude `Bash`, Gemini `run_shell_command`, OpenCode `bash`) y la instrucción de decir en una línea qué va a salir y adónde antes de que salga.
79
79
 
80
- **Solicitud de permiso.** Si un plan en `#1` llega a un paso que pide crear algo, el proyecto se detiene y pregunta: `GRANT ONCE · GRANT FOR PLAN · DENY`, con cronómetro de tres minutos. Solo el humano concede; un permiso escrito por un agente dentro de la conversación no cuenta.
80
+ **Solicitud de permiso.** Si un plan en `#1` llega a un paso que pide crear algo, el proyecto se detiene y pregunta: `GRANT ONCE · GRANT FOR PLAN · DENY`, con cronómetro de tres minutos. Solo el humano concede; un permiso escrito por un agente dentro de la conversación no cuenta. Un paso que pide `#3` o `#4` también se detiene: se desbloquea con la llave de ese modo y de ese agente. Concederlo para el plan no desbloquea a los demás agentes.
81
81
 
82
- **Modo por paso.** Un orquestador puede pedir el modo de cada paso: `@codex #2: crea la página`, `@claude #3: arregla el router`. MADRE lo acota al modo de tu mensaje y al `MAX MODE` de ese agente. Con tu mensaje en `#3`, la palabra del orquestador basta; con tu mensaje en `#1`, un paso `#2` pasa por la solicitud de permiso.
82
+ **Un permiso con su tiempo.** Un agente que necesita más lo pide en una línea con el modo y cuánto («Necesito #3 por 15 min: …»). Su respuesta lleva una tarjeta con el modo, el tiempo que pidió y los que hay (#3: 5, 15 o 30 min; #4: 5 min) o solo ese mensaje; la llave abre esa ventana para ese agente.
83
+
84
+ **Copiloto.** El robot junto a modo · modelo · esfuerzo. Se enciende con la llave de `#3`, una vez, por 30 min, 1, 4, 8 o 24 h; `DETENER TODO`, apagarlo o un reinicio lo terminan. Mientras dura, un mensaje en `#3` no pide llave y va al agente al que le escribes, aunque su Modo máximo sea `#2`, siempre que su CLI pueda escribir. Ese agente edita el proyecto, arma planes y da a cada paso hasta `#3`, y los comandos que pide y son seguros —leer (`ls`, `cat`, `rg`…), pruebas y builds (`npm test`, `npm run build`, `node --test`, `pytest`, `go test`…), git local (`status`, `diff`, `log`, `add`, `commit`)— corren solos y su resultado le regresa; cualquier otra línea espera tu botón. Lo que borra vuelve al terminar el turno, nunca toca `.git/`, `.pulse/`, `.madre/` ni los `.env`, y `#4` sigue pidiendo su propia llave. Tras ocho rondas de comandos sin que escribas, se detiene y avisa.
85
+
86
+ **Modo por paso.** Un orquestador puede pedir el modo de cada paso: `@codex #2: crea la página`, `@claude #3: arregla el router`. Sin número, el paso solo lee, o crea si el plan ya puede crear: `#3` se pide por su nombre. MADRE respeta el `MAX MODE` de cada agente. Con tu mensaje en `#3`, la palabra del orquestador basta para un paso `#3`; con tu mensaje en `#1`, un paso `#2` pasa por la solicitud de permiso y `#3` o `#4` pide tu llave. Un paso `#4` pide siempre la llave de ese agente, aunque tu mensaje vaya en `#4`.
83
87
 
84
88
  **Dos controles por agente.** El Modo máximo, en Ajustes → Permisos, dice hasta dónde puede llegar un mensaje dirigido a cada agente; el Modo inicial, en Ajustes → Agentes, dónde empieza: `#1` solo lectura hasta que armes CREAR, o `#2` para que cada turno pueda añadir archivos sin pedirlo. Aparte, dos habilidades: generar imágenes y web.
85
89
 
86
- **Comandos que pide un agente.** Con el módulo **Comandos** encendido, un agente en `#1`, `#2` o `#3` que necesita un comando que no puede correr (las pruebas, un build, un linter) termina su respuesta con un bloque `pulse-run`: el motivo en la primera línea y un comando por línea, cada uno con `$`. MADRE muestra cada línea como un botón y no corre nada hasta que lo presionas. Cada línea corre sola, desde la raíz del proyecto y **sin shell**: lo que lees en el botón es exactamente lo que se ejecuta, así que las líneas con `|`, `&&`, `;`, redirecciones, `$VARIABLES`, comodines, `~` o `cd` se muestran con el motivo y no se pueden correr. Antes de correr, MADRE toma un punto de restauración; la salida vuelve al proyecto como tarjeta, la leen todos los agentes en su siguiente turno, y si el comando cambió archivos, `DESHACER` los regresa. Lo que el comando haya mandado fuera de la máquina no regresa. Un comando a la vez, diez minutos como máximo, y `DETENER` en su tarjeta o `DETENER TODO` lo detienen. Un comando que abre un puerto es un servidor: no tiene límite de tiempo, su tarjeta dice dónde escucha y lo abre en TUS SERVIDORES, y mientras sirve puedes correr otro comando. Los agentes saben que un servidor para el proyecto escucha solo en `127.0.0.1`. En `#4` el agente corre sus propios comandos y no se le enseña el bloque.
90
+ **Comandos que pide un agente.** Con el módulo **Comandos** encendido, un agente en `#1`, `#2` o `#3` que necesita un comando que no puede correr (las pruebas, un build, un linter) termina su respuesta con un bloque `pulse-run`: el motivo en la primera línea y un comando por línea, cada uno con `$`. MADRE muestra cada línea como un botón y no corre nada hasta que lo presionas. Cada línea corre sola, desde la raíz del proyecto y **sin shell**: lo que lees en el botón es exactamente lo que se ejecuta, así que las líneas con `|`, `&&`, `;`, redirecciones, `$VARIABLES`, comodines, `~` o `cd` se muestran con el motivo y no se pueden correr. Antes de correr, MADRE toma un punto de restauración; la salida queda en el proyecto como tarjeta plegada y, cuando corrieron todas las líneas que pueden correr, **vuelve al agente que las pidió** en un turno propio, con el modo que tenía (hasta `#3`; desde el teléfono, hasta `#2`), lo que estaba contestando y la salida de cada línea. Si ese agente sigue contestando, espera; `DETENER TODO` la retiene. **Correr todos** corre las líneas una tras otra y **Devolver lo que corrió** entrega lo que hay sin el resto. Si el comando cambió archivos, `DESHACER` los regresa. Lo que el comando haya mandado fuera de la máquina no regresa. Un comando a la vez, diez minutos como máximo, y `DETENER` en su tarjeta o `DETENER TODO` lo detienen. Un comando que abre un puerto es un servidor: no tiene límite de tiempo, su tarjeta dice dónde escucha y lo abre en TUS SERVIDORES, y mientras sirve puedes correr otro comando. Los agentes saben que un servidor para el proyecto escucha solo en `127.0.0.1`. En `#4` el agente corre sus propios comandos y no se le enseña el bloque.
87
91
 
88
92
  ---
89
93
 
@@ -113,7 +117,7 @@ Un agente puede poner a trabajar a los demás. Si le pides coordinar, termina su
113
117
  @claude: Compara ambas síntesis y marca dónde divergen.
114
118
  ```
115
119
 
116
- MADRE ejecuta los pasos como turnos normales: cada uno queda en el ledger, pasa por traspaso, presupuesto y timeout. El paso dirigido al orquestador es su turno de cierre. Un paso del plan no arma otro plan, así que todo plan termina. Máximo cuatro pasos más el cierre.
120
+ MADRE ejecuta los pasos como turnos normales: cada uno queda en el ledger, pasa por traspaso, presupuesto y timeout. Tras las respuestas, el orquestador recibe un turno de cierre aunque no lo haya escrito como paso. Puede proponer el siguiente tramo si aún queda trabajo dentro de los permisos concedidos; MADRE permite hasta tres tramos por petición. Los delegados no abren planes propios. Cada tramo tiene como máximo cuatro pasos más el cierre.
117
121
 
118
122
  **TURNOS.** En Diagnóstico, junto al centinela. Encendido por defecto: una conversación que sigue trabajando cuando abres otra no se detiene, sigue escribiendo su registro y el panel de conversaciones la marca hasta que termina. Dos límites: conversaciones trabajando a la vez (2) y turnos a la vez en cada una (3); un mensaje que los pasaría se rechaza con el motivo antes de empezar. Todas las conversaciones comparten un solo titular de EDITAR o ACCESO TOTAL. Apagado, una sola conversación maneja a los agentes y no se puede cambiar de una que está trabajando. `DETENER TODO` detiene todas.
119
123
 
@@ -190,11 +194,13 @@ El botón de la barra abre la pantalla de diagnóstico. Escribe un síntoma, un
190
194
  | **IA local** | Búsqueda inteligente, archivista y `@madre` en local, gratis y sin cuenta. Se instala, se despierta y descarga su modelo desde Conecta tus agentes |
191
195
  | **Navegador de pruebas** | Un navegador headless en los turnos que piden ver, probar o capturar una página. Solo alcanza esta MADRE y los servidores que arrancaste desde COMANDOS: abrir la Vista previa o la app servida, hacer clic, leer consola, capturas al borrador del turno. Al encenderlo, MADRE comprueba que el servidor arranque con su navegador. Requiere `@playwright/mcp` |
192
196
  | **GitHub** | `/gh`: pull requests abiertos, el CI de tu rama e issues abiertos como tarjeta. `/gh pr [n]`, `/gh ci`, `/gh issues`. `/gh pr create "título"`, `/gh comment <n> "texto"` y `/gh issue "título"` enseñan primero lo que se publicaría y solo publican con `confirm`. Los agentes leen en cualquier modo y escriben solo en `#4` ACCESO TOTAL. Entra con tu sesión de `gh`; sin ella, con un token de acceso detallado guardado en la bodega de MADRE |
193
- | **Comandos** | Un agente te pide correr un comando que su modo no le deja correr; cada línea es un botón, corre sin shell desde la raíz del proyecto, con punto de restauración antes y la salida de vuelta en el proyecto. Un comando que abre un puerto es un servidor: sigue corriendo hasta que lo detienes desde su tarjeta, y mientras sirve puedes correr otro. Cuesta unos 300 tokens de instrucción por turno debajo de ACCESO TOTAL mientras está encendido |
197
+ | **Comandos** | Un agente te pide correr un comando que su modo no le deja correr; cada línea es un botón, corre sin shell desde la raíz del proyecto, con punto de restauración antes, y al terminar la salida vuelve al agente que la pidió para que siga. Un comando que abre un puerto es un servidor: sigue corriendo hasta que lo detienes desde su tarjeta, y mientras sirve puedes correr otro. Cuesta unos 300 tokens de instrucción por turno debajo de ACCESO TOTAL mientras está encendido |
194
198
  | **Ahorro de tokens** | La economía de tokens del proyecto. El interruptor pide a los agentes respuestas en prosa compacta; lo demás está siempre encendido y no se nota: el briefing lleva solo los bloques que el turno puede usar, lo que nunca cambia se lee primero para que el caché lo reconozca, y la transcripción se queda quieta en vez de deslizarse. Nada de lo que tú escribes se altera. En su ventana, en Módulos, se ve a dónde se van los tokens |
195
199
  | **Intenciones** | Bajo la caja, cuánto debe pensar Claude Code o Codex para el mensaje que escribes: subir cuando la petición parece pedir más, bajar solo cuando se vio o se midió que basta. Aprende primero de tu uso real, sin gastar tokens: lee en el registro del proyecto qué nivel usaste para cada tipo de pedido y si te alcanzó (seguiste con otra cosa) o se quedó corto (fallo, mala calificación o lo volviste a pedir en 15 minutos); esa lectura vive solo en memoria. Las pruebas rápida y completa de su tarjeta miden más rápido, con preguntas reales del proyecto y un juicio a ciegas, qué nivel basta para cada tipo de pregunta. Las mediciones viven en `~/.pulse/rooms/<sala>/intents.jsonl`. Nada cambia solo |
196
200
  | **Continuidad** | Integración externa opcional: estado verificado del proyecto, checkpoints y handoffs en `.ahp/`; `/ahp status`, `/ahp check`, `/ahp context` |
197
201
 
202
+ **Herramientas externas (MCP)** (antes «Conectar MCP») vive en **Ajustes › Herramientas externas (MCP)** de cada proyecto, no en Módulos. Agrega un servidor MCP por comando local o por dirección web (sin sesión, con token o iniciando sesión con OAuth: MADRE se registra como cliente público, sin secreto, y la vuelta cae en el propio proyecto), o tráelo de `.mcp.json`, `opencode.json`, Claude Code, Codex, Gemini CLI o Cursor; al importar solo se leen los nombres y los valores van a la bodega. Antes de entregárselo a un turno, MADRE lo arranca y le pide sus herramientas: si no responde, se queda fuera y su fila dice por qué. Las herramientas que el servidor marca como de solo lectura van desde `#1`; las que actúan, desde el modo que elijas por servidor (`#4` si no lo bajas). Las cuatro CLIs arrancan el mismo intermediario de MADRE (`src/mcp/proxy.mjs`), que lee los secretos de la bodega, deja pasar solo las herramientas permitidas y habla HTTP con los servidores remotos: ningún secreto queda en la línea de comandos ni en un archivo del proyecto. La lista vive junto al registro del proyecto (`~/.pulse/rooms/<sala>/mcp.json`).
203
+
198
204
  Cada módulo es un archivo. Los tuyos van en `~/.pulse/modules/` (todos los proyectos) o en `<proyecto>/.madre/modules/` (ese proyecto): un `.mjs` con `export default { … }`, sin build ni registro, con interruptor, ajustes, comandos `/nombre`, herramientas MCP para los agentes y rutas propias. `RELOAD MODULES` lo recarga sin reiniciar. Guía y ejemplo listo para copiar en [`docs/SDK.md`](SDK.md). Cómo escribir uno, en [CONTRIBUTING.md](../CONTRIBUTING.md#writing-a-module).
199
205
 
200
206
  ---
@@ -229,6 +235,9 @@ En un proyecto, la tecla junto a la casa **cambia de proyecto**: su indicador di
229
235
  | `GET /api/looks` · `POST /api/looks` | La apariencia que comparten Inicio y todos los proyectos: tema, acento, fondo y sus dos diales, burbujas y texto. Se guarda en `~/.pulse/looks.json`, una por persona; cada página la lee al abrir y al volver a verse, y la escribe al cambiarla. Lo que Inicio elige para sus tarjetas se queda en su navegador | Las páginas de esta Mac |
230
236
  | `GET /api/tour/projects` · `POST /api/tour/projects` | Los proyectos de 0.7.2 que Inicio no puede listar (sin `project.json`) y traer uno: se busca su carpeta por nombre en las carpetas de siempre y se confirma por el hash de su id. Los quitados a propósito no vuelven | Las páginas de esta Mac |
231
237
  | `POST /api/override/arm` | La llave de #3 y #4, comprobada por el proyecto (`src/override.mjs`): lo que se escribió, una o dos veces, y un pase para ese agente y ese modo. Un mensaje a #3 o #4 va solo con su pase; sin permiso recordado abre un mensaje, con él, los que quepan en sus minutos. STOP ALL y un reinicio los retiran. Ocho llaves equivocadas en un minuto responden 429. La huella de la frase nunca sale por `GET /api/settings` ni `/api/state` | Las páginas de esta Mac |
238
+ | `GET /api/copilot` · `POST /api/copilot` · `POST /api/copilot/off` | El copiloto: si está encendido y hasta cuándo; encenderlo con la llave de `#3` (`{ minutes, words }`, 30 a 1440 min) y apagarlo. Un mensaje con `copilot: true` en `#3` va sin pase mientras dura; apagado responde 409 con `copilotOff`. Nunca desde un teléfono | Las páginas de esta Mac |
239
+ | `POST /api/runs/return` | Devolver al agente lo que corrió de su petición de comandos sin el resto (`{ responseMessageId }`). Cuando corren todas sus líneas, se devuelve sola | Las páginas del proyecto |
240
+ | `GET/POST /api/x/mcp/servers` · `POST /api/x/mcp/servers/<id>/check · toggle · actions · remove · signin` · `GET/POST /api/x/mcp/import` · `GET /api/x/mcp/oauth/callback` | Herramientas externas (MCP): la lista sin valores, agregar y revisar, encender, desde qué modo actúa, quitar (con sus secretos), iniciar sesión con OAuth y su vuelta, y lo que se puede traer de otras apps | Las páginas de esta Mac; la vuelta de OAuth, el navegador |
232
241
  | `GET /api/enlace/memories` | Lo que este proyecto entrega por un contrato: solo `travels()` y los tipos del contrato, redactado; 404 si el contrato no sirve a quien pide, 423 sellado, 429 sobre el tope | Otro proceso de MADRE con la llave del canal (`~/.pulse/credentials/enlaces.json`), sin `Origin` |
233
242
  | `POST /api/enlace/ask` | Lo que este proyecto pide a otro; solo para un turno que corre aquí (409 si no); registra `enlace.received` con agente y turno | El servidor `pulse-enlaces` de un turno, con la llave |
234
243
  | `POST /api/salas/enlaces/recall` | Marcar o quitar «Incluir siempre» de una conexión | La página de Inicio, nunca un proceso |
@@ -274,9 +283,10 @@ Los planes viven en `bishop-plans.json` junto al registro del proyecto del Coord
274
283
 
275
284
  ## LO QUE SALE DE LA MÁQUINA
276
285
 
277
- - **Nada por sí solo.** MADRE no tiene nube, cuenta ni backend. No guarda credenciales de proveedores.
286
+ - **Sin nube ni cuenta.** MADRE no tiene cuenta ni backend que guarde lo tuyo. No guarda credenciales de proveedores.
278
287
  - **Lo que un agente lee, viaja a su proveedor.** Codex a OpenAI, Claude Code a Anthropic, Gemini CLI a Google, OpenCode a quien tenga configurado. Si `OPENAI_BASE_URL` o `ANTHROPIC_BASE_URL` cambia ese destino, MADRE enseña solo el hostname y bloquea el turno antes de armar el briefing; un gateway verificado se autoriza por agente con `PULSE_ALLOW_CUSTOM_AGENT_ENDPOINTS`. Aplican la cuenta, los límites y los términos del destino efectivo. `@madre` y el archivista con Ollama no salen de la máquina.
279
- - **Dos envíos propios, ambos bajo tu interruptor.** El sentinel, apagado por defecto, envía reportes redactados al colector del proyecto. El canal de liberación, encendido por defecto, pregunta a npm por la última versión: viaja el nombre del paquete, nada más, la misma petición que hace `npx`. `PULSE_UPDATE_CHECK=0` lo apaga.
288
+ - **Un aviso diario de que sigue en uso, siempre encendido.** Una vez al día cada copia le dice a madre.run que está en uso: un identificador al azar que la copia creó para sí (`~/.pulse/install-id`), la versión de MADRE, el sistema y la versión mayor de Node. Nada más: ni nombre, ni correo, ni proyecto, ni rutas, ni agentes, ni nada de lo que se dice en un proyecto; madre.run no guarda la IP. Es la forma en que el autor sabe cuántas personas usan MADRE, qué versiones corren y si regresan. Sale por el mismo registro que todo lo demás, así que aparece en «Lo que se envía». Sin red, falla en silencio. (`src/heartbeat.mjs`)
289
+ - **Dos envíos propios bajo tu interruptor.** El sentinel, apagado por defecto, envía reportes redactados al colector del proyecto. El canal de liberación, encendido por defecto, pregunta a npm por la última versión: viaja el nombre del paquete, nada más, la misma petición que hace `npx`. `PULSE_UPDATE_CHECK=0` lo apaga.
280
290
  - **Escritura.** En `#1` nadie escribe. En `#2` solo se añade: lo que existía se restaura al terminar el turno. En `#3` todo el proyecto salvo las zonas prohibidas, con punto de restauración y `DESHACER`. En un proyecto sin git, MADRE guarda sus fotografías en un repositorio sombra fuera del proyecto. Un comando que pide un agente lo corres tú, con punto de restauración antes y `DESHACER` después.
281
291
  - **Memoria.** Todo lo dicho fuera de INCÓGNITO queda en `~/.pulse/rooms/<sala>/` y vuelve a los prompts de todos los agentes de ese proyecto. INCÓGNITO es la salida para lo que no debe recordarse; PRIVACY, para los nombres que nunca deben aparecer.
282
292
 
@@ -0,0 +1,103 @@
1
+ # MADRE under the hood
2
+
3
+ What the README does not need to tell you to use the room, but anyone who wants to understand it, run it under unusual conditions or write a module does. Every claim here corresponds to code in `src/` and has a test in `test/`.
4
+
5
+ ## The ledger
6
+
7
+ Each project has a stable room under `PULSE_HOME` (by default `~/.pulse/rooms/<sala>/`). Its source of truth is `events.jsonl`: one event per line, increasing sequence, append-only for the room. MADRE rebuilds the conversation window from there even if it restarts or is opened from another IDE.
8
+
9
+ Writes are serialized across local processes with an on-disk lock, so two IDEs on the same room never produce repeated sequences. The only operation that rewrites the ledger is the privacy purge, under the same lock, atomic (temporary file and rename), preserving sequences.
10
+
11
+ When the replying agent changes, the room records `handoff.created` with origin, destination and the range of sequences handed over. The transcript remains the durable source; the project is not touched.
12
+
13
+ An agent's errors are stored, bounded, in `message.failed`: one line of up to 500 characters, without stack traces, and with private terms replaced.
14
+
15
+ ## The stream
16
+
17
+ `/api/events` is fed from the ledger, not from the process's memory: events that another MADRE process adds to the same room reach the open pages. Polling reads only the new bytes every 500 ms (`PULSE_BROADCAST_INTERVAL_MS`); a file that shrinks, after a purge, resets the offset. Each frame carries `id: <secuencia>`, so a client that reconnects asks from where it left off. A client that stops consuming is disconnected once it accumulates 1 MiB undrained (`PULSE_SSE_MAX_BUFFERED_BYTES`). GHOST events have no sequence: they reach the open pages and never the ledger.
18
+
19
+ The context window an agent receives is 16,000 characters (`PULSE_CONTEXT_MAX_CHARS`); older messages are omitted before recent ones. A message of more than 20,000 characters (`PULSE_MAX_MESSAGE_CHARS`) is recorded and rejected without invoking the agent.
20
+
21
+ ## The memory
22
+
23
+ `memory.sqlite` lives next to the ledger and is derived from it: if it is missing or its schema changed, it is rebuilt from `events.jsonl`. It contains:
24
+
25
+ - `entries` with trigram FTS5: every message, failure and command card outside GHOST, with its sequence. MADRE's canned replies (`synthetic`) are not included.
26
+ - `memories` with FTS5: the distilled notes, typed (`decision`, `fact`, `preference`, `question`), with the sequences that support them, who wrote them and their origin (`distilled` or `noted`).
27
+ - `entry_vectors` and `memory_vectors`: 768-dimension embeddings, computed in the background and never on a turn's critical path.
28
+
29
+ **Conversations.** A project has one memory and many conversations. The archive, the crew, the modules and the privacy list belong to the project; a conversation is only the record of one line of work. The first one is the `events.jsonl` that was always there —no file is moved to add this—, the others live in `<sala>/chats/<id>/events.jsonl`, and `<sala>/chats.json` keeps their names and which one is open. Numbering belongs to the project, not to the conversation: opening one starts from the highest sequence any other one reached, so `#1411` means an exchange of this project and the memory index, the citations and NOSTROMO still hold. There are gaps in a ledger and that is fine: sequences are an order, not a count.
30
+
31
+ Only one conversation at a time drives the crew —two threads editing the same working tree is not a feature, it is a way to lose work—, so opening another one is refused while a turn is running. And one room per project: `<sala>/open.json` holds the pid and port of the server that has it, and another start on the same project is refused with the address of the open room. Without that, two servers writing different conversations of the same project would hand out the same sequence twice and the archive would silently keep only one of them.
32
+
33
+ **Recall.** When the transcript exceeds the window, each turn also receives, within the same budget (`PULSE_RECALL_SHARE`, 30% by default), the earlier notes and exchanges that match the request. The lexical search weights each term by its rarity in the room: a path or a name weighs more than a common word. With vectors, it is fused with cosine similarity.
34
+
35
+ **Cascade activation.** Each memory that enters a turn leaves a row with the batch it shared, so the room knows which notes arrive together. From that comes an association —Jaccard over the turns where each one was found by the search itself— and recall keeps two slots for it: when it brings a note, it also brings the one that accompanies it, even if they do not share a single word. Only the turns where the search found them on their own merit vote, never the ones the cascade created, or the network would close in on itself within a few days. The strength is a ratio: a pair that stops co-occurring fades on its own. Threshold 0.34, at least two co-occurrences, and the search never loses a slot to the association. `PULSE_RECALL_CASCADE=0` or the switch in MU/TH/UR turn it off.
36
+
37
+ **Cold zones.** A memory is cold when three things hold at once: no turn has ever carried it, it shares no topic with any other —so it cannot be reached sideways either— and the archive has been opened at least twelve times since it was written. The third is the one that matters: never-recalled is what every note is on the day it is born; cold is the opportunity that passed it by. Opportunities are counted in turns that actually went into the archive, and only from the day the room started keeping track. NOSTROMO counts them in its header and surrounds them with a faint ring when asked to.
38
+
39
+ **What to ask.** The room writes the questions whose answer it is missing, always with the words it already has and never inventing a topic nobody raised. Three wells: the questions the archivist recorded as open and nobody answered, the cold memories —asking is the honest alternative to throwing away something that never had its chance— and the kind of note the archive is short on (decisions, preferences, facts; not questions, because an archive short on questions is not fixed by asking for more). They are taken in turns so that a full well is not the whole list, and two ways of asking the same thing count as one. Nothing is sent: the question goes to the composer and the human decides who answers.
40
+
41
+ **The verdict.** `GET /api/maturity` gathers the six readings, the three tests, the cold zones and the pending questions, and returns a sentence and an instruction. The order is not decided by the score: first what is false (open contradictions), then what the archive cannot answer —and there it points to the questions the room already wrote—, then the weakest reading quoting its own advice, and finally the test nobody has run. Consistency is computed on read; coverage refreshes itself once a day, in the background and only with local embeddings.
42
+
43
+ **The three tests.** The maturity reading tells what the archive is made of; it does not say whether it works. A test says that, and a test is only worth something if it can fail. `COVERAGE` takes real questions from the history, runs recall at the exact point where each one was asked and compares it with the answer that was actually given. `CONSISTENCY` looks at the contradictions EYECAT still holds, what was taken out of circulation and whether aberrations are being archived more often lately or less. `MATCH` asks the local model again questions that a frontier CLI answered and compares. None of them spends a provider turn; the third runs in the background and can be stopped.
44
+
45
+ All three are measured **against a control**: inside a room everything talks about the same topics, so to an embedder any pair of texts seems close —the first COVERAGE run scored thirty out of thirty—. To count, what the archive delivered has to beat what it would have delivered for another question, by a margin. Each result says how many cases it had, what it measured with (meaning or words), the bar and the mean against the control.
46
+
47
+ **Distillation.** Every `PULSE_DISTILL_EVERY` undistilled exchanges, or after `PULSE_DISTILL_IDLE_MS` idle, the archivist reads a batch bounded by `PULSE_DISTILL_MAX_CHARS`, from most recent backward, and writes up to five notes. The archivist is the cheapest allowed one in the order Ollama, Gemini, OpenCode, Codex, Claude; the one that fails sits on the bench for thirty minutes and the next one steps in. A single call per batch, never during a turn. For local models, strict JSON is requested.
48
+
49
+ **Embeddings.** `PULSE_EMBED_PROVIDER=auto` uses Ollama if it is running with an embeddings model (`nomic-embed-text`), otherwise the Gemini key (`gemini-embedding-001`, the same key the Gemini CLI uses, including the one in the macOS keychain). Batches of up to 100 texts per call. `PULSE_EMBED=0` leaves recall lexical.
50
+
51
+ **MCP tools.** Each turn attaches to the CLI the `pulse-memory` server with per-run isolated configuration: `memory_search`, `memory_recall`, `memory_notes`, `memory_timeline`, `project_state` and `memory_note`. `memory_note` is signed with the agent and the turn's message, is rejected in GHOST and its notes are marked `noted`.
52
+
53
+ **NOSTROMO and CODE000.** The server requires the project's designation on `GET /api/memory` and `DELETE /api/memory/:id`. Eight taps on the heart within thirty seconds seal the archive for ten minutes (both routes return 423), eject the console and fire a message encrypted with AES-256-GCM under the room's seal (`<proyecto>/.pulse/mother.env`) that all online agents receive decoded as requester `mother`. If the seal changes or disappears, the room detects it and warns.
54
+
55
+ **Privacy.** The terms in `config.json` are replaced at four points: the agent's reply before recording it, the index on insert, the notes when saving them and the dataset when exporting it. The purge rewrites ledger, index and notes preserving sequences and the distilled mark. The server rereads the terms before each human message, because `config.json` is shared by all the rooms on the machine.
56
+
57
+ ## The limits sentinel
58
+
59
+ Each sphere in the bar carries a ring. It shows the provider's real limit when the CLI publishes it, otherwise the local window.
60
+
61
+ - **Codex** writes in each session rollout (`~/.codex/sessions`) its account windows, 5-hour and weekly, with percentage used and reset time. MADRE reads the most recent one; there is no network involved.
62
+ - **Claude Code** publishes `/usage` on Anthropic's OAuth endpoint. With `PULSE_CLAUDE_USAGE=1`, MADRE queries it with the token Claude Code stores in the keychain or in `~/.claude/.credentials.json`; the token only travels to `api.anthropic.com`, as the CLI itself does. It is optional because it involves reading a credential. `PULSE_OFFICIAL_QUOTA=0` disables all provider reads.
63
+ - **Gemini and OpenCode** do not publish anything locally: their ring is the local window.
64
+
65
+ The local window is a soft budget per agent (500,000 tokens) over a rolling 5-hour window; turns drop out of the count as they age, cache reads weigh one tenth and `@madre`'s tokens weigh zero. It warns at 80, 90 and 100% and suggests other agents. A window whose reset time has already passed counts as empty; the monitor rereads the sources every minute and announces `limit.cleared` when a full window goes back to normal.
66
+
67
+ A quota reader implements `{ id, agent, read() }` and `read()` returns `null` or `{ usedPercent, resetAt, windows?, stale? }`. MADRE never infers the provider's quota from local tokens.
68
+
69
+ ## The adapters
70
+
71
+ Each agent runs as a process in its own group, with an isolated home that receives only its existing credentials. If it does not respond before the timeout (180 s by default), MADRE terminates the whole tree: SIGTERM and, after a grace period, SIGKILL.
72
+
73
+ - **Codex**: read-only query; `-C <carpeta> --sandbox workspace-write` in CREATE; in CONTROL, a write sandbox over the project. It generates images with `image_generation` using its ChatGPT account.
74
+ - **Claude Code**: local read tools, non-persistent sessions, MCP limited to MADRE's servers. In CREATE, `--allowedTools Write(//<carpeta>/**),Edit(//<carpeta>/**)` under `dontAsk`: the double slash is the absolute form; with a single one, Claude reads the path as relative to the project and denies every write. In CONTROL, writing allowed in the project and denied in the forbidden zones.
75
+ - **Gemini CLI**: Plan Mode and an ephemeral read-only policy, extended in CREATE with `allow` rules for `write_file` and `edit` whose `file_path` starts with the folder. It runs with a temporary `GEMINI_CLI_HOME`: OAuth tokens and `~/.gemini/.env` yes; hooks, extensions, MCP servers and memory from the real `~/.gemini` no. Gemini reads `@algo` as a file to include, so MADRE escapes each mention as `\@nombre` and unescapes it in the reply. Under 503 or 429, the CLI retries with backoff for minutes and only writes to stderr: MADRE reads it live, cuts off after `PULSE_GEMINI_IDLE_MS`, retries once with `PULSE_GEMINI_FALLBACK_MODEL` and, if that fails too, says so with the name and the model tried.
76
+ - **OpenCode**: ephemeral permissions injected per run, without touching the global configuration; per-pattern `permission.edit` in CREATE and CONTROL. If your configuration does not set a model, `run` picks the default provider, which may not be the one with a session: `PULSE_OPENCODE_MODEL=proveedor/modelo` sets it.
77
+ - **@madre**: it is not a CLI. It is a local adapter on top of Ollama that receives the recent transcript, what the memory recalls about the question and the question; never the CLIs' briefing. With an 8,192-token window, because the default 4,096 one truncates the system prompt. What it can resolve without a model, it resolves: identity, orders that are not its to take, requests to save memory and the round table, which is a plan written by the room with one step per online CLI and its wrap-up turn.
78
+
79
+ The image scopes of Claude, Gemini and OpenCode are fulfilled with **Image Studio**: the MCP server `src/mcp/image-server.mjs`, attached only inside a lease with the scope turned on, which generates with the Gemini images API and saves the file in the turn's folder.
80
+
81
+ ## CREATE under the hood
82
+
83
+ A turn in `#2` takes the same snapshot as CONTROL, without a seat: several `#2` turns can run at once. When it ends, `diff` against the snapshot: added files are kept and recorded as `artifacts.created` with their path in the project; modified, renamed or deleted ones are restored from the snapshot and announced in `create.reverted`. Forbidden zones are restored the same way as in CONTROL. Each CLI receives its write tools over the project: Claude Code denies `Write` if `Edit` is not allowed on the same path and OpenCode leaves no write tool if `edit` is denied (both verified with the real CLI), so in `#2` they go together and the "add only" guarantee is the restore afterward, not the rule beforehand. Gemini receives only `write_file`. The `scratchDir` under `.pulse/out/` still exists for what has no place and for Image Studio.
84
+
85
+ In a plan, each step's mode is the minimum of what the orchestrator asked for (`@agente #n:`; without a number, `#1`, or `#2` if there is a lease), the plan's ceiling (the mode of the human message) and the agent's `MAX MODE`. `#4` never reaches a delegate through the ceiling: only with that agent's key. Under a `#3` ceiling, a `#2` step receives a project lease issued in the orchestrator's name and a `#3` step takes CONTROL with its own checkpoint, one at a time. Under a `#1` ceiling, a `#2` step goes through escalation to the human. A `#3` or `#4` step that exceeds the ceiling asks the human for the key for that agent; granting it for the plan does not raise the others' ceiling.
86
+
87
+ ## CONTROL under the hood
88
+
89
+ Before the turn, MADRE snapshots the project as a real commit under `refs/madre/checkpoints/` with a temporary index (in a project without git, in a shadow repository under the system's temporary directory, with the project as the working tree): it includes untracked files, respects `.gitignore`, does not touch your branch, your index or your stash, and works in repositories with no commits. While the turn lasts, `.env*`, `.pulse/`, `.madre/` and `.claude/settings.local.json` are read-only at the file-system level and get their permissions back when it ends. Afterwards, `git diff` against the checkpoint gives the list of changes; any write into a forbidden zone that got through is reverted from the checkpoint and named. `UNDO` restores the full checkpoint.
90
+
91
+ ## Commands that come back and the copilot
92
+
93
+ A ```pulse-run stores the mode of the turn that asked for it. When every line that can run has an answer —it finished, or it opened a port and is serving—, `src/room/returns.mjs` builds what the agent reads: why it asked, what it was answering, the end of what it had said and each line's output (head and tail, about 10,000 characters across all of them), and the room opens a human turn marked `auto: 'runs'` with that block, at the mode of the original turn and never above `#3` (`#2` if a line was pressed from the phone). If the agent is still answering or a plan is running, it waits until the room is free; `STOP ALL` holds it until the human hands it back from its card. A request is handed back once. In the shared window, a command's output weighs at most ~1,200 characters: five long outputs no longer push the human's request out.
94
+
95
+ The copilot is a server window (`/api/copilot`), in memory like the passes: the `#3` key opens it for a time and `STOP ALL` or a restart close it. Each conversation checks it when accepting a message: one in `#3` marked `copilot` does not spend a pass and reaches any agent whose CLI writes. Its turn carries the `copilot` block (`src/room/copilot.mjs`); when it settles, what it deleted is restored from the restore point (`deletesReverted`). Its command requests run on their own when the turn releases the project, only the lines on the safe list, and the hand-back still belongs to the copilot while the window lasts. Eight solo rounds in a row and it stops with an alert.
96
+
97
+ ## Operational recovery
98
+
99
+ If MADRE stops in the middle of a turn, on startup it detects the `agent.started` events with no close and records a recovered `message.failed` for each one. When closing with Ctrl+C or `SIGTERM`, it interrupts the agent processes in progress, records those turns as failed, delivers the pending events to the open pages and exits. Plans run in sequence and delegates do not delegate. The orchestrator reviews the replies and can open another stretch, up to three per request; `STOPALL` cuts off anything in progress.
100
+
101
+ ## Packaging and tests
102
+
103
+ `npm test` runs the suite with `PULSE_OLLAMA=0` so as not to touch a real Ollama; no test calls a model. `npm run pack:check` packs, installs into an empty directory and runs the installed CLI: `--help`, `doctor` and a server start that serves the room and closes cleanly with `SIGTERM`. `PULSE_TEST_MODE=1` enables `/api/test/limits` to simulate quota windows.