@jossuealcala/madre 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/CONTRIBUTING.md +32 -1
- package/README.md +39 -6
- package/SECURITY.md +1 -1
- package/bin/madre.mjs +37 -3
- package/package.json +4 -3
- package/public/app.js +247 -7
- package/public/brands.js +18 -0
- package/public/index.html +5 -0
- package/public/styles.css +20 -0
- package/public/troubleshooting.js +24 -2
- package/src/adapters/madre.mjs +85 -0
- package/src/auth-probe.mjs +1 -0
- package/src/capabilities.mjs +1 -0
- package/src/dataset.mjs +85 -0
- package/src/distiller.mjs +16 -6
- package/src/embeddings.mjs +7 -1
- package/src/extensions.mjs +24 -224
- package/src/memory.mjs +3 -2
- package/src/modules/ahp.mjs +64 -0
- package/src/modules/ashcode.mjs +28 -0
- package/src/modules/git-pulse.mjs +26 -0
- package/src/modules/helpers.mjs +30 -0
- package/src/modules/image-studio.mjs +39 -0
- package/src/modules/index.mjs +21 -0
- package/src/modules/ollama.mjs +56 -0
- package/src/modules/ripley.mjs +20 -0
- package/src/modules/sdk.mjs +78 -0
- package/src/ollama.mjs +118 -0
- package/src/room/archivist.mjs +141 -0
- package/src/room/attachments.mjs +15 -0
- package/src/room/budget.mjs +83 -0
- package/src/room/context.mjs +31 -0
- package/src/room/control.mjs +66 -0
- package/src/room/escalation.mjs +41 -0
- package/src/room/ghost.mjs +32 -0
- package/src/room/guard.mjs +52 -0
- package/src/room/prompt.mjs +62 -0
- package/src/room/vectors.mjs +47 -0
- package/src/room.mjs +126 -388
- package/src/server.mjs +190 -53
- package/src/setup.mjs +25 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
Todas las versiones publicadas de `@jossuealcala/madre`. Fechas en ISO.
|
|
4
4
|
|
|
5
|
+
Una versión se cierra cuando está en npm: hasta entonces su sección se llama **Sin publicar** y puede crecer. Cada versión publicada tiene exactamente una etiqueta `vX.Y.Z`, una release en GitHub y una sección aquí; el parche puede llegar a dos dígitos (`0.2.10`) antes de subir el menor. Ver `docs/ROADMAP.md` para el criterio de qué sube cada número.
|
|
6
|
+
|
|
7
|
+
## 0.3.0 · 2026-09-18
|
|
8
|
+
|
|
9
|
+
### Ollama, la inteligencia local (roadmap 2a)
|
|
10
|
+
- Nuevo módulo `OLLAMA`: si Ollama corre en la máquina, los embeddings de la memoria se calculan localmente y la destilación la hace primero un modelo local, gratis y sin que nada salga. MODULES muestra servidor, modelos y roles, descarga los recomendados con `PULL` (progreso en la sala) y permite apagar cada rol o el módulo. Sin Ollama, todo sigue igual.
|
|
11
|
+
- El archivista local pide JSON estructurado y no cuenta contra ningún presupuesto de proveedor; el reporte `memory.distilled` dice `local`, modelo y tokens.
|
|
12
|
+
- Variables: `PULSE_EMBED_PROVIDER`, `PULSE_OLLAMA_HOST`, `PULSE_OLLAMA_MODEL`, `PULSE_OLLAMA_EMBED_MODEL`.
|
|
13
|
+
|
|
14
|
+
### CONTROL: prevención antes que restauración
|
|
15
|
+
- Mientras un agente tiene CONTROL, los `.env`, `.pulse/`, `.madre/` y `.claude/settings.local.json` quedan en solo lectura a nivel de sistema de archivos y recuperan sus permisos al terminar; el aviso lista qué se bloqueó. `.git/` sigue restaurándose desde el checkpoint después del turno.
|
|
16
|
+
|
|
17
|
+
### Núcleo
|
|
18
|
+
- `src/room.mjs` pasa de 1204 a 908 líneas: prompt, contexto, CONTROL, escalación, archivista, vectores, presupuesto, GHOST y adjuntos viven ahora en `src/room/`, cada uno con una responsabilidad. Mismo comportamiento, misma suite.
|
|
19
|
+
|
|
20
|
+
### Dataset y modelo del proyecto (roadmap 2c)
|
|
21
|
+
- `EXPORT DATASET` en MEMORY y `madre dataset` en terminal escriben `train.jsonl` / `valid.jsonl` junto al ledger: los turnos reales de la sala como pares de chat redactados, más las notas destiladas como pares de recuerdo. `docs/training/` trae la receta LoRA con mlx-lm, el `Modelfile` y `train.sh`. Un modelo registrado en Ollama como `madre-<proyecto>` lo toma `@madre` automáticamente.
|
|
22
|
+
|
|
23
|
+
### @madre, el quinto agente (roadmap 2b)
|
|
24
|
+
- Con Ollama y un modelo de chat, `@madre` entra a la sala: responde desde todo el archivo con citas `[#n]`, dice cuando algo nunca se discutió, nunca escribe ni delega, y sus tokens locales no cuentan. Los orquestadores pueden delegarle pasos de verificación. Entra y sale con Ollama (`agents.updated`); interruptor en MODULES → OLLAMA.
|
|
25
|
+
- El asistente de terminal y `madre doctor` muestran Ollama junto a las CLIs (servidor, modelo de chat, embeddings) y cuentan a `@madre` como agente en línea: con Ollama corriendo la sala abre aunque ninguna CLI tenga sesión, con el aviso de conectar una para trabajar en archivos.
|
|
26
|
+
- `@madre` ya no se confunde de identidad ni promete lo que no hace: la identidad se repite al final del briefing, cada llamada a Ollama pide una ventana de 8k tokens (la de 4k por defecto recortaba el prompt de sistema), las órdenes de acción (convocar, delegar, ejecutar, escribir) se contestan sin llamar al modelo señalando a los agentes CLI, y el chip `TO @madre` dice "memory · answers, does not act". Los modelos de chat generales (`qwen2.5`, `llama3.1`, `gemma3`) van antes que los `-coder`.
|
|
27
|
+
- README: seis módulos con OLLAMA y el SDK enlazado a CONTRIBUTING, enlaces absolutos para que npm los resuelva, estado real del adaptador de Claude (MCP de memoria), y bloque "Primeros cinco minutos" con el recorrido completo desde `npx` hasta conectar las IAs desde MU/TH/UR sin volver a la terminal.
|
|
28
|
+
|
|
29
|
+
### SDK de módulos
|
|
30
|
+
- `src/modules/sdk.mjs` con `defineModule`: un módulo es un archivo con sus ajustes en `config.json`, su descripción para MODULES, su interruptor, sus rutas y sus hooks. Los seis módulos (AHP+, Image Studio, Git Pulse, AshCode, RIPLEY, Ollama) viven en `src/modules/`; `extensions.mjs` queda como capa de compatibilidad y el servidor monta las rutas de los módulos de forma genérica.
|
|
31
|
+
|
|
32
|
+
### Memoria configurable desde MU/TH/UR
|
|
33
|
+
- Sección `MEMORY` en CONNECTIONS: archivista preferido, quiénes pueden destilar, cada cuántos intercambios o minutos de reposo, proveedor de embeddings y porcentaje de recall. Se guarda en `config.json` y se aplica en vivo.
|
|
34
|
+
|
|
35
|
+
## 0.2.3 · 2026-09-18
|
|
36
|
+
|
|
37
|
+
### RIPLEY navega
|
|
38
|
+
- El visor renderiza HTML como un navegador del proyecto: la página se sirve en `/preview/project/<ruta>`, sus scripts corren y sus rutas relativas a CSS, JS, imágenes y fuentes funcionan. El marco sigue sellado: sin origen propio, sin red, sin formularios, sin acceso a MADRE, y solo carga recursos del proyecto a través de MADRE. Antes los scripts estaban bloqueados y una página construida con JavaScript se veía vacía.
|
|
39
|
+
- Barra mínima en el visor: atrás y recargar, con la ruta y el título de la página en pantalla. Sin URL editable: RIPLEY es un visor del proyecto, no un navegador general.
|
|
40
|
+
- Recarga sola cuando un agente cambia la página abierta o algo de su carpeta, en CONTROL o en un lease.
|
|
41
|
+
- Los errores de la página se ven: un puente de una línea dentro del marco reenvía `window.onerror`, promesas rechazadas y recursos que no cargan; el visor los muestra en una franja con `ASK THE ROOM`, que deja el error y el archivo en el compositor.
|
|
42
|
+
|
|
5
43
|
## 0.2.2 · 2026-09-18
|
|
6
44
|
|
|
7
45
|
### Corrección crítica
|
package/CONTRIBUTING.md
CHANGED
|
@@ -19,12 +19,36 @@ node ./bin/madre.mjs doctor --catalog # what MU/TH/UR already knows
|
|
|
19
19
|
- Agents never write outside their lease. If you widen what an agent may do, the permission modes and MU/TH/UR's catalog must say so.
|
|
20
20
|
- MU/TH/UR speaks in uppercase and in short sentences; the room speaks like a person. Keep both voices.
|
|
21
21
|
|
|
22
|
+
## Writing a module
|
|
23
|
+
|
|
24
|
+
A module is one file in `src/modules/`, registered in `src/modules/index.mjs`:
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
import { defineModule } from './sdk.mjs';
|
|
28
|
+
export default defineModule({
|
|
29
|
+
id: 'night-vision', name: 'Night Vision', vendor: 'MADRE', summary: '…',
|
|
30
|
+
settings: { enabled: false, gain: 2 }, // lives in ~/.pulse/config.json → modules.nightVision
|
|
31
|
+
confirm: 'Send { "confirm": true }…', // optional: the switch asks first
|
|
32
|
+
async status(ctx) { return { detail: '…' }; },// optional: what MODULES shows
|
|
33
|
+
async onToggle(ctx, enabled) {}, // optional: apply live
|
|
34
|
+
routes: [{ method: 'GET', path: '/api/night-vision', handler: async (ctx, { payload }) => ({ status: 200, body: {} }) }],
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`ctx` carries `projectRoot`, `config`, `settings`, `agents`, `room`, `readConfig()`, `updateConfig(patch)`, `record(type, payload)` and `services` (what the server offers: `imageKey`, `setImageModule`, `ollama`). A builtin gets a default switch that flips `enabled`, persists and records `extension.toggled`. Add a card branch in `public/app.js` only if the generic switch is not enough, and a condition in `public/troubleshooting.js` so MU/TH/UR knows it.
|
|
39
|
+
|
|
22
40
|
## Where things live
|
|
23
41
|
|
|
24
42
|
```
|
|
25
43
|
bin/madre.mjs the CLI · start, doctor, setup
|
|
26
44
|
src/server.mjs HTTP + SSE, settings, modules, sentinel routes
|
|
27
|
-
src/room.mjs
|
|
45
|
+
src/room.mjs the turn engine: send, dispatch, turns, plans, handoff, scopes
|
|
46
|
+
src/room/ its pieces: prompt (what an agent reads), context (transcript + recall),
|
|
47
|
+
control (checkpoint, diff, undo), escalation (waiting for the human),
|
|
48
|
+
archivist (distillation), vectors (embeddings), budget (token window),
|
|
49
|
+
ghost (off the record), attachments
|
|
50
|
+
src/modules/ one file per module on the SDK (sdk.mjs): ahp, image-studio, git-pulse, ashcode,
|
|
51
|
+
ripley, ollama; index.mjs is the registry, extensions.mjs the compatibility layer
|
|
28
52
|
src/adapters/ one file per CLI: Codex, Claude Code, Gemini CLI, OpenCode
|
|
29
53
|
src/memory.mjs SQLite index, distilled notes, vectors, recall
|
|
30
54
|
src/distiller.mjs the archivist's prompt and parsing
|
|
@@ -35,4 +59,11 @@ public/ the room UI; troubleshooting.js is MU/TH/UR's knowledge bas
|
|
|
35
59
|
docs/report-collector/ the Worker that turns sentinel reports into issues
|
|
36
60
|
```
|
|
37
61
|
|
|
62
|
+
## Versions
|
|
63
|
+
|
|
64
|
+
- A version is **closed only when it is on npm**. Until then its changelog section reads *Sin publicar* and keeps growing; no new number is opened while the previous one is unpublished.
|
|
65
|
+
- One published version = one `vX.Y.Z` tag = one GitHub release = one changelog section. Tags and releases are created at publish time, never before.
|
|
66
|
+
- Patch (`0.2.x`) for fixes and additions inside existing modules; the patch number may reach two digits. Minor (`0.x`) for a new mode, a new module, a new agent, or a change to what leaves the machine. Major when the room's ledger or memory format stops being readable by the previous version.
|
|
67
|
+
- `scripts/release.mjs` does the closing in one go: checks the tree is clean and CI-green, runs the suite and pack:check, turns *Sin publicar* into the dated section, tags, pushes, creates the release and prints the publish command.
|
|
68
|
+
|
|
38
69
|
Open questions go to issues with the `question` label. Ideas go through `✎ FEEDBACK` in MU/TH/UR or a plain issue. Be kind to the crew.
|
package/README.md
CHANGED
|
@@ -27,6 +27,15 @@ Una sola sala para conversar con los agentes de IA que ya están instalados en t
|
|
|
27
27
|
npx @jossuealcala/madre start
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
**Primeros cinco minutos.** Node 22.5 o superior y al menos una de estas CLIs con sesión: Codex, Claude Code, Gemini CLI, OpenCode; u Ollama corriendo con un modelo de chat. Entra a la carpeta del proyecto y corre el comando de arriba.
|
|
31
|
+
|
|
32
|
+
1. MADRE detecta qué CLIs tienes y quién tiene sesión. Si nadie está en línea, MU/TH/UR abre un asistente en la terminal: elige un número para correr el sign-in de esa CLI, `s` para abrir la sala.
|
|
33
|
+
2. La sala abre en `http://127.0.0.1:4317`. Escribe a un agente con `TO @agente`; el modo del mensaje va en el chip de al lado (`#1 EXCHANGE` por defecto, solo lectura).
|
|
34
|
+
3. Para conectar o reconectar una IA sin terminal: MU/TH/UR → `⚙ CONNECTIONS`. Codex y Claude tienen botón `SIGN IN`; Gemini y OpenCode muestran el comando exacto para su propio prompt. Ninguna credencial pasa por MADRE.
|
|
35
|
+
4. Si tienes Ollama, MODULES → OLLAMA ya está encendido: la memoria se embebe localmente y `@madre` aparece en la fila.
|
|
36
|
+
5. `⚙ CONNECTIONS → MEMORY` ajusta quién destila y cada cuánto; `◉ NOSTROMO` muestra lo que la sala recuerda.
|
|
37
|
+
|
|
38
|
+
|
|
30
39
|
Tres nombres, tres capas. **MADRE** es el producto: lo que instalas, abres en el navegador y ves junto al logo del latido. **PULSE** es el canal sobre el que corre una sala: el registro de eventos, el bloque de delegación entre agentes, los homes aislados de cada CLI y la carpeta `.pulse/` donde caen los artefactos; por eso esos identificadores conservan su nombre. **MU/TH/UR** es la voz operativa dentro de MADRE: diagnóstico, conexiones y ajustes. El comando `pulse` sigue funcionando como alias de `madre`.
|
|
31
40
|
|
|
32
41
|
## Uso
|
|
@@ -208,22 +217,41 @@ Solo Codex genera imágenes de forma nativa. El módulo **Image Studio** (en `MO
|
|
|
208
217
|
|
|
209
218
|
## Módulos
|
|
210
219
|
|
|
211
|
-
La sala ofrece módulos integrados de MADRE y una integración externa opcional. El botón `MODULES` de la barra lista los disponibles y su estado. Hoy hay
|
|
220
|
+
La sala ofrece módulos integrados de MADRE y una integración externa opcional. El botón `MODULES` de la barra lista los disponibles y su estado. Hoy hay seis:
|
|
212
221
|
|
|
213
222
|
- **Git Pulse** (integrado, sin instalación): `/git status`, `/git log [n]`, `/git diff` y `/git branches` traen a la sala la rama, los cambios sin confirmar, los últimos commits o el resumen del diff, en solo lectura y sin gastar un turno de agente. La tarjeta queda en el registro como `command.output` y entra en el contexto que reciben los agentes, así todos razonan sobre los mismos hechos del repositorio. Requiere que el proyecto sea un repositorio git.
|
|
214
223
|
- **Image Studio** (integrado): ver la sección anterior.
|
|
215
|
-
- **RIPLEY** (integrado): actívalo en `MODULES` y el visor de archivos renderiza HTML, SVG y Markdown en lugar de mostrar su código, con un botón `PREVIEW`/`SOURCE` en la cabecera. HTML y SVG se sirven por `/
|
|
224
|
+
- **RIPLEY** (integrado): actívalo en `MODULES` y el visor de archivos renderiza HTML, SVG y Markdown en lugar de mostrar su código, con un botón `PREVIEW`/`SOURCE` en la cabecera. HTML y SVG se sirven por `/preview/project/<ruta>` dentro de un marco sellado: los scripts de la página sí corren, pero el marco no tiene origen propio (`sandbox allow-scripts`, sin `same-origin`), no puede hacer peticiones de red, ni enviar formularios, ni navegar la ventana de MADRE, y solo carga CSS, JS, imágenes y fuentes del propio proyecto a través de MADRE. Las rutas relativas de la página funcionan, el visor tiene atrás y recargar, se recarga solo cuando un agente cambia la página abierta, y los errores de la página aparecen en una franja con `ASK THE ROOM`. Markdown se renderiza en el propio visor. Apagado, esos archivos se muestran como texto con una nota. Sirve para ver lo que los agentes crean en `.pulse/out/` sin salir de la sala.
|
|
225
|
+
- **OLLAMA** (integrado): encendido solo si Ollama corre en la máquina. Muestra servidor, modelos y roles (embeddings, archivista, `@madre`), descarga los recomendados con `PULL` y deja apagar cada rol. Ver [Ollama: la inteligencia local](#ollama-la-inteligencia-local).
|
|
216
226
|
- **AshCode** (integrado, beta): actívalo en `MODULES` para mostrar el botón `$ ash_code` en el campo de texto. Cuando está iluminado, MADRE intenta abreviar localmente mensajes en español o inglés antes de enviarlos a un agente, y pide respuestas concisas. La burbuja muestra el texto enviado y permite desplegar el original; las respuestas abreviadas también conservan el original. Se omite la transformación si detecta código, rutas, enlaces, negaciones, cifras, estructura compleja, idioma incierto o ninguna reducción segura. **Puede cambiar el significado o producir errores: revisa siempre el original y la respuesta.** Menos caracteres no demuestra menos tokens facturados; consulta el uso real del proveedor. Al encenderlo, el campo se ensancha como con CREATE, la etiqueta pasa a `MU/TH/UR · SPECIAL ORDER 937 ›` y la caja hace un guiño a MADRE: un barrido CRT con líneas de fósforo en verde Homebrew (el verde del perfil Homebrew de Terminal.app), que también viste el botón como un prompt de bash con cursor parpadeante. Se apaga desde `ORDER 937` para el siguiente mensaje o se deshabilita en `MODULES`. No requiere npm ni modifica el proyecto: su estado se guarda en la configuración local de MADRE.
|
|
217
227
|
- **AHP+** (`@jossuealcala/ahp-plus`): estado verificado del proyecto, checkpoints y handoffs entre sesiones de IA, guardado en `.ahp/`. MADRE lo detecta por `.ahp/manifest.json` y lo instala con `npx --yes @jossuealcala/ahp-plus@1.4.1 setup . --platforms <agentes detectados>`, pidiendo adaptadores solo para los agentes presentes en la máquina que AHP+ soporta (Codex, Claude, OpenCode). Una vez instalado, `/ahp status`, `/ahp check` y `/ahp context` consultan su estado desde el campo de texto.
|
|
218
228
|
|
|
229
|
+
Cada módulo es un archivo en `src/modules/` declarado con `defineModule`: sus ajustes en `config.json`, su ficha para `MODULES`, su interruptor, sus rutas y sus hooks. Cómo escribir uno, en [CONTRIBUTING.md](https://github.com/jossuealcacao-exe/madre/blob/main/CONTRIBUTING.md#writing-a-module).
|
|
230
|
+
|
|
219
231
|
Instalar el módulo externo AHP+ es la única acción de módulos con la que MADRE escribe en el proyecto. Por eso el botón muestra primero el comando exacto y exige confirmación; la ejecución se transmite en vivo a la sala y queda registrada en el log como `extension.install.started`, `extension.install.output` y `extension.install.finished`. La consulta a los agentes sigue siendo de solo lectura.
|
|
220
232
|
|
|
221
233
|
## Modelo de amenazas, en corto
|
|
222
234
|
|
|
223
235
|
- **Qué sale de la máquina.** MADRE no tiene nube ni cuenta: no almacena credenciales, no tiene backend y no envía nada por sí sola. Pero cada agente es una CLI que llama a su proveedor: lo que un agente lee del proyecto puede viajar a OpenAI, Anthropic o Google según su configuración. El único envío propio de MADRE es el del sentinel, y solo si lo activas.
|
|
224
|
-
- **Escritura.** En #1 nadie escribe. En #2 la escritura queda confinada a `.pulse/out/<lease>/` por las reglas de cada CLI. En #3 CONTROL el proyecto entero es escribible salvo `.git/`, `.pulse/` y los `.env`: Claude, Gemini y OpenCode reciben esa prohibición como regla previa; Codex entra con su sandbox `workspace-write`, que no admite excluir rutas dentro del proyecto, así que
|
|
236
|
+
- **Escritura.** En #1 nadie escribe. En #2 la escritura queda confinada a `.pulse/out/<lease>/` por las reglas de cada CLI. En #3 CONTROL el proyecto entero es escribible salvo `.git/`, `.pulse/` y los `.env`: Claude, Gemini y OpenCode reciben esa prohibición como regla previa; Codex entra con su sandbox `workspace-write`, que no admite excluir rutas dentro del proyecto, así que MADRE añade prevención propia para todos los agentes: mientras dura el turno, los `.env`, `.pulse/`, `.madre/` y `.claude/settings.local.json` quedan en solo lectura a nivel de sistema de archivos y recuperan sus permisos al terminar; el aviso de CONTROL lista qué quedó bloqueado. `.git/` sigue escribible porque las CLIs lo necesitan, y por eso sigue restaurándose desde el checkpoint **después del turno**. Un agente que cambie permisos a propósito cae en esa restauración.
|
|
225
237
|
- **Memoria.** Todo lo dicho fuera de GHOST queda en `~/.pulse/rooms/<sala>/` y se reinyecta en los prompts de todos los agentes de esa sala. GHOST es la salida para lo que no debe recordarse.
|
|
226
238
|
|
|
239
|
+
## Memoria desde MU/TH/UR
|
|
240
|
+
|
|
241
|
+
En `⚙ CONNECTIONS → MEMORY` se ajusta la memoria sin terminal y se aplica al siguiente turno: quién destila primero (`AUTO` elige al más barato permitido, con Ollama al frente cuando corre), quiénes pueden destilar, cada cuántos intercambios o tras cuántos minutos de reposo, dónde se calculan los embeddings (`AUTO`, `OLLAMA`, `GEMINI`, `OFF`) y qué parte del contexto puede ocupar el recall. Todo queda en `~/.pulse/config.json` bajo `memory`; las variables de entorno, si están puestas, mandan al siguiente arranque.
|
|
242
|
+
|
|
243
|
+
## @madre, el quinto agente
|
|
244
|
+
|
|
245
|
+
Cuando Ollama corre con un modelo de chat, aparece en la sala un quinto agente: `@madre`. Es la memoria del proyecto convertida en interlocutor: responde desde el archivo completo, notas destiladas y citas exactas con su secuencia `[#n]`, más lo que lleve el mensaje. No escribe, no dibuja, no navega ni delega; cuando la sala nunca habló de algo, lo dice. Los demás agentes pueden delegarle un paso para comprobar qué se decidió. Sus tokens son locales y no cuentan contra ningún presupuesto. Entra y sale con Ollama, y MU/TH/UR lo anuncia; el interruptor `@MADRE IN THE ROOM` en MODULES → OLLAMA lo apaga.
|
|
246
|
+
|
|
247
|
+
## El modelo del proyecto
|
|
248
|
+
|
|
249
|
+
`MEMORY → EXPORT DATASET` (o `madre dataset`) escribe junto al ledger los turnos reales de la sala como pares de chat redactados, más las notas destiladas, en el formato que leen `mlx-lm` y los demás entrenadores. [`docs/training/`](https://github.com/jossuealcacao-exe/madre/blob/main/docs/training/README.md) explica cómo entrenar un LoRA local sobre un modelo pequeño y registrarlo en Ollama como `madre-<proyecto>`; en cuanto existe, `@madre` responde con él. Es la destilación de MADRE AI: la sala produce el dato, tú decides cuándo entrenar, y el modelo se evalúa contra lo que la sala sí decidió antes de confiar en él.
|
|
250
|
+
|
|
251
|
+
## Ollama: la inteligencia local
|
|
252
|
+
|
|
253
|
+
Si Ollama corre en la máquina, MADRE lo usa sin configurar nada: los embeddings de la memoria se calculan localmente con el modelo de embeddings disponible (`nomic-embed-text` recomendado) y la destilación de memorias la hace primero el modelo local (`qwen2.5:7b` en una Mac de 16 GB, `qwen2.5:3b` en 8 GB; cualquiera de la familia Qwen, Llama o Gemma sirve, y MADRE prefiere los de chat general sobre los `-coder`), antes que Gemini y el resto. Recordar deja de costar tokens y nada del proyecto sale de la máquina para eso. El módulo `OLLAMA` en MODULES muestra qué hay, permite descargar los modelos recomendados con `PULL`, apagar cada rol y desactivar el módulo. Sin Ollama, todo sigue como antes. `PULSE_OLLAMA_HOST`, `PULSE_OLLAMA_MODEL` y `PULSE_OLLAMA_EMBED_MODEL` eligen host y modelos; `PULSE_EMBED_PROVIDER=gemini` mantiene los embeddings en Gemini aunque Ollama exista.
|
|
254
|
+
|
|
227
255
|
## Sentinel de errores y feedback
|
|
228
256
|
|
|
229
257
|
MU/TH/UR tiene una sección SENTINEL. Cuando un turno falla con un error que ninguna condición conocida explica, o el proceso de MADRE se cae, el sentinel guarda un reporte en el registro de la sala (`sentinel.report`): el error con rutas, nombres de usuario, correos y claves eliminados, la versión de MADRE y de Node, la plataforma y las versiones de los agentes detectados. Los repetidos se agrupan por huella durante 24 horas.
|
|
@@ -250,7 +278,12 @@ Cada agente tiene un timeout de 180 s por defecto; la burbuja de espera muestra
|
|
|
250
278
|
| `PULSE_DISTILL_MAX_CHARS` | `6000` | Tamaño máximo del lote que lee el destilador |
|
|
251
279
|
| `PULSE_DISTILL_AGENT` | — | Agente destilador preferido; por defecto el más barato disponible |
|
|
252
280
|
| `PULSE_DISTILL_MODEL` | — | Modelo para la destilación |
|
|
253
|
-
| `PULSE_EMBED` | `1` | Embeddings
|
|
281
|
+
| `PULSE_EMBED` | `1` | Embeddings para recall por significado (`0` lo apaga) |
|
|
282
|
+
| `PULSE_EMBED_PROVIDER` | `auto` | `ollama`, `gemini` o `auto` (Ollama si corre con modelo de embeddings, si no Gemini) |
|
|
283
|
+
| `PULSE_OLLAMA` | `1` | `0` ignora Ollama por completo |
|
|
284
|
+
| `PULSE_OLLAMA_HOST` | `http://127.0.0.1:11434` | Dónde escucha Ollama |
|
|
285
|
+
| `PULSE_OLLAMA_MODEL` | el mejor disponible | Modelo local para destilar |
|
|
286
|
+
| `PULSE_OLLAMA_EMBED_MODEL` | el mejor disponible | Modelo local de embeddings |
|
|
254
287
|
| `PULSE_EMBED_MODEL` | `gemini-embedding-001` | Modelo de embeddings |
|
|
255
288
|
| `PULSE_EMBED_DIMS` | `768` | Dimensiones del vector |
|
|
256
289
|
| `PULSE_MEMORY_TOOLS` | `1` | Servidor MCP `pulse-memory` adjunto a cada turno (`0` lo quita) |
|
|
@@ -283,14 +316,14 @@ Gemini CLI lee `@algo` en el prompt como un archivo a incluir, incluso en modo h
|
|
|
283
316
|
|
|
284
317
|
- Codex: consulta de solo lectura habilitada.
|
|
285
318
|
- OpenCode: consulta restringida habilitada; MADRE inyecta permisos efímeros y no modifica la configuración global. Si tu configuración de OpenCode no fija modelo, `run` elige el proveedor por defecto, que puede no ser el que tiene sesión válida; fija `PULSE_OPENCODE_MODEL=proveedor/modelo` (por ejemplo `openai/gpt-5.6-sol`) al arrancar MADRE.
|
|
286
|
-
- Claude Code: consulta restringida habilitada con Safe Mode, herramientas locales de lectura, MCP
|
|
319
|
+
- Claude Code: consulta restringida habilitada con Safe Mode, herramientas locales de lectura, MCP limitado al servidor de memoria de MADRE (`pulse-memory`) y sesiones no persistentes.
|
|
287
320
|
- Gemini CLI: consulta restringida habilitada con Plan Mode y una política efímera que solo permite herramientas locales de lectura. MADRE ejecuta Gemini con un `GEMINI_CLI_HOME` temporal que solo recibe las credenciales existentes (tokens OAuth y `~/.gemini/.env`; una API key guardada en el llavero del sistema funciona sin copia); hooks, extensiones, servidores MCP y memoria del `~/.gemini` real no se cargan. El relanzamiento interno del CLI se desactiva para que el timeout controle el proceso que hace la petición.
|
|
288
321
|
|
|
289
322
|
Todos los adaptadores corren en su propio grupo de procesos. Si un agente no responde antes del timeout, MADRE termina el árbol completo (SIGTERM y, tras un periodo de gracia, SIGKILL), no solo el lanzador.
|
|
290
323
|
|
|
291
324
|
## Cambios
|
|
292
325
|
|
|
293
|
-
Ver [CHANGELOG.md](CHANGELOG.md). La versión actual es 0.
|
|
326
|
+
Ver [CHANGELOG.md](https://github.com/jossuealcacao-exe/madre/blob/main/CHANGELOG.md) y el [roadmap](https://github.com/jossuealcacao-exe/madre/blob/main/docs/ROADMAP.md). La versión actual es 0.3.0, beta pública: el núcleo está probado y bajo CI, la superficie sigue cambiando y las decisiones que aún duelen están escritas en el modelo de amenazas. Los problemas se reportan desde MU/TH/UR (`✎ FEEDBACK` o el sentinel) o en [issues](https://github.com/jossuealcacao-exe/madre/issues); la seguridad, según [SECURITY.md](https://github.com/jossuealcacao-exe/madre/blob/main/SECURITY.md).
|
|
294
327
|
|
|
295
328
|
## Licencia
|
|
296
329
|
|
package/SECURITY.md
CHANGED
|
@@ -13,7 +13,7 @@ Please include the MADRE version (`madre doctor --json`), the platform, which ag
|
|
|
13
13
|
|
|
14
14
|
## Known, accepted for the beta
|
|
15
15
|
|
|
16
|
-
- In `#3 CONTROL`,
|
|
16
|
+
- In `#3 CONTROL`, `.env` files, `.pulse/`, `.madre/` and `.claude/settings.local.json` are made read-only for the length of the turn and restored from the checkpoint afterwards; `.git/` stays writable because the CLIs need it and is only restored after the turn. An agent that changes permissions on purpose is caught by that restoration, not prevented.
|
|
17
17
|
- Everything said outside `#0 GHOST` is kept in the room's memory and reaches every agent of that room. Use GHOST for what must not be remembered.
|
|
18
18
|
|
|
19
19
|
NOBODY DELETES MOTHER'S MEMORY. EVERYTHING ELSE IS FAIR GAME.
|
package/bin/madre.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
5
6
|
import { startPulse } from '../src/server.mjs';
|
|
6
7
|
import { detectAgents } from '../src/runtime-detection.mjs';
|
|
7
8
|
import { probeAll } from '../src/auth-probe.mjs';
|
|
@@ -42,6 +43,14 @@ if (nodeMajor < 22 || (nodeMajor === 22 && nodeMinor < 5)) {
|
|
|
42
43
|
console.error(`\n MOTHER › MADRE needs Node 22.5 or newer (found ${process.version}): the room's memory runs on node:sqlite.\n`);
|
|
43
44
|
process.exit(2);
|
|
44
45
|
}
|
|
46
|
+
if (has('--version') || has('-v') || command === 'version') {
|
|
47
|
+
// Version and commit, so a report can name exactly what ran.
|
|
48
|
+
const pkg = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
|
|
49
|
+
let commit = '';
|
|
50
|
+
try { commit = execFileSync('git', ['rev-parse', '--short', 'HEAD'], { cwd: new URL('..', import.meta.url).pathname, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim(); } catch { /* installed from npm: no repo */ }
|
|
51
|
+
console.log(`madre ${pkg.version}${commit ? ` · ${commit}` : ''} · node ${process.version}`);
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
45
54
|
const stateRoot = process.env.PULSE_HOME;
|
|
46
55
|
if (command !== 'help') {
|
|
47
56
|
const stats = await stat(projectRoot).catch(() => null);
|
|
@@ -70,15 +79,38 @@ if (command === 'doctor' && (has('--catalog') || has('--conditions'))) {
|
|
|
70
79
|
console.log('');
|
|
71
80
|
}
|
|
72
81
|
process.exitCode = 0;
|
|
82
|
+
} else if (command === 'dataset') {
|
|
83
|
+
// Export the room's dataset without opening the room: the same files the server writes.
|
|
84
|
+
const { createHash } = await import('node:crypto');
|
|
85
|
+
const { join, basename, resolve: resolvePath } = await import('node:path');
|
|
86
|
+
const { homedir } = await import('node:os');
|
|
87
|
+
const { realpath } = await import('node:fs/promises');
|
|
88
|
+
const { EventStore } = await import('../src/event-store.mjs');
|
|
89
|
+
const { RoomMemory } = await import('../src/memory.mjs');
|
|
90
|
+
const { exportDataset } = await import('../src/dataset.mjs');
|
|
91
|
+
const root = stateRoot ?? process.env.PULSE_HOME ?? join(homedir(), '.pulse');
|
|
92
|
+
const canonical = await realpath(projectRoot).catch(() => resolvePath(projectRoot));
|
|
93
|
+
const roomId = `${basename(canonical) || 'root'}-${createHash('sha256').update(canonical).digest('hex').slice(0, 16)}`;
|
|
94
|
+
const roomDir = join(root, 'rooms', roomId);
|
|
95
|
+
const store = await new EventStore(join(roomDir, 'events.jsonl')).initialize();
|
|
96
|
+
const memory = await new RoomMemory(join(roomDir, 'memory.sqlite')).initialize(store).catch(() => null);
|
|
97
|
+
const result = await exportDataset({ events: await store.readAll(), notes: memory ? memory.memories({ limit: 5000 }) : [], dir: join(roomDir, 'dataset'), project: basename(canonical), home: homedir() });
|
|
98
|
+
memory?.close();
|
|
99
|
+
if (has('--json')) console.log(JSON.stringify(result, null, 2));
|
|
100
|
+
else console.log(`\nMADRE dataset · ${result.project}\n\n pairs ${result.pairs} (${result.turns} turns · ${result.notes} notes)\n train ${result.train}\n valid ${result.valid}\n by agent ${Object.entries(result.byAgent).map(([id, n]) => `@${id} ${n}`).join(' · ') || '-'}\n folder ${result.dir}\n\n Train it: docs/training/README.md (mlx-lm on Apple Silicon), then \`ollama create madre-${result.project.toLowerCase().replace(/[^a-z0-9]+/g, '-')}\` and @madre picks it up.\n`);
|
|
101
|
+
process.exitCode = 0;
|
|
73
102
|
} else if (command === 'doctor') {
|
|
74
103
|
const agents = await detectAgents();
|
|
75
104
|
const probes = await probeAll(agents);
|
|
105
|
+
const { localIntelligence, madreOnline } = await import('../src/setup.mjs');
|
|
106
|
+
const ollama = await localIntelligence();
|
|
76
107
|
const report = agents.map((agent) => ({ ...agent, session: probes[agent.id] }));
|
|
77
108
|
const result = {
|
|
78
|
-
ok: report.some((agent) => isOnline(agent, agent.session)),
|
|
109
|
+
ok: report.some((agent) => isOnline(agent, agent.session)) || madreOnline(ollama),
|
|
79
110
|
node: process.version,
|
|
80
111
|
project: projectRoot,
|
|
81
112
|
agents: report,
|
|
113
|
+
ollama: { running: Boolean(ollama.running), chatModel: ollama.chatModel ?? null, embedModel: ollama.embedModel ?? null, madre: madreOnline(ollama) },
|
|
82
114
|
};
|
|
83
115
|
|
|
84
116
|
if (has('--json')) {
|
|
@@ -90,6 +122,7 @@ if (command === 'doctor' && (has('--catalog') || has('--conditions'))) {
|
|
|
90
122
|
const session = agent.detected ? ` · ${agent.session.state}${agent.session.detail ? ` (${agent.session.detail})` : ''}` : '';
|
|
91
123
|
console.log(` ${agent.label.padEnd(10)} ${mark}${agent.version ? ` · ${agent.version}` : ''}${session}`);
|
|
92
124
|
}
|
|
125
|
+
console.log(` ${'Ollama'.padEnd(10)} ${ollama.disabled ? 'ignored (PULSE_OLLAMA=0)' : ollama.running ? `running${ollama.chatModel ? ` · @madre with ${ollama.chatModel}` : ' · no chat model yet'}${ollama.embedModel ? ` · embeddings ${ollama.embedModel}` : ''}` : 'not running · optional'}`);
|
|
93
126
|
console.log(`\n Project ${result.project}`);
|
|
94
127
|
console.log(result.ok ? '\nReady to start. Known conditions and fixes: `madre doctor --catalog [query]`.\n' : '\nNo agent is online. Run `madre setup`. Known conditions and fixes: `madre doctor --catalog`.\n');
|
|
95
128
|
}
|
|
@@ -109,7 +142,8 @@ if (command === 'doctor' && (has('--catalog') || has('--conditions'))) {
|
|
|
109
142
|
if (process.stdin.isTTY && process.stdout.isTTY && !has('--no-setup')) {
|
|
110
143
|
const agents = await detectAgents();
|
|
111
144
|
const probes = await probeAll(agents);
|
|
112
|
-
|
|
145
|
+
const { localIntelligence, madreOnline } = await import('../src/setup.mjs');
|
|
146
|
+
if (!agents.some((agent) => isOnline(agent, probes[agent.id])) && !madreOnline(await localIntelligence())) {
|
|
113
147
|
const { action } = await runSetup({ projectRoot, stateRoot });
|
|
114
148
|
if (action !== 'start') process.exit(0);
|
|
115
149
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jossuealcala/madre",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MADRE: one local room where the AI coding agents already installed on your machine (Codex, Claude Code, Gemini CLI, OpenCode) work on a project together over the PULSE channel: read-only by default, per-message permission modes up to a checkpointed CONTROL, a shared memory every agent recalls and queries, and NOSTROMO to browse it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -55,9 +55,10 @@
|
|
|
55
55
|
"scripts": {
|
|
56
56
|
"start": "node ./bin/madre.mjs start",
|
|
57
57
|
"doctor": "node ./bin/madre.mjs doctor",
|
|
58
|
-
"test": "node --test",
|
|
58
|
+
"test": "node --import ./test/setup.mjs --test",
|
|
59
59
|
"check": "npm test && node ./bin/madre.mjs doctor --json",
|
|
60
|
-
"pack:check": "node ./scripts/pack-check.mjs"
|
|
60
|
+
"pack:check": "node ./scripts/pack-check.mjs",
|
|
61
|
+
"release": "node ./scripts/release.mjs"
|
|
61
62
|
},
|
|
62
63
|
"publishConfig": {
|
|
63
64
|
"access": "public"
|