@jossuealcala/madre 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/CONTRIBUTING.md +6 -1
- package/README.md +146 -219
- package/bin/madre.mjs +8 -0
- package/docs/INTERNALS.md +81 -0
- package/docs/training/Modelfile +5 -0
- package/docs/training/README.md +47 -0
- package/docs/training/train.sh +17 -0
- package/package.json +4 -2
- package/public/app.js +270 -44
- package/public/index.html +2 -0
- package/public/styles.css +40 -11
- package/public/troubleshooting.js +13 -4
- package/src/adapters/claude.mjs +4 -1
- package/src/adapters/gemini.mjs +8 -5
- package/src/adapters/madre.mjs +122 -12
- package/src/adapters/opencode.mjs +23 -6
- package/src/capabilities.mjs +10 -8
- package/src/checkpoint.mjs +118 -21
- package/src/conversation-context.mjs +4 -2
- package/src/dataset.mjs +57 -15
- package/src/directives.mjs +7 -4
- package/src/event-store.mjs +29 -1
- package/src/lease.mjs +12 -7
- package/src/memory.mjs +61 -2
- package/src/privacy.mjs +109 -0
- package/src/room/context.mjs +3 -3
- package/src/room/control.mjs +23 -11
- package/src/room/prompt.mjs +8 -4
- package/src/room.mjs +148 -32
- package/src/server.mjs +81 -6
- package/src/updates.mjs +79 -0
package/bin/madre.mjs
CHANGED
|
@@ -112,6 +112,13 @@ if (command === 'doctor' && (has('--catalog') || has('--conditions'))) {
|
|
|
112
112
|
agents: report,
|
|
113
113
|
ollama: { running: Boolean(ollama.running), chatModel: ollama.chatModel ?? null, embedModel: ollama.embedModel ?? null, madre: madreOnline(ollama) },
|
|
114
114
|
};
|
|
115
|
+
const pkg = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
|
|
116
|
+
const { checkForUpdate, detectInstall, updateCommand } = await import('../src/updates.mjs');
|
|
117
|
+
const { join: joinPath } = await import('node:path');
|
|
118
|
+
const { homedir } = await import('node:os');
|
|
119
|
+
const check = await checkForUpdate({ name: pkg.name, current: pkg.version, cacheFile: joinPath(process.env.PULSE_HOME ?? joinPath(homedir(), '.pulse'), 'updates.json'), enabled: process.env.PULSE_UPDATE_CHECK !== '0' });
|
|
120
|
+
const update = { ...check, command: updateCommand(detectInstall({ projectRoot }), pkg.name, check.latest ?? 'latest') };
|
|
121
|
+
result.update = update;
|
|
115
122
|
|
|
116
123
|
if (has('--json')) {
|
|
117
124
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -123,6 +130,7 @@ if (command === 'doctor' && (has('--catalog') || has('--conditions'))) {
|
|
|
123
130
|
console.log(` ${agent.label.padEnd(10)} ${mark}${agent.version ? ` · ${agent.version}` : ''}${session}`);
|
|
124
131
|
}
|
|
125
132
|
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'}`);
|
|
133
|
+
console.log(` ${'MADRE'.padEnd(10)} ${update.current}${update.available ? ` · ${update.latest} available · ${update.command}` : update.latest ? ' · up to date' : update.enabled ? ' · npm not reachable' : ' · update check off (PULSE_UPDATE_CHECK=0)'}`);
|
|
126
134
|
console.log(`\n Project ${result.project}`);
|
|
127
135
|
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');
|
|
128
136
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# MADRE por dentro
|
|
2
|
+
|
|
3
|
+
Lo que el README no necesita contar para usar la sala, pero sí quien quiera entenderla, operarla en condiciones raras o escribir un módulo. Cada afirmación aquí corresponde a código en `src/` y tiene prueba en `test/`.
|
|
4
|
+
|
|
5
|
+
## El ledger
|
|
6
|
+
|
|
7
|
+
Cada proyecto tiene una sala estable bajo `PULSE_HOME` (por defecto `~/.pulse/rooms/<sala>/`). Su fuente de verdad es `events.jsonl`: un evento por línea, secuencia creciente, append-only para la sala. MADRE reconstruye la ventana de conversación desde ahí aunque se reinicie o se abra desde otro IDE.
|
|
8
|
+
|
|
9
|
+
Las escrituras se serializan entre procesos locales con un lock en disco, así dos IDEs sobre la misma sala nunca producen secuencias repetidas. La única operación que reescribe el ledger es el purgado de privacidad, bajo el mismo lock, atómica (archivo temporal y rename), conservando secuencias.
|
|
10
|
+
|
|
11
|
+
Cuando cambia el agente que responde, la sala registra `handoff.created` con origen, destino y el rango de secuencias entregado. El transcript sigue siendo la fuente durable; el proyecto no se toca.
|
|
12
|
+
|
|
13
|
+
Los errores de un agente se guardan acotados en `message.failed`: una línea de hasta 500 caracteres, sin stack traces, y con los términos privados sustituidos.
|
|
14
|
+
|
|
15
|
+
## El stream
|
|
16
|
+
|
|
17
|
+
`/api/events` se alimenta del ledger, no de la memoria del proceso: los eventos que otro proceso MADRE agregue a la misma sala llegan a las páginas abiertas. El sondeo lee solo los bytes nuevos cada 500 ms (`PULSE_BROADCAST_INTERVAL_MS`); un archivo que encoge, tras un purgado, reinicia el offset. Cada frame lleva `id: <secuencia>`, así un cliente que reconecta pide desde donde se quedó. Un cliente que deja de consumir se desconecta al acumular 1 MiB sin drenar (`PULSE_SSE_MAX_BUFFERED_BYTES`). Los eventos GHOST no tienen secuencia: llegan a las páginas abiertas y nunca al ledger.
|
|
18
|
+
|
|
19
|
+
La ventana de contexto que recibe un agente es de 16 000 caracteres (`PULSE_CONTEXT_MAX_CHARS`); se omiten los mensajes antiguos antes que los recientes. Un mensaje de más de 20 000 caracteres (`PULSE_MAX_MESSAGE_CHARS`) se registra y se rechaza sin invocar al agente.
|
|
20
|
+
|
|
21
|
+
## La memoria
|
|
22
|
+
|
|
23
|
+
`memory.sqlite` vive junto al ledger y se deriva de él: si falta o su esquema cambió, se reconstruye desde `events.jsonl`. Contiene:
|
|
24
|
+
|
|
25
|
+
- `entries` con FTS5 en trigramas: todo mensaje, fallo y tarjeta de comando fuera de GHOST, con su secuencia. Las respuestas enlatadas de MADRE (`synthetic`) no entran.
|
|
26
|
+
- `memories` con FTS5: las notas destiladas, tipadas (`decision`, `fact`, `preference`, `question`), con las secuencias que las sustentan, quién las escribió y su origen (`distilled` o `noted`).
|
|
27
|
+
- `entry_vectors` y `memory_vectors`: embeddings de 768 dimensiones, calculados en segundo plano y nunca en el camino crítico de un turno.
|
|
28
|
+
|
|
29
|
+
**Recall.** Cuando el transcript excede la ventana, cada turno recibe además, dentro del mismo presupuesto (`PULSE_RECALL_SHARE`, 30 % por defecto), las notas y los intercambios anteriores que coinciden con la petición. La búsqueda léxica pondera cada término por su rareza en la sala: una ruta o un nombre pesan más que una palabra común. Con vectores, se fusiona con la similitud de coseno.
|
|
30
|
+
|
|
31
|
+
**Destilación.** Cada `PULSE_DISTILL_EVERY` intercambios sin destilar, o tras `PULSE_DISTILL_IDLE_MS` de reposo, el archivista lee un lote acotado por `PULSE_DISTILL_MAX_CHARS`, del más reciente hacia atrás, y escribe hasta cinco notas. El archivista es el más barato permitido en el orden Ollama, Gemini, OpenCode, Codex, Claude; el que falla queda en banca treinta minutos y pasa el siguiente. Una sola llamada por lote, nunca durante un turno. Para los modelos locales se pide JSON estricto.
|
|
32
|
+
|
|
33
|
+
**Embeddings.** `PULSE_EMBED_PROVIDER=auto` usa Ollama si corre con un modelo de embeddings (`nomic-embed-text`), si no la key de Gemini (`gemini-embedding-001`, la misma key que usa el Gemini CLI, incluida la del llavero de macOS). Lotes de hasta 100 textos por llamada. `PULSE_EMBED=0` deja el recall léxico.
|
|
34
|
+
|
|
35
|
+
**Herramientas MCP.** Cada turno adjunta a la CLI el servidor `pulse-memory` con configuración aislada por corrida: `memory_search`, `memory_recall`, `memory_notes`, `memory_timeline`, `project_state` y `memory_note`. `memory_note` va firmada por el agente y el mensaje del turno, se rechaza en GHOST y sus notas se marcan `noted`.
|
|
36
|
+
|
|
37
|
+
**NOSTROMO y CODE000.** El servidor exige la designación del proyecto en `GET /api/memory` y `DELETE /api/memory/:id`. Ocho toques al corazón en treinta segundos sellan el archivo diez minutos (ambas rutas responden 423), expulsan la consola y disparan un mensaje cifrado con AES-256-GCM bajo el sello de la sala (`<proyecto>/.pulse/mother.env`) que todos los agentes en línea reciben decodificado como requester `mother`. Si el sello cambia o desaparece, la sala lo detecta y avisa.
|
|
38
|
+
|
|
39
|
+
**Privacidad.** Los términos de `config.json` se sustituyen en cuatro puntos: la respuesta del agente antes de grabarla, el índice al insertar, las notas al guardarlas y el dataset al exportarlo. El purgado reescribe ledger, índice y notas conservando secuencias y la marca de destilado. El servidor relee los términos antes de cada mensaje humano, porque `config.json` es compartido por todas las salas de la máquina.
|
|
40
|
+
|
|
41
|
+
## El centinela de límites
|
|
42
|
+
|
|
43
|
+
Cada esfera de la barra lleva un anillo. Muestra el límite real del proveedor cuando el CLI lo publica, si no, la ventana local.
|
|
44
|
+
|
|
45
|
+
- **Codex** escribe en cada rollout de sesión (`~/.codex/sessions`) sus ventanas de cuenta, de 5 horas y semanal, con porcentaje usado y hora de reinicio. MADRE lee el más reciente; no hay red de por medio.
|
|
46
|
+
- **Claude Code** publica `/usage` en el endpoint OAuth de Anthropic. Con `PULSE_CLAUDE_USAGE=1`, MADRE lo consulta con el token que Claude Code guarda en el llavero o en `~/.claude/.credentials.json`; el token solo viaja a `api.anthropic.com`, como hace el propio CLI. Es opcional porque implica leer una credencial. `PULSE_OFFICIAL_QUOTA=0` desactiva toda lectura de proveedor.
|
|
47
|
+
- **Gemini y OpenCode** no publican nada localmente: su anillo es la ventana local.
|
|
48
|
+
|
|
49
|
+
La ventana local es un presupuesto blando por agente (500 000 tokens) sobre una ventana rodante de 5 horas; los turnos salen del cómputo al envejecer, las lecturas de caché pesan una décima parte y los tokens de `@madre` pesan cero. Avisa al 80, 90 y 100 % y sugiere otros agentes. Una ventana cuya hora de reinicio ya pasó cuenta como vacía; el monitor relee las fuentes cada minuto y anuncia `limit.cleared` cuando una ventana llena vuelve a la normalidad.
|
|
50
|
+
|
|
51
|
+
Un lector de cuota implementa `{ id, agent, read() }` y `read()` devuelve `null` o `{ usedPercent, resetAt, windows?, stale? }`. MADRE nunca infiere la cuota del proveedor a partir de tokens locales.
|
|
52
|
+
|
|
53
|
+
## Los adaptadores
|
|
54
|
+
|
|
55
|
+
Cada agente corre como proceso en su propio grupo, con un home aislado que solo recibe sus credenciales existentes. Si no responde antes del timeout (180 s por defecto), MADRE termina el árbol completo: SIGTERM y, tras un periodo de gracia, SIGKILL.
|
|
56
|
+
|
|
57
|
+
- **Codex**: consulta de solo lectura; `-C <carpeta> --sandbox workspace-write` en CREATE; en CONTROL, sandbox de escritura sobre el proyecto. Genera imágenes con `image_generation` usando su cuenta de ChatGPT.
|
|
58
|
+
- **Claude Code**: herramientas locales de lectura, sesiones no persistentes, MCP limitado a los servidores de MADRE. En CREATE, `--allowedTools Write(//<carpeta>/**),Edit(//<carpeta>/**)` bajo `dontAsk`: la doble barra es la forma absoluta; con una sola, Claude lee la ruta como relativa al proyecto y niega toda escritura. En CONTROL, escritura permitida en el proyecto y negada en las zonas prohibidas.
|
|
59
|
+
- **Gemini CLI**: Plan Mode y una política efímera de solo lectura, ampliada en CREATE con reglas `allow` para `write_file` y `edit` cuyo `file_path` empiece por la carpeta. Corre con un `GEMINI_CLI_HOME` temporal: tokens OAuth y `~/.gemini/.env` sí, hooks, extensiones, servidores MCP y memoria del `~/.gemini` real no. Gemini lee `@algo` como un archivo a incluir, así que MADRE escapa cada mención como `\@nombre` y la desescapa en la respuesta. Bajo 503 o 429, el CLI reintenta con backoff durante minutos y solo escribe en stderr: MADRE lo lee en vivo, corta tras `PULSE_GEMINI_IDLE_MS`, reintenta una vez con `PULSE_GEMINI_FALLBACK_MODEL` y, si tampoco, lo dice con nombre y modelo probado.
|
|
60
|
+
- **OpenCode**: permisos efímeros inyectados por corrida, sin tocar la configuración global; `permission.edit` por patrón en CREATE y CONTROL. Si tu configuración no fija modelo, `run` elige el proveedor por defecto, que puede no ser el que tiene sesión: `PULSE_OPENCODE_MODEL=proveedor/modelo` lo fija.
|
|
61
|
+
- **@madre**: no es una CLI. Es un adaptador local sobre Ollama que recibe la transcripción reciente, lo que la memoria recuerda de la pregunta y la pregunta; nunca el briefing de las CLIs. Con una ventana de 8 192 tokens, porque la de 4 096 por defecto recorta el prompt de sistema. Lo que puede resolver sin modelo, lo resuelve: identidad, órdenes que no le corresponden, peticiones de guardar memoria y la mesa redonda, que es un plan escrito por la sala con un paso por CLI en línea y su turno de cierre.
|
|
62
|
+
|
|
63
|
+
Los alcances de imagen de Claude, Gemini y OpenCode se cumplen con **Image Studio**: el servidor MCP `src/mcp/image-server.mjs`, adjunto solo dentro de un lease con el alcance encendido, que genera con la API de imágenes de Gemini y guarda el archivo en la carpeta del turno.
|
|
64
|
+
|
|
65
|
+
## CREATE por dentro
|
|
66
|
+
|
|
67
|
+
Un turno en `#2` toma la misma fotografía que CONTROL, sin asiento: varios turnos `#2` pueden correr a la vez. Al terminar, `diff` contra la fotografía: los archivos añadidos se conservan y se registran como `artifacts.created` con su ruta en el proyecto; los modificados, renombrados o borrados se restauran desde la fotografía y se anuncian en `create.reverted`. Las zonas prohibidas se restauran igual que en CONTROL. Cada CLI recibe sus herramientas de escritura sobre el proyecto: Claude Code niega `Write` si `Edit` no está permitido en la misma ruta y OpenCode deja sin herramienta de escritura si `edit` está denegado (ambos verificados con el CLI real), así que en `#2` van juntas y la garantía de "solo añadir" es la restauración posterior, no la regla previa. Gemini recibe solo `write_file`. El `scratchDir` bajo `.pulse/out/` sigue existiendo para lo que no tiene sitio y para Image Studio.
|
|
68
|
+
|
|
69
|
+
En un plan, el modo de cada paso es el mínimo entre lo que pidió el orquestador (`@agente #n:`), el techo del plan (el modo del mensaje humano) y el `MAX MODE` del agente. Bajo techo `#3`, un paso `#2` recibe un lease de proyecto emitido a nombre del orquestador y un paso `#3` toma CONTROL con su propio checkpoint, uno a la vez. Bajo techo `#1`, un paso `#2` pasa por la escalación al humano.
|
|
70
|
+
|
|
71
|
+
## CONTROL por dentro
|
|
72
|
+
|
|
73
|
+
Antes del turno, MADRE fotografía el proyecto como un commit real bajo `refs/madre/checkpoints/` con un índice temporal (en un proyecto sin git, en un repositorio sombra bajo el directorio temporal del sistema, con el proyecto como árbol de trabajo): incluye archivos sin seguimiento, respeta `.gitignore`, no toca tu rama, tu índice ni tu stash, y funciona en repositorios sin commits. Mientras dura el turno, `.env*`, `.pulse/`, `.madre/` y `.claude/settings.local.json` quedan en solo lectura a nivel de sistema de archivos y recuperan sus permisos al terminar. Después, `git diff` contra el checkpoint da la lista de cambios; cualquier escritura en una zona prohibida que hubiera pasado se revierte desde el checkpoint y se nombra. `UNDO` restaura el checkpoint completo.
|
|
74
|
+
|
|
75
|
+
## Recuperación operativa
|
|
76
|
+
|
|
77
|
+
Si MADRE se detiene a mitad de un turno, al arrancar detecta los `agent.started` sin cierre y registra un `message.failed` recuperado para cada uno. Al cerrar con Ctrl+C o `SIGTERM`, interrumpe los procesos de agente en curso, registra esos turnos como fallidos, entrega los eventos pendientes a las páginas abiertas y termina. Los planes se ejecutan en secuencia y los delegados no delegan, así que todo plan termina; `STOPALL` corta cualquier cosa en curso.
|
|
78
|
+
|
|
79
|
+
## Empaquetado y pruebas
|
|
80
|
+
|
|
81
|
+
`npm test` corre la suite con `PULSE_OLLAMA=0` para no tocar un Ollama real; ninguna prueba llama a un modelo. `npm run pack:check` empaqueta, instala en un directorio vacío y ejecuta el CLI instalado: `--help`, `doctor` y un arranque del servidor que sirve la sala y cierra limpio con `SIGTERM`. `PULSE_TEST_MODE=1` habilita `/api/test/limits` para simular ventanas de cuota.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# ollama create madre-<project> -f Modelfile
|
|
2
|
+
FROM ./madre.gguf
|
|
3
|
+
PARAMETER temperature 0.1
|
|
4
|
+
PARAMETER num_ctx 8192
|
|
5
|
+
SYSTEM """You are @madre, the memory of this MADRE project room. Answer only from what the room said and decided; when it never discussed a point, say so. Cite ledger sequences like [#123]."""
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# MADRE AI · entrenar el modelo del proyecto
|
|
2
|
+
|
|
3
|
+
Roadmap 2c. La sala exporta lo que recuerda como pares de chat; tú entrenas un modelo pequeño con ellos en tu máquina; Ollama lo sirve; `@madre` lo usa en cuanto existe. Todo local.
|
|
4
|
+
|
|
5
|
+
## 1 · Exportar
|
|
6
|
+
|
|
7
|
+
Desde MU/TH/UR → `⚙ CONNECTIONS` → `MEMORY` → `EXPORT DATASET`, o en terminal:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
madre dataset # en la carpeta del proyecto
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Escribe `~/.pulse/rooms/<sala>/dataset/{train.jsonl, valid.jsonl, manifest.json}`. Cada línea es `{"messages":[{role:"system"},{role:"user"},{role:"assistant"}]}`: los turnos reales de la sala, redactados (sin rutas, nombres, correos ni claves), más las notas destiladas como pares de recuerdo. GHOST nunca está.
|
|
14
|
+
|
|
15
|
+
Cuánto hace falta: con menos de ~200 pares el modelo aprende el tono y poco más; a partir de ~1000 empieza a valer. Exporta cada tanto; el split es determinista, así que las líneas no cambian de lado.
|
|
16
|
+
|
|
17
|
+
## 2 · Entrenar (Apple Silicon, mlx-lm)
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
python3 -m venv ~/.madre-train && source ~/.madre-train/bin/activate
|
|
21
|
+
pip install mlx-lm
|
|
22
|
+
cd ~/.pulse/rooms/<sala>
|
|
23
|
+
mlx_lm.lora --model Qwen/Qwen2.5-1.5B-Instruct --train --data dataset --iters 600 --batch-size 2 --learning-rate 1e-5 --adapter-path adapters
|
|
24
|
+
mlx_lm.lora --model Qwen/Qwen2.5-1.5B-Instruct --adapter-path adapters --data dataset --test
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`train.sh` en esta carpeta hace lo mismo con comprobaciones. En 16 GB usa el 1.5B; con 32 GB o más, `Qwen/Qwen2.5-3B-Instruct` o `Qwen/Qwen2.5-Coder-7B-Instruct` con `--batch-size 1`. Una ronda de 600 iteraciones tarda de 10 a 40 minutos.
|
|
28
|
+
|
|
29
|
+
## 3 · Servir en Ollama
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
mlx_lm.fuse --model Qwen/Qwen2.5-1.5B-Instruct --adapter-path adapters --save-path fused
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Ollama lee GGUF. Para Llama y Mistral `mlx_lm.fuse` acepta `--export-gguf`; para Qwen convierte con llama.cpp:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
git clone --depth 1 https://github.com/ggml-org/llama.cpp && pip install -r llama.cpp/requirements.txt
|
|
39
|
+
python3 llama.cpp/convert_hf_to_gguf.py fused --outfile madre.gguf --outtype q8_0
|
|
40
|
+
cp docs/training/Modelfile . && ollama create madre-<proyecto> -f Modelfile
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
El nombre importa: `madre-<proyecto>` en minúsculas, con guiones. Al siguiente `RECHECK` en MODULES → OLLAMA, `@madre` cambia a ese modelo y la tarjeta MEMORY lo dice.
|
|
44
|
+
|
|
45
|
+
## 4 · Evaluar antes de confiar
|
|
46
|
+
|
|
47
|
+
Antes de promover un modelo nuevo, pregúntale a `@madre` las diez cosas que la sala sí decidió y las cinco que nunca discutió. Debe acertar las primeras y decir "la sala nunca lo discutió" en las segundas. Si inventa, vuelve al modelo base (`ollama rm madre-<proyecto>`) y entrena con más pares o menos iteraciones.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# MADRE AI · one LoRA round on this room's dataset with mlx-lm (Apple Silicon).
|
|
3
|
+
# docs/training/train.sh <room-dir> [base-model] [iters]
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
ROOM="${1:?room dir, e.g. ~/.pulse/rooms/<sala>}"
|
|
6
|
+
BASE="${2:-Qwen/Qwen2.5-1.5B-Instruct}"
|
|
7
|
+
ITERS="${3:-600}"
|
|
8
|
+
[ -f "$ROOM/dataset/train.jsonl" ] || { echo "no dataset: run 'madre dataset' first"; exit 2; }
|
|
9
|
+
PAIRS=$(wc -l < "$ROOM/dataset/train.jsonl")
|
|
10
|
+
[ "$PAIRS" -ge 50 ] || { echo "only $PAIRS training pairs; let the room grow (aim for a few hundred)"; exit 3; }
|
|
11
|
+
python3 -c "import mlx_lm" 2>/dev/null || { echo "pip install mlx-lm (inside a venv) first"; exit 4; }
|
|
12
|
+
cd "$ROOM"
|
|
13
|
+
echo "training LoRA on $PAIRS pairs · base $BASE · $ITERS iterations"
|
|
14
|
+
mlx_lm.lora --model "$BASE" --train --data dataset --iters "$ITERS" --batch-size 2 --learning-rate 1e-5 --adapter-path adapters
|
|
15
|
+
mlx_lm.lora --model "$BASE" --adapter-path adapters --data dataset --test
|
|
16
|
+
echo
|
|
17
|
+
echo "adapters in $ROOM/adapters · next: mlx_lm.fuse, convert to GGUF, ollama create madre-<project> (see README.md)"
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jossuealcala/madre",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "MADRE
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "MADRE · one local room where the AI coding agents already on your machine (Codex, Claude Code, Gemini CLI, OpenCode) work on a project together, with a shared memory every one of them recalls and a local @madre that speaks for it. Read-only by default, per-message permission modes up to a checkpointed CONTROL. Nothing leaves your machine on its own.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
7
7
|
"codex",
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
"LICENSE",
|
|
43
43
|
"NOTICE",
|
|
44
44
|
"docs/madre-banner.svg",
|
|
45
|
+
"docs/training",
|
|
46
|
+
"docs/INTERNALS.md",
|
|
45
47
|
"SECURITY.md",
|
|
46
48
|
"CONTRIBUTING.md"
|
|
47
49
|
],
|