@jossuealcala/madre 1.0.1 → 1.0.3

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 (189) hide show
  1. package/ADDITIONAL-TERMS.md +93 -0
  2. package/CHANGELOG.en.md +2013 -0
  3. package/CHANGELOG.md +102 -1
  4. package/CONTRIBUTING.md +1 -1
  5. package/LICENSE +661 -202
  6. package/NOTICE +26 -14
  7. package/README.en.md +241 -0
  8. package/README.md +21 -12
  9. package/TRADEMARKS.en.md +50 -0
  10. package/TRADEMARKS.md +33 -16
  11. package/bin/madre.cjs +40 -0
  12. package/bin/madre.mjs +7 -0
  13. package/docs/INTERNALS.md +6 -0
  14. package/docs/REFERENCE.md +40 -5
  15. package/docs/SDK.md +4 -2
  16. package/docs/en/INTERNALS.md +103 -0
  17. package/docs/en/REFERENCE.md +365 -0
  18. package/docs/en/SDK.md +308 -0
  19. package/docs/en/training/README.md +59 -0
  20. package/docs/training/README.md +48 -9
  21. package/docs/training/train.sh +7 -2
  22. package/package.json +13 -5
  23. package/public/abduction.js +2 -0
  24. package/public/app.js +3154 -539
  25. package/public/attribution.js +114 -0
  26. package/public/brands.js +23 -6
  27. package/public/code-tools.js +143 -0
  28. package/public/editor.js +22 -4
  29. package/public/es.js +1004 -416
  30. package/public/hardware.js +50 -0
  31. package/public/i18n.js +25 -1
  32. package/public/index.html +18 -11
  33. package/public/inquiry.js +2 -0
  34. package/public/loader.js +2 -0
  35. package/public/macroverso.js +189 -96
  36. package/public/market-art.js +161 -0
  37. package/public/market-view.js +529 -0
  38. package/public/market.js +189 -0
  39. package/public/neural.js +110 -0
  40. package/public/nostromo-engine.js +414 -47
  41. package/public/power.js +100 -0
  42. package/public/resay.js +11 -0
  43. package/public/review-ask.js +2 -0
  44. package/public/routing.js +23 -1
  45. package/public/salas-mac.css +119 -18
  46. package/public/salas-mac.html +14 -2
  47. package/public/salas-mac.js +358 -56
  48. package/public/salas.css +2 -0
  49. package/public/salas.html +1 -0
  50. package/public/salas.js +4 -2
  51. package/public/styles.css +1793 -77
  52. package/public/syntax.js +2 -0
  53. package/public/touch.js +2 -0
  54. package/public/tour-chapters.js +2 -0
  55. package/public/tour.js +84 -5
  56. package/public/troubleshooting.js +24 -17
  57. package/public/wallpaper.js +275 -0
  58. package/src/adapters/claude.mjs +2 -0
  59. package/src/adapters/codex.mjs +2 -0
  60. package/src/adapters/cursor.mjs +96 -0
  61. package/src/adapters/gemini.mjs +13 -4
  62. package/src/adapters/madre.mjs +5 -2
  63. package/src/adapters/opencode.mjs +7 -3
  64. package/src/adapters/process.mjs +2 -0
  65. package/src/asking.mjs +2 -0
  66. package/src/auth-probe.mjs +145 -12
  67. package/src/bridge/devices.mjs +2 -0
  68. package/src/bridge/handoff.mjs +2 -0
  69. package/src/bridge/host.mjs +2 -0
  70. package/src/bridge/network.mjs +2 -0
  71. package/src/bridge/policy.mjs +3 -1
  72. package/src/bridge/qr.mjs +2 -0
  73. package/src/bridge/server.mjs +2 -0
  74. package/src/capabilities.mjs +11 -0
  75. package/src/chats.mjs +2 -0
  76. package/src/checkpoint.mjs +18 -1
  77. package/src/choices.mjs +2 -0
  78. package/src/cli-args.mjs +2 -0
  79. package/src/cold.mjs +2 -0
  80. package/src/commands.mjs +2 -0
  81. package/src/config.mjs +2 -0
  82. package/src/conversation-context.mjs +15 -1
  83. package/src/credentials.mjs +35 -3
  84. package/src/dataset.mjs +78 -4
  85. package/src/directives.mjs +2 -0
  86. package/src/distiller.mjs +2 -0
  87. package/src/embeddings.mjs +2 -0
  88. package/src/enlaces.mjs +214 -6
  89. package/src/event-store.mjs +2 -0
  90. package/src/exam.mjs +6 -4
  91. package/src/extensions.mjs +13 -3
  92. package/src/eyecat-watch.mjs +2 -0
  93. package/src/eyecat.mjs +2 -0
  94. package/src/file-ops.mjs +2 -0
  95. package/src/files.mjs +32 -0
  96. package/src/github.mjs +2 -0
  97. package/src/heartbeat.mjs +2 -0
  98. package/src/i18n.mjs +31 -1
  99. package/src/image-studio.mjs +2 -0
  100. package/src/json-file.mjs +2 -0
  101. package/src/launch.mjs +2 -0
  102. package/src/lease.mjs +5 -1
  103. package/src/lobby-work.mjs +2 -0
  104. package/src/local-ai.mjs +2 -0
  105. package/src/looks.mjs +127 -2
  106. package/src/market-key.mjs +8 -0
  107. package/src/market-remote.mjs +239 -0
  108. package/src/maturity.mjs +3 -1
  109. package/src/mcp/connect.mjs +345 -0
  110. package/src/mcp/github-server.mjs +2 -0
  111. package/src/mcp/image-server.mjs +2 -0
  112. package/src/mcp/memory-server.mjs +2 -0
  113. package/src/mcp/proxy.mjs +153 -0
  114. package/src/mcp/smtp-server.mjs +2 -0
  115. package/src/memory-dashboard.mjs +2 -0
  116. package/src/memory-tools.mjs +2 -0
  117. package/src/memory.mjs +2 -0
  118. package/src/models.mjs +49 -3
  119. package/src/module-scope.mjs +68 -0
  120. package/src/modules/ahp.mjs +104 -7
  121. package/src/modules/ash-policy.mjs +2 -0
  122. package/src/modules/ash.mjs +3 -1
  123. package/src/modules/bishop-exam.mjs +122 -0
  124. package/src/modules/bishop-plan.mjs +5 -3
  125. package/src/modules/bishop.mjs +84 -23
  126. package/src/modules/choices.mjs +2 -0
  127. package/src/modules/correo.mjs +2 -0
  128. package/src/modules/enlaces.mjs +89 -6
  129. package/src/modules/git-pulse.mjs +2 -0
  130. package/src/modules/github.mjs +2 -0
  131. package/src/modules/helpers.mjs +2 -0
  132. package/src/modules/image-studio.mjs +13 -2
  133. package/src/modules/index.mjs +4 -1
  134. package/src/modules/intents-calibration.mjs +2 -0
  135. package/src/modules/intents-desk.mjs +4 -2
  136. package/src/modules/intents-observe.mjs +2 -0
  137. package/src/modules/intents-policy.mjs +4 -1
  138. package/src/modules/intents-try.mjs +2 -0
  139. package/src/modules/intents.mjs +11 -7
  140. package/src/modules/local-models.mjs +124 -0
  141. package/src/modules/mcp-connect.mjs +293 -0
  142. package/src/modules/ollama.mjs +15 -4
  143. package/src/modules/playwright.mjs +88 -15
  144. package/src/modules/ripley.mjs +2 -0
  145. package/src/modules/runs.mjs +5 -3
  146. package/src/modules/sdk.mjs +63 -9
  147. package/src/modules/updates.mjs +2 -0
  148. package/src/mother.mjs +2 -0
  149. package/src/npm-launch.mjs +18 -0
  150. package/src/ollama.mjs +8 -5
  151. package/src/outbound.mjs +16 -6
  152. package/src/override.mjs +2 -0
  153. package/src/ports.mjs +6 -2
  154. package/src/prices.mjs +2 -0
  155. package/src/privacy.mjs +2 -0
  156. package/src/quota-monitor.mjs +2 -0
  157. package/src/quota-sources.mjs +2 -0
  158. package/src/request-guard.mjs +2 -0
  159. package/src/review-ask.mjs +2 -0
  160. package/src/room/archivist.mjs +2 -0
  161. package/src/room/attachments.mjs +2 -0
  162. package/src/room/budget.mjs +2 -0
  163. package/src/room/context.mjs +2 -0
  164. package/src/room/control.mjs +7 -1
  165. package/src/room/copilot.mjs +76 -0
  166. package/src/room/economy.mjs +2 -0
  167. package/src/room/escalation.mjs +2 -0
  168. package/src/room/ghost.mjs +2 -0
  169. package/src/room/guard.mjs +2 -0
  170. package/src/room/prompt.mjs +25 -5
  171. package/src/room/returns.mjs +82 -0
  172. package/src/room/runs.mjs +4 -0
  173. package/src/room/vectors.mjs +2 -0
  174. package/src/room.mjs +223 -35
  175. package/src/router.mjs +3 -1
  176. package/src/runs.mjs +6 -1
  177. package/src/runtime-detection.mjs +11 -0
  178. package/src/salas.mjs +28 -0
  179. package/src/sentinel-errors.mjs +2 -0
  180. package/src/server-sentinel.mjs +2 -0
  181. package/src/server.mjs +757 -81
  182. package/src/setup.mjs +3 -1
  183. package/src/smtp.mjs +2 -0
  184. package/src/tour.mjs +2 -0
  185. package/src/updates.mjs +2 -0
  186. package/src/usage-sentinel.mjs +2 -0
  187. package/src/vault.mjs +2 -0
  188. package/src/verdict.mjs +3 -1
  189. package/src/whats-new.mjs +2 -0
package/docs/REFERENCE.md CHANGED
@@ -15,7 +15,7 @@ Necesitas Node 22.5 o superior y al menos una de estas CLIs con sesión iniciada
15
15
 
16
16
  1. Corre `npx @jossuealcala/madre` desde cualquier carpeta: abre Inicio, con todos tus proyectos y el Coordinador arriba. La primera vez lo acompaña un asistente de tres pasos: conectar los agentes (cada uno con su botón para instalarlo y firmarlo, ahí mismo; una vez para todos los proyectos), agregar los proyectos (eliges carpetas dentro de tu carpeta de usuario; agregar no abre) y abrir los que vas a usar. `npx @jossuealcala/madre start` dentro de una carpeta sigue abriendo ese proyecto directo; si no hay agentes, el proyecto abre igual en Conecta tus agentes para instalarlos y firmarlos.
17
17
  2. El proyecto abre en `http://127.0.0.1:4317`. Elige un agente en el selector o escribe `@claude …`. El chip junto a `to @agente` dice en qué modo sale el mensaje; `#1 SOLO CONVERSAR`, solo lectura, es el predeterminado.
18
- 3. Para sumar o reconectar una IA más tarde: Ajustes → Agentes (el botón de ajustes de la barra, o ⌘, / Ctrl+,), donde los agentes viven junto al resto de los ajustes. Codex y Claude Code se firman con un clic; Gemini y OpenCode aceptan su llave ahí mismo. MADRE no guarda credenciales de proveedores: cada llave va al archivo de su propio CLI.
18
+ 3. Para sumar o reconectar una IA más tarde: Ajustes → Agentes (el botón de ajustes de la barra, o ⌘, / Ctrl+,), donde los agentes viven junto al resto de los ajustes. Codex, Claude Code, Gemini (con tu cuenta de Google) y OpenCode (con GitHub Copilot) se firman con un clic; Gemini y OpenCode también aceptan su llave ahí mismo. Debajo de cada agente, «¿Prefieres tu terminal?» despliega el mismo paso escrito como comando, para quien prefiera hacerlo a mano. MADRE no guarda credenciales de proveedores: cada sesión y cada llave van al archivo de su propio CLI.
19
19
  4. Con Ollama, el módulo IA local (Módulos, en la barra) ya está encendido: la memoria se embebe localmente y `@madre` aparece en la fila.
20
20
  5. Ajustes → Memoria decide quién destila la memoria y cada cuánto. El Mapa de memoria, desde la cabecera de Diagnóstico, muestra lo que el proyecto recuerda.
21
21
 
@@ -25,13 +25,24 @@ npx @jossuealcala/madre setup # el mismo alta, desde la terminal, si la pr
25
25
  npx @jossuealcala/madre start --no-open --project RUTA
26
26
  ```
27
27
 
28
+ **En un servidor, sin pantalla.** MADRE escucha solo en `127.0.0.1` de la máquina donde corre, y es a propósito: no tiene contraseña, y quien llegara a ella podría poner a trabajar a los agentes ahí. No abras sus puertos a la red. Para usarla en un servidor, ábrela por un túnel SSH desde tu computadora. Inicio usa el 4317 y cada proyecto que abras toma el siguiente puerto libre (4318, 4319…), así que el túnel lleva varios; si abres más proyectos, agrega más `-L`.
29
+
30
+ ```bash
31
+ # en tu computadora: entra al servidor con el túnel
32
+ ssh -L 4317:127.0.0.1:4317 -L 4318:127.0.0.1:4318 -L 4319:127.0.0.1:4319 -L 4320:127.0.0.1:4320 usuario@servidor
33
+ # ya dentro del servidor
34
+ npx @jossuealcala/madre --no-open
35
+ ```
36
+
37
+ Luego abre `http://127.0.0.1:4317/salas` en el navegador de tu computadora. Los agentes se instalan en el servidor y se conectan desde Ajustes › Agentes: Claude te da un enlace y un código que pegas ahí mismo, y Gemini y OpenCode aceptan su llave. Usa tu usuario y no root: los agentes trabajan con los permisos de quien corre MADRE.
38
+
28
39
  **Tres nombres.** **MADRE** es el producto. **Diagnóstico** es su voz operativa: fallas, conexiones, ajustes. **Historial** es el canal sobre el que corre el proyecto: el registro de eventos, el bloque del plan, la carpeta `.pulse/` donde caen los artefactos; esos identificadores conservan su nombre de antes, PULSE.
29
40
 
30
41
  ---
31
42
 
32
43
  ## EL PROYECTO
33
44
 
34
- **Conecta tus agentes.** Sin agentes en línea el proyecto abre en Conecta tus agentes: una tarjeta por agente con su estado real y la única acción que le toca, `INSTALL` o `SIGN IN`. Todo corre en tu máquina, con el comando a la vista, y la salida se transmite a la misma pantalla. Codex y Claude Code se firman con un clic porque su CLI abre el navegador; Gemini y OpenCode aceptan su llave ahí mismo, que MADRE escribe donde ese CLI la busca, con el archivo cerrado a tu usuario y sin guardar copia en ninguna parte, solo desde esta computadora. Cada tarjeta dice además con qué cuenta se firma ese agente y si hay una entrada sin pagar, para que elegir no sea a ciegas. Esa pantalla se repliega en cuanto un agente queda listo y no vuelve: es el primer contacto de un proyecto sin nadie dentro. A partir de ahí los agentes viven en `⚙ CONNECTIONS`, con los mismos botones y, al lado, los modos, los permisos y las llaves de cada agente.
45
+ **Conecta tus agentes.** Sin agentes en línea el proyecto abre en Conecta tus agentes: una tarjeta por agente con su estado real y la única acción que le toca, `INSTALL` o `SIGN IN`. Todo corre en tu máquina, con el comando a la vista, y la salida se transmite a la misma pantalla. Codex, Claude Code y Gemini se firman con un clic porque su CLI abre el navegador (Gemini no tiene comando para firmarse: MADRE selecciona «Login with Google» en sus ajustes, contesta por ti el sí que pide antes de abrir el navegador y detiene la corrida en cuanto el CLI guarda su sesión; si no termina, deja sus archivos como estaban). OpenCode se firma con GitHub Copilot: MADRE corre `opencode auth login -p github-copilot`, elige github.com en su menú y muestra la página y el código de dispositivo que escribes en GitHub. Desde la sala solo se ofrecen los proveedores que permiten este acceso a herramientas de terceros: nunca la suscripción de Claude (Anthropic no lo permite) y, por ahora, tampoco ChatGPT ni GitLab; esos y GitHub Enterprise quedan en `opencode auth login`, en tu terminal. Gemini y OpenCode también aceptan su llave ahí mismo, que MADRE escribe donde ese CLI la busca, con el archivo cerrado a tu usuario y sin guardar copia en ninguna parte, solo desde esta computadora. Cada tarjeta dice además con qué cuenta se firma ese agente y si hay una entrada sin pagar, para que elegir no sea a ciegas. Esa pantalla se repliega en cuanto un agente queda listo y no vuelve: es el primer contacto de un proyecto sin nadie dentro. A partir de ahí los agentes viven en `⚙ CONNECTIONS`, con los mismos botones y, al lado, los modos, los permisos y las llaves de cada agente.
35
46
 
36
47
  **La barra.** La marca con su latido, la raíz del proyecto, los agentes, `LIVE`, las alertas (`DETENER TODO`, versión nueva), `MODULES`, `Diagnóstico`, tema y panel de archivos. Cada esfera de agente lleva el Uso, su consumo: el límite real del proveedor cuando el CLI lo publica, si no, la ventana local de MADRE. Un clic la despliega.
37
48
 
@@ -53,6 +64,8 @@ Un segundo clic en la esfera elegida, o el chip `default model ▾`, elige el mo
53
64
 
54
65
  **Archivos.** El icono de la derecha abre el árbol del proyecto en solo lectura. El visor numera líneas; clic y Shift+clic seleccionan un rango y `REVIEW WITH` lo manda a un agente. Con **Vista previa** encendida en `MODULES`, HTML, SVG y Markdown se renderizan en un marco sellado en lugar de mostrar su código, con barra atrás/recargar y recarga automática cuando un agente cambia el archivo.
55
66
 
67
+ **Código.** La tecla `CÓDIGO` de la barra abre el visor junto a la conversación como espacio de código: los archivos del proyecto con su buscador, pestañas (hasta 12, que siguen ahí al recargar) y, sobre el código, la ruta y la función donde está el cursor. ⌘P (Ctrl+P fuera de macOS) abre un archivo por su nombre. Cambiar de pestaña no pierde lo que escribiste: el borrador se queda en su pestaña, marcado con un punto, hasta que guardas o descartas. Lo que un agente cambió en su último turno de `#3` EDITAR queda marcado en su color, con una tarjeta por cambio: **Conservar** (deja de marcarse), **Deshacer** (vuelve a poner lo que había solo en esas líneas; el resto del turno se queda) y **Preguntar por qué** (se lo pregunta al agente en la conversación). Un turno deshecho con `DESHACER`, o líneas que reescribiste tú, ya no se marcan. Al pedir revisión de unas líneas, `REVISAR CON` ofrece Explicar, Mejorar, Escribir pruebas y Arreglar. **Al lado** pone junto al código el Markdown renderizado mientras escribes, o la página HTML recargada al guardar (esta con Vista previa encendida). Lo conservado se guarda en `code-reviewed.json`, junto al registro del proyecto (`GET /api/files/changes`, `POST /api/files/changes/review`).
68
+
56
69
  **Tema.** Sol/luna en la barra: automático, claro u oscuro. El claro no brilla; la pantalla de Diagnóstico sigue siendo fósforo.
57
70
 
58
71
  **Idioma.** El proyecto habla **español** por defecto. El botón `EN` de la barra lo pasa a inglés y el navegador lo recuerda; `PULSE_LANGUAGE=en` manda sobre el config en el siguiente arranque. Un idioma es solo cómo se lee: lo que quedó escrito en el ledger conserva las palabras con que se escribió, y al mostrarse se vuelve a decir en el idioma del proyecto.
@@ -79,11 +92,15 @@ Cada mensaje sale con un modo. Tu modo es el techo de cualquier plan que ese men
79
92
 
80
93
  **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
94
 
95
+ **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.
96
+
97
+ **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.
98
+
82
99
  **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
100
 
84
101
  **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
102
 
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.
103
+ **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
104
 
88
105
  ---
89
106
 
@@ -135,6 +152,8 @@ Todo lo dicho fuera de INCÓGNITO queda indexado junto al ledger, en `~/.pulse/r
135
152
 
136
153
  **Mapa de memoria.** La memoria en un mapa, detrás del nombre del proyecto: MADRE es un sol rojo que late, cada memoria un planeta en el color de su tipo, unidos por venas que pulsan. Se navega, se lee y solo se puede borrar, con doble confirmación. Ocho toques al corazón activan el Bloqueo temporal y sellan el archivo diez minutos.
137
154
 
155
+ **Modo neural.** La tecla **Neural** en la cabecera del Mapa de memoria y del Mapa de proyectos dibuja la misma red como las neuronas de un cerebro: cada memoria es un punto de luz en el color de su tipo, los enlaces son axones finos y solo se encienden los caminos por donde viaja un pulso y la neurona a la que llega. El núcleo (y, en el Mapa de proyectos, el Coordinador) es el bulbo central de ese cerebro, con su tallo, y late. Al encenderlo, la luz sale del núcleo y alcanza cada neurona a su paso. Muestra lo mismo y cuesta una fracción: no hay superficies sombreadas punto por punto, ni nebulosa, ni estrellas. Cuando el equipo no le da al mapa los cuadros que necesita, la tecla invita a probarlo una vez por sesión; tú eliges cuándo usar cada modo. La elección se recuerda para Inicio y todos los proyectos (`pulse.neural` en `~/.pulse/looks.json`).
156
+
138
157
  **@madre.** Con Ollama y un modelo de chat, la memoria habla: `@madre` responde desde todo el archivo con citas `[#n]`, dice cuando el proyecto nunca discutió algo, no escribe ni ejecuta, y convoca a los agentes si se lo pides. Sus tokens son locales y no cuentan. Cuando existe un modelo entrenado con el proyecto, lo usa.
139
158
 
140
159
  **Ajustes.** Ajustes → Memoria: quién destila, quiénes pueden, cada cuánto, dónde se embebe, cuánto contexto puede ocupar el recall. Todo en `~/.pulse/config.json`, sin reiniciar.
@@ -149,7 +168,7 @@ El proyecto acumula material de entrenamiento mientras trabajas. `MEMORY` muestr
149
168
 
150
169
  `EXPORT DATASET` escribe `train.jsonl` y `valid.jsonl` junto al ledger, redactados. La tarjeta `TRAIN` trae los comandos ya rellenados con tu carpeta de proyecto y el modelo base que cabe en tu máquina. El entrenamiento corre fuera de MADRE, con mlx en Apple Silicon; la receta vive en [`docs/training/`](training/README.md). En cuanto Ollama tiene un modelo `madre-<proyecto>`, `@madre` responde con él y las demás CLIs reciben la indicación de preguntarle primero: la memoria del proyecto deja de costar tokens.
151
170
 
152
- **Ollama.** Si corre en la máquina, MADRE lo usa sin configurar nada: búsqueda inteligente local, archivista local, `@madre`. El módulo IA local, en Módulos, muestra servidor, modelos y roles, descarga los recomendados y deja apagar cada rol. `qwen2.5:7b` en 16 GB, `qwen2.5:3b` en 8 GB; MADRE prefiere modelos de chat general sobre los `-coder`.
171
+ **Ollama.** Si corre en la máquina, MADRE lo usa sin configurar nada: búsqueda inteligente local, archivista local, `@madre`. El módulo IA local, en Módulos, muestra servidor, modelos y roles, descarga los recomendados y deja apagar cada rol. El modelo que propone sale de tu equipo, no de una regla fija: el bloque «Tu computadora» lee el chip Apple y su memoria compartida, la tarjeta NVIDIA y su memoria de video, o solo el procesador, y muestra cada tamaño de Qwen2.5 (0.5B a 72B) con su mínimo para correr y para entrenar (por ejemplo, `qwen2.5:7b` desde 12 GB y `qwen2.5:3b` desde 8 GB). Si hay varios descargados, usa el más grande; prefiere modelos de chat general sobre los `-coder`.
153
172
 
154
173
  ---
155
174
 
@@ -190,11 +209,13 @@ El botón de la barra abre la pantalla de diagnóstico. Escribe un síntoma, un
190
209
  | **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
210
  | **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
211
  | **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 |
212
+ | **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
213
  | **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
214
  | **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
215
  | **Continuidad** | Integración externa opcional: estado verificado del proyecto, checkpoints y handoffs en `.ahp/`; `/ahp status`, `/ahp check`, `/ahp context` |
197
216
 
217
+ **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`).
218
+
198
219
  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
220
 
200
221
  ---
@@ -227,11 +248,25 @@ En un proyecto, la tecla junto a la casa **cambia de proyecto**: su indicador di
227
248
  | `POST /api/salas/forget` | Quitar un proyecto de MADRE: lo cierra si está abierto, revoca sus conexiones y aparta su `project.json` como `project.forgotten.json`. Nunca el del Coordinador | La página de Inicio con su `Origin`, nunca un proceso |
228
249
  | `GET /api/tour` · `POST /api/tour` | El recorrido de 1.0: si se debe el bonjour, si la persona viene de 0.7.2, capítulos leídos, dónde iba, pistas vistas. Se guarda en `~/.pulse/tour.json`, uno por persona, no uno por puerto | Las páginas de esta Mac |
229
250
  | `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 |
251
+ | `GET /api/looks/wallpaper` · `PUT /api/looks/wallpaper` · `POST /api/looks/wallpaper/frame` · `DELETE /api/looks/wallpaper` | Tu propia imagen de fondo (1.0.3): una sola para todas las páginas, en `~/.pulse/wallpaper/`. La página la ajusta (lado mayor de 2880 px), la codifica y saca sus colores para el velo, la malla y el tinte; el servidor guarda solo una imagen WebP, JPEG o PNG de hasta 8 MB, reconocida por sus primeros bytes (nunca SVG), y la sirve con su tipo y `nosniff`. `GET /api/looks` la incluye como `custom`; cada página sigue eligiéndola o no (`pulse.wallpaper` = `custom`) | Las páginas de esta Mac |
230
252
  | `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
253
  | `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 |
254
+ | `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 |
255
+ | `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 |
256
+ | `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
257
  | `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
258
  | `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
259
  | `POST /api/salas/enlaces/recall` | Marcar o quitar «Incluir siempre» de una conexión | La página de Inicio, nunca un proceso |
260
+ | `GET /api/enlace/corpus` | (D-S15) Todo lo que este proyecto deja aprender al Coordinador por un contrato con `train`: las notas que viajan de los tipos del contrato, hasta 5,000, redactadas; 404 si el contrato no lo permite, 423 sellado, 429 sobre su tope de 6 por hora | La sala del Coordinador, con la llave del canal, sin `Origin` |
261
+ | `POST /api/salas/enlaces/train` | Marcar o quitar «El Coordinador aprende de él»; al quitarla se borra la copia que guardó Salas | La página de Inicio, nunca un proceso |
262
+ | `GET /api/enlace/state` | (D-S16) El estado canónico de Continuidad (AHP+) de este proyecto por un contrato con `state`: objetivo, fase, siguiente paso, bloqueos, último traspaso, decisiones aceptadas y lo abierto, redactado; `state: null` sin `.ahp/`; 404 si el contrato no lo permite, 423 sellado, 429 sobre `perHour` | La sala que lee, con la llave del canal, sin `Origin` |
263
+ | `POST /api/enlace/deliver` | (D-S17) Notas que entrega la sala que lee por un contrato con `deliver` (1 a 5, de los tipos que se sostienen, 600 caracteres); quedan pendientes en la bandeja; 429 sobre `perHour` o con 50 esperando | La sala que lee, con la llave del canal, sin `Origin` |
264
+ | `POST /api/enlace/ask-state`, `POST /api/enlace/send` | El lado que pide de lo anterior, para las herramientas `enlace_state` y `enlace_deliver` de un turno que corre aquí | Un proceso de esta Mac con la llave y un turno vivo |
265
+ | `GET /api/enlace/inbox` · `POST /api/enlace/inbox/decide` | (D-S17) Las notas entregadas a este proyecto, y aceptar o rechazar una; aceptada, entra a la memoria (`origin: 'delivered'`) | La página del proyecto, o un agente suyo en `#3`/`#4` con la llave |
266
+ | `POST /api/salas/enlaces/allow` | (D-S16, D-S17) Marcar o quitar «Comparte su estado» (`state`) o «Recibe notas entregadas» (`deliver`) | La página de Inicio, nunca un proceso |
267
+ | `POST /api/madre/shutdown` | Apagar MADRE: pide a cada proyecto abierto que se cierre como lo cierra Inicio, espera hasta 15 s y se cierra; responde `closed` y `stuck` | Solo la página de MADRE en esta computadora (`Origin` propio), nunca un proceso ni el teléfono |
268
+ | `GET /api/home-layout` · `POST /api/home-layout` | El acomodo de Inicio en `~/.pulse/home.json` (widgets, orden de proyectos, barra fijada, tarjetas), igual desde cualquier puerto | La página de Inicio |
269
+ | `GET /api/x/bishop/exam` · `POST /api/x/bishop/exam` | (D-S18) El último examen del modelo local del Coordinador y si sigue valiendo para el modelo en uso; empezarlo (corre en segundo plano) | La página de Inicio |
235
270
  | `POST /api/enlace/notice` | La línea de Diagnóstico al firmar o revocar | El proyecto que sirve Inicio, con la llave |
236
271
 
237
272
  Los contratos viven en `~/.pulse/config.json` bajo `enlaces` y los cruces en `enlaces.jsonl` junto al registro de cada proyecto.
package/docs/SDK.md CHANGED
@@ -54,7 +54,7 @@ export default ({ defineModule }) => defineModule({
54
54
 
55
55
  ## Lo que un módulo puede declarar
56
56
 
57
- Esta tabla es **el contrato completo**: 36 campos, ni uno más. Cualquier otro que escribas MADRE
57
+ Esta tabla es **el contrato completo**: 38 campos, ni uno más. Cualquier otro que escribas MADRE
58
58
  te lo dice al instalar («no entendí estos campos») en vez de ignorarlo en silencio. Una prueba de
59
59
  la suite compara esta tabla contra el código, así que si alguna vez se separan, es un fallo.
60
60
 
@@ -66,11 +66,13 @@ la suite compara esta tabla contra el código, así que si alguna vez se separan
66
66
  | `tracks` | Si tu módulo envuelve algo de fuera, su versión no es la tuya: es la de esa cosa. Declara `{ name, npm }` o `{ name, github }` y devuelve la versión encontrada en `status(ctx)` como `runs: [{ name, version }]`. MADRE muestra esa versión y busca una más nueva sola, una vez al día, con el botón ↻ de la ficha para mirar ahora |
67
67
  | `updatePlan(ctx, { latest })` | Cómo se trae esa versión nueva a esta computadora: `{ command, args, display, note, after }`. MADRE enseña `display` y no corre nada hasta que la humana lo leyó; la salida cae en la sala línea por línea. Sin comando, devuelve `{ command: null, note, download }` y la ficha manda a descargarlo |
68
68
  | `updates` | `{ url }` https donde publicas **tu propio módulo**. Con eso su ficha trae un botón que va por el archivo, lo verifica igual que una instalación y lo reemplaza si pasa. Si lo instalaste desde un archivo, MADRE recuerda cuál y no necesitas declarar nada: edítalo y pide una copia nueva |
69
- | `settings` | Valores por defecto. Viven en `~/.pulse/config.json` bajo `modules.<idEnCamelCase>`; `enabled` es el interruptor |
69
+ | `settings` | Valores por defecto. Viven en `~/.pulse/config.json` bajo `modules.<idEnCamelCase>`; `enabled` es el interruptor para todos los proyectos, y `rooms` guarda lo que dijo cada proyecto, que gana. MADRE lo resuelve por ti: `ctx.settings.enabled` ya es el de este proyecto |
70
70
  | `status(ctx)` | Qué muestra la tarjeta: `{ status: { installed, detail }, preflight: { ok, problems }, install: { display } }`. `install` se devuelve desde aquí; no es un campo superior del módulo |
71
71
  | `status(ctx)` → `runs` | Lo que tu módulo maneja y no es MADRE: `[{ name, version, target }]`. `version` es lo que encontraste en esta computadora (`null` si no está), `target` lo que instalarías. Si coincide con `tracks.name`, esa es la versión de la ficha |
72
72
  | `toggle(ctx, payload)` | Sustituye el interruptor por defecto; `confirm: 'texto'` pide confirmación antes de encender |
73
73
  | `onToggle(ctx, enabled)` | Reacciona al interruptor |
74
+ | `ready(ctx)` | Lo que pides antes de encender, en un proyecto o en todos (desde el Mercado también): `null` si está listo, `{ status, body: { error } }` si no. Apagar nunca lo pregunta |
75
+ | `footer` | Hasta dos teclas junto a la versión de MADRE, abajo a la derecha, mientras tu módulo está encendido: `[{ icon: 'heart' \| 'star' \| 'link', label, text, action, url }]`. Los textos pueden ser una frase o `{ es, en }`; `url` tiene que ser https y se abre en otra pestaña. MADRE la dibuja: al pasar el ratón muestra `text` y un botón con `action` |
74
76
  | `slash` | Comandos `/nombre` que corren en el servidor con tu `ctx` y devuelven `{ ok, title, text }`. La sala los muestra como tarjeta y los agentes los leen |
75
77
  | `toolsForTurn(ctx, turn)` | Servidores MCP para el turno de un agente: `[{ name, command, args, env, tools, sends, brief }]`. MADRE los adjunta a la CLI en su corrida aislada y describe `brief` al agente. `turn` trae el agente, el modo, el arriendo, la carpeta, el puerto y `turn.turn`: el id de la respuesta que ese turno escribirá. Si tu servidor llama de vuelta a la sala en nombre del turno, manda ese id; `ctx.room.runningTurn(id)` dice si sigue corriendo y para qué agente |
76
78
  | `toolsForTurn` → `sends` | Cuáles de tus herramientas **mandan algo fuera**. El núcleo las retira por debajo de `#4` AIRLOCK: ni se le cuenta al modelo que existen. Ver abajo |
@@ -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.