@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/en/SDK.md ADDED
@@ -0,0 +1,308 @@
1
+ # MADRE SDK · write your own modules
2
+
3
+ A MADRE module is **one file**. No build, no dependencies, no signing up anywhere. You copy it into a folder, reload the modules from «Create your module» in MODULES, and it shows up on the board with its switch. You can write it by hand or ask an AI for it, with this document as context.
4
+
5
+ ## Where it lives
6
+
7
+ | Folder | Scope |
8
+ |---|---|
9
+ | `~/.pulse/modules/*.mjs` | All your rooms |
10
+ | `<proyecto>/.madre/modules/*.mjs` | That project only |
11
+
12
+ No agent can write there: `.madre/` is a forbidden zone in CONTROL and AIRLOCK, and `~/.pulse` is outside every project. A module gets into MADRE only because you put it there.
13
+
14
+ ## The file
15
+
16
+ The `export default` is a plain object. MADRE wraps it with `defineModule`. There are two complete
17
+ examples, and both work as is:
18
+
19
+ | | what it teaches |
20
+ |---|---|
21
+ | [`hello-module.mjs`](../sdk/hello-module.mjs) | the minimum: a switch, one setting, a `/hello` command |
22
+ | [`connector-module.mjs`](../sdk/connector-module.mjs) | a real connector: key in the vault, declared destination, and **a single file that is the module page when imported and the MCP server when executed** |
23
+
24
+ Start with the first one. If your module talks to something outside this computer, copy the
25
+ second: that shape can't be guessed, and the obvious way to write it fails **silently** (see
26
+ "A file that is also a server", below).
27
+
28
+ ```js
29
+ export default {
30
+ id: 'hello', // kebab-case
31
+ name: 'HELLO',
32
+ summary: 'Qué hace, en una frase.',
33
+ settings: { enabled: false, greeting: 'hola' },
34
+ async status(ctx) { return { status: { installed: Boolean(ctx.settings.enabled), detail: ctx.settings.enabled ? 'on' : 'off' } }; },
35
+ slash: [{ name: 'hello', usage: '/hello [name]', summary: 'Saluda.', async execute(ctx, args) { return { ok: true, title: 'HELLO', text: `${ctx.settings.greeting}, ${args[0] ?? 'crew'}` }; } }],
36
+ };
37
+ ```
38
+
39
+ **Your module does not import packages.** Not MADRE, not the SDK, nothing from npm. Before installing it, MADRE copies your file to a separate temporary folder and loads it there —that way it checks what it is without running it where it lives— and that folder has no `node_modules`: an `import` by package name doesn't resolve and the installation fails.
40
+
41
+ **Node builtins do work**, always: `node:fs`, `node:url`, `node:tls`, `node:child_process`. That's enough to speak any protocol. What there isn't is anything to install.
42
+
43
+ If you need `defineModule` —to compute something before defining the module, for example— **MADRE hands it to you**: export a function and you receive it as an argument.
44
+
45
+ ```js
46
+ export default ({ defineModule }) => defineModule({
47
+ id: 'mi-modulo',
48
+ name: 'MI MÓDULO',
49
+ // …lo que hayas calculado arriba
50
+ });
51
+ ```
52
+
53
+ > The modules that ship with MADRE do write `import { defineModule } from './sdk.mjs'`, because they live inside the package. **If you ask an agent to write one for you, it will read those files and copy that line** — and it won't work. Tell it to export a plain object, or the function above.
54
+
55
+ ## What a module can declare
56
+
57
+ This table is **the complete contract**: 38 fields, not one more. Any other field you write, MADRE
58
+ tells you about at install time ("I didn't understand these fields") instead of silently ignoring it. A test in
59
+ the suite compares this table against the code, so if they ever drift apart, it's a failure.
60
+
61
+
62
+ | Field | What it is |
63
+ |---|---|
64
+ | `id`, `name`, `vendor`, `summary`, `creates`, `requires` | Its page in MODULES. `summary` is one sentence: what it does. `creates` and `requires` are short lines, one idea each |
65
+ | `version` | Yours, and it starts at `1.0.0`. If you don't declare it, the page shows the file's date |
66
+ | `tracks` | If your module wraps something from outside, its version isn't yours: it's that thing's. Declare `{ name, npm }` or `{ name, github }` and return the version found in `status(ctx)` as `runs: [{ name, version }]`. MADRE shows that version and looks for a newer one on its own, once a day, with the page's ↻ button to check now |
67
+ | `updatePlan(ctx, { latest })` | How that new version is brought to this computer: `{ command, args, display, note, after }`. MADRE shows `display` and runs nothing until the human has read it; the output lands in the room line by line. With no command, return `{ command: null, note, download }` and the page sends you to download it |
68
+ | `updates` | An https `{ url }` where you publish **your own module**. With that, its page gets a button that fetches the file, verifies it the same way as an installation, and replaces it if it passes. If you installed it from a file, MADRE remembers which one and you don't need to declare anything: edit it and ask for a new copy |
69
+ | `settings` | Default values. They live in `~/.pulse/config.json` under `modules.<idEnCamelCase>`; `enabled` is the switch for every project, and `rooms` keeps what each project said, which wins. MADRE works it out for you: `ctx.settings.enabled` is already this project's |
70
+ | `status(ctx)` | What the card shows: `{ status: { installed, detail }, preflight: { ok, problems }, install: { display } }`. `install` is returned from here; it is not a top-level field of the module |
71
+ | `status(ctx)` → `runs` | What your module manages that isn't MADRE: `[{ name, version, target }]`. `version` is what you found on this computer (`null` if it isn't there), `target` is what you would install. If it matches `tracks.name`, that is the page's version |
72
+ | `toggle(ctx, payload)` | Replaces the default switch; `confirm: 'texto'` asks for confirmation before turning on |
73
+ | `onToggle(ctx, enabled)` | Reacts to the switch |
74
+ | `ready(ctx)` | What you ask before turning on, in one project or in all (from the Market too): `null` when ready, `{ status, body: { error } }` when not. Turning off never asks it |
75
+ | `footer` | Up to two keys beside MADRE's version, bottom right, while your module is on: `[{ icon: 'heart' \| 'star' \| 'link', label, text, action, url }]`. Words can be one sentence or `{ en, es }`; `url` must be https and opens in a new tab. MADRE draws it: on hover it shows `text` and a button with `action` |
76
+ | `slash` | `/name` commands that run on the server with your `ctx` and return `{ ok, title, text }`. The room shows them as a card and the agents read them |
77
+ | `toolsForTurn(ctx, turn)` | MCP servers for an agent's turn: `[{ name, command, args, env, tools, sends, brief }]`. MADRE attaches them to the CLI in its isolated run and describes `brief` to the agent. `turn` carries the agent, the mode, the lease, the folder, the port, and `turn.turn`: the id of the reply that turn will write. If your server calls back to the room on behalf of the turn, send that id; `ctx.room.runningTurn(id)` tells you whether it is still running and for which agent |
78
+ | `toolsForTurn` → `sends` | Which of your tools **send something outside**. The core withdraws them below `#4` AIRLOCK: the model isn't even told they exist. See below |
79
+ | `reaches` | Where your module reaches, in the same four answers MADRE gives about its own. See below |
80
+ | `secrets` | The keys you need, declared instead of drawn: `[{ name, label, note, where }]`. MADRE draws the field, keeps it in its vault under your id, and gives it back to you through `ctx.vault`. See below |
81
+ | `routes` | Your own HTTP routes: `{ method, path, handler(ctx, { payload, params, url, request, viaPhone }) }` → `{ status, body }`. `viaPhone` is `true` when the request comes from a paired phone: deny it yourself if your route belongs to the Mac |
82
+ | `onEvent(ctx, event)` | Every ledger event of every live conversation in the room, while your module is on. `ctx.room` and `ctx.chat` are that conversation's, and `ctx.record` writes into it. It runs separately: whatever it takes long on or fails at doesn't stop the room. As always, a module doesn't fabricate messages or turns |
83
+ | `controls` | Your module's settings, declared instead of drawn: `[{ key, label, type: 'select' \| 'switch' \| 'text', options, choices, note, invert }]`. MADRE draws them on the page and saves them in your block of `config.json`. In a `select`, `choices: [{ value, label }]` says which phrase the person reads for each value that gets saved (if you give it, `options` comes from there); without it, the person reads the value as is |
84
+ | `onSettings(ctx, settings)` | Tells you when the human changed one of your `controls`, in case something live needs to know |
85
+ | `conditions` | Entries for the MU/TH/UR catalog, with a remedy per platform |
86
+ | `kind` | `'builtin'` (the default) changes how MADRE behaves and lives in `config.json`; `'installer'` writes into the project with a command the human confirms before it runs |
87
+ | `configKey` | Your block in `config.json`. By default it is your `id` in camelCase; declare it only if you want a different one |
88
+ | `card` | Which card MADRE draws. A module of yours leaves the default value: the named cards are the ones MADRE ships drawn for its own |
89
+ | `models` | The models your module chooses between, if it wraps something that has them. They show up on the page |
90
+ | `package` | The npm package that installs what your module manages, if there is one |
91
+ | `confirm` | A text. If it is there, turning on the switch asks for confirmation and doesn't turn on until the human gives it |
92
+ | `toggledEvent`, `toggledBody` | What gets added to the `extension.toggled` event and to the notice the room sees when your module is turned on or off |
93
+ | `preflight(ctx)`, `detect(ctx)`, `installCommand(ctx)` | **Legacy**, from when a module could only be an installer. They still work; for something new, return `preflight` from `status(ctx)` as above |
94
+ | `describe(ctx)` | MADRE builds it from everything above. **Don't declare it**: it is on the list because the object carries it, not because you have to write it |
95
+
96
+ ### Can it connect to *X*?
97
+
98
+ That doesn't depend on MADRE. A module can do whatever a Node process can do on your
99
+ computer: speak TLS, start a server, store a key. **It depends on how that service
100
+ lets a human hand over their own credential**, and that falls into three tiers:
101
+
102
+ | | what the service asks for | does it work on install? |
103
+ |---|---|---|
104
+ | **A** | a static key in minutes: personal token, API key, app password. No app to register, no review | **yes** |
105
+ | **B** | that each user register their own app (OAuth without restricted permissions) | yes, but signing up stops being "paste this" — and you would have to write OAuth |
106
+ | **C** | review, security assessment, or verified publisher | **no**: each user would have to be their own developer |
107
+
108
+ Almost everything useful is in **A**: GitHub, GitLab, Linear, Notion (internal integration), Jira,
109
+ Slack, Discord, Telegram, Stripe, Shopify, Cloudflare, Odoo, any database, and any
110
+ API that accepts an `Authorization: Bearer`. In **B**: Google Calendar and Drive, Microsoft Graph,
111
+ Mercado Libre. In **C**: Gmail for reading, all of Meta, banking.
112
+
113
+ **The rule**, if you don't want to read the table: it's worth it when the credential can be obtained in less
114
+ than five minutes without being a developer, can be revoked on its own, and what your module brings in or sends out fits in one
115
+ line of the page. The long catalog, and why, is in
116
+ [§6 of `CONECTORES.md`](https://github.com/jossuealcacao-exe/madre/blob/main/docs/en/CONNECTORS.md#6--qu%C3%A9-alcanza-un-m%C3%B3dulo-y-de-qui%C3%A9n-es-el-muro), in the repository.
117
+
118
+ ### A file that is also a server
119
+
120
+ `toolsForTurn` returns `args` that point to a file, and you only have one. You don't need two:
121
+ **yours is the module page when MADRE imports it and the MCP server when MADRE executes it.** It knows
122
+ which of the two it is at the end of the file.
123
+
124
+ ```js
125
+ import { realpath } from 'node:fs/promises';
126
+ import { fileURLToPath } from 'node:url';
127
+ const SELF = fileURLToPath(import.meta.url);
128
+
129
+ // …export default { …, toolsForTurn: () => [{ command: process.execPath, args: [SELF], … }] }
130
+
131
+ const real = async (p) => (p ? realpath(p).catch(() => p) : null);
132
+ if ((await real(process.argv[1])) === (await real(SELF))) serve();
133
+ ```
134
+
135
+ **Resolve both paths before comparing them.** `process.argv[1] === SELF` looks the same and almost
136
+ always is: when MADRE launches it, it passes the same `SELF` that Node's loader already resolved.
137
+ But as soon as **you run the file yourself by hand to test it** —`node ~/.pulse/modules/tuyo.mjs`, or
138
+ any path that goes through `/tmp`, which on macOS is a link to `/private/tmp`— `argv[1]` keeps
139
+ what you typed and `SELF` doesn't. The comparison comes out false, `serve()` never runs, the process starts,
140
+ answers nothing and **exits successfully**. It doesn't print an error because, on paper, there wasn't one.
141
+ Two lines save you that afternoon.
142
+
143
+ ### If your module talks to an outside service
144
+
145
+ Declare where it reaches. `src/outbound.mjs` is not a log of outgoing traffic: it is a contract, and
146
+ it patches global `fetch` so that no module can get around it. A connector that doesn't declare its
147
+ destination shows up in the log as "went to an address nothing here declares" — true, and
148
+ useless to someone trying to tell your module apart from a leak.
149
+
150
+ ```js
151
+ reaches: [{
152
+ id: 'gmail',
153
+ host: 'gmail.googleapis.com',
154
+ to: 'Google · Gmail, con tu cuenta',
155
+ what: 'El asunto y el cuerpo del correo que el agente redactó.',
156
+ when: 'cuando un agente usa la herramienta de envío',
157
+ where: 'MODULES → CORREO',
158
+ }]
159
+ ```
160
+
161
+ The four answers are the same ones MADRE gives about its own, and for the same reason: whoever
162
+ reads the log deserves to know what travels, when, where to, and where it's turned off. Your declaration is
163
+ stored **separately** from the core's and marked with your `id`, because who promised what is part
164
+ of the promise. It is rebuilt on every load: uninstalling your module takes its destination with it.
165
+
166
+ If you point your module at another server at runtime, declare again with the **same
167
+ `id`**: that way the entry is replaced instead of leaving the log answering for an address
168
+ you no longer use.
169
+
170
+ ### If your module needs a key
171
+
172
+ Declare them and don't ask for them yourself. MADRE draws a password field on the `KEYS` floor of your
173
+ page, accepts the value **only from this computer** (`127.0.0.1`), stores it in
174
+ `~/.pulse/credentials/<tu-id>.json` with `0600` permissions inside a `0700` directory, and notes
175
+ in the ledger that one was saved and **with what name and what length, never the value**.
176
+
177
+ ```js
178
+ secrets: [{
179
+ name: 'app-password',
180
+ label: 'APP PASSWORD',
181
+ note: 'No es la contraseña de tu cuenta. Una de aplicación, que puedes revocar sola.',
182
+ where: 'https://myaccount.google.com/apppasswords', // enlace a dónde sacarla
183
+ }]
184
+ ```
185
+
186
+ And you read it through `ctx.vault`, which comes scoped to your module:
187
+
188
+ ```js
189
+ await ctx.vault.get('app-password') // el valor, solo para ti
190
+ await ctx.vault.held() // [{ module, name, bytes }] — nombres y tamaños, nunca valores
191
+ await ctx.vault.keep(name, value) // guardar
192
+ await ctx.vault.forget(name) // olvidar; sin nombre, todas las tuyas
193
+ ```
194
+
195
+ Your id is sealed inside the SDK, so asking for another module's secret is not something you can
196
+ *write*. The page only shows that one is stored and how many characters it has.
197
+
198
+ **The value goes to the environment of the process you start, and nowhere else.** Not to the prompt, not
199
+ to the `brief`, not to a tool result, not to the ledger.
200
+
201
+ ### If your module sends something
202
+
203
+ Reading can be undone: in the worst case you brought in something that wasn't useful. **Sending can't.** An email, a
204
+ message, a record in someone else's system: that goes out under the name of whoever opened the room
205
+ and doesn't come back.
206
+
207
+ That's why sending lives in `#4` AIRLOCK, where the rule already requires the agent to say in one line
208
+ what goes out and where before it goes out. **The core enforces it, not your good will:**
209
+
210
+ ```js
211
+ tools: ['buscar_correo', 'mandar_correo'],
212
+ sends: ['mandar_correo'], // por debajo de #4 esta se retira de la lista
213
+ ```
214
+
215
+ If *all* of a server's tools send, the whole server doesn't travel below
216
+ `#4`. If some don't send, the server travels with the list trimmed and a `brief` that says why
217
+ it comes short. And whatever you decide to check, check it **in your server and not in the `brief`**: a
218
+ prompt is a suggestion.
219
+
220
+ **Can it connect to *X*?** The answer doesn't depend on MADRE but on how that service lets
221
+ a human hand over their own key, and it is mapped in three tiers —with a catalog— in
222
+ [§6 of `CONECTORES.md`](https://github.com/jossuealcacao-exe/madre/blob/main/docs/en/CONNECTORS.md#6--qu%C3%A9-alcanza-un-m%C3%B3dulo-y-de-qui%C3%A9n-es-el-muro), in the repository.
223
+ Read it before writing anything: it saves you discovering halfway through that the service requires an annual
224
+ security review to let you in.
225
+
226
+ The whole design of the connectors is in
227
+ [`CONECTORES.md`](https://github.com/jossuealcacao-exe/madre/blob/main/docs/en/CONNECTORS.md), in the repository. A complete connector to read from beginning
228
+ to end —CORREO, which sends email over SMTP without a single dependency— is in
229
+ `src/modules/correo.mjs` and takes ten minutes to read. It doesn't appear in MODULES yet: we're
230
+ finishing it, and in the meantime it can only be turned on deliberately with `PULSE_LABS=correo`.
231
+
232
+ ## Publishing it
233
+
234
+ The page of a module of yours has **GET A NEWER FILE**: MADRE fetches the file —from the `url` you declared or from the file you installed it from—, verifies it in a separate copy, and only replaces the installed one if it loads, follows the house rules, and states a different version. Verifying installs nothing.
235
+
236
+ And in the MODULES header there is **+ ADD A MODULE** to install someone else's `.mjs`. It goes through the same door as everything else. Said plainly, because it is what it is: a module runs **inside MADRE, with the permissions of whoever opens it**. MADRE checks that it loads and that it doesn't leave its pen —its own id, routes only under `/api/x/<id>/`, never on top of a MADRE module—; what the code *intends* is something nobody but you can check.
237
+
238
+ ## The module page
239
+
240
+ You don't draw anything: you declare, and MADRE builds your module the same way as its own. In MODULES each module is a card on the board and, when you tap it, a page with the same blocks as SETTINGS. That's why yours reads the same as the ones MADRE ships.
241
+
242
+ **The board card** has an icon, your `name`, a line with your `summary`, and its switch if it is a module that gets turned on. A module of yours carries the «Yours» tag.
243
+
244
+ **The page**, in this order:
245
+
246
+ | Block | What it shows | Where it comes from |
247
+ |---|---|---|
248
+ | What it does | your sentence, the «Active» switch with what your module says about itself, and the version with «Look for a newer one» | `summary`, `status(ctx).status.detail`, `vendor`, `version` or `tracks` |
249
+ | Settings | one row per control: its name on the left, the selector, switch, or field on the right; it saves when you change it | `controls` |
250
+ | Keys | one field per secret, what is stored (name and length, never the value), and the option to forget it | `secrets` |
251
+ | What it touches | each thing it writes or needs, with its label | `creates`, `requires` |
252
+ | Commands | what it adds to the text box | `commands` or `slash` |
253
+ | Yours | get a newer file and remove it | the file you installed, `updates` |
254
+
255
+ A module that installs into the project instead of being turned on keeps its install card, with the command in view before anything runs, inside the «What it does» block. The figures at the top of the page and the dedicated window belong to MADRE's modules that keep a reading (Ash, Suggested effort, Ollama); you don't need to declare anything for them.
256
+
257
+ ## The `ctx`
258
+
259
+ ```
260
+ ctx = {
261
+ projectRoot, stateRoot, // el proyecto y ~/.pulse
262
+ config, settings, // config.json completo y tus ajustes con defaults
263
+ env, agents, room, // agentes detectados; la sala (room.capabilities(), room.record(...))
264
+ readConfig(), updateConfig(patch),
265
+ record(type, payload), // escribe un evento en el ledger; tipo "algo.algo", nunca message.* ni agent.*
266
+ services: { imageKey, ollama, … }, // lo que el servidor ofrece
267
+ vault: { get, held, keep, forget } // tus secretos, y solo los tuyos
268
+ }
269
+ ```
270
+
271
+ `turn`, in `toolsForTurn`: `{ agent, mode, lease, scratchDir, port, roomDir }`. `mode` goes from 0 to 4; in 0 (GHOST) nothing is saved, so decide whether you want to hand over tools there.
272
+
273
+ ## House rules
274
+
275
+ - **Nothing leaves the machine on its own.** If your module talks to a service, say so in `summary` and in `requires`, and do it only when the human asks for it.
276
+ - **Don't store credentials.** Use the sessions that already live on the machine.
277
+ - **Don't write into the project** from a module; that's what the agents' modes are for. A module that installs something into the project is `kind: 'installer'` and shows the command before running it.
278
+ - **Fail softly.** An exception in `toolsForTurn` hands over nothing; in a command, the card states the error. Never break an agent's turn.
279
+ - **MADRE's voice.** Short uppercase labels, notes that say what doesn't leave the machine, `MU/TH/UR › ` when you speak in a notice.
280
+
281
+ ## Let your AI build it, in the room
282
+
283
+ Type `/module <lo que debe hacer>` in the composer. It is the explicit entry point to the guided flow: if `#2 CREATE` isn't active, MADRE asks you to choose it and keeps your request intact. With `#2` active, it keeps the agent you chose and hands it the SDK contract and the example. The agent must write **a single file** named `<id>.module.mjs` in its scratch folder; it cannot install it on its own.
284
+
285
+ MADRE recognizes that name and puts a card in the room: `INSTALL FOR EVERY ROOM` or `INSTALL FOR THIS PROJECT`. Read it, decide, one click. MADRE validates it in a copy, saves it as `<id>.mjs` in the folder you chose, and it appears in MODULES with the «Yours» tag. You can also ask for the same thing in natural language while you're in `#2` or higher; `/module` makes the format explicit and doesn't grant permissions on its own.
286
+
287
+ Agents never write to `~/.pulse/modules` or `.madre/modules`: they propose, you install.
288
+
289
+ A module of yours carries the «Yours» tag and is removed from its page with «Remove» —also from «Create your module», in the list of yours—. MADRE confirms the exact file, deletes that file and its origin record for updates, and withdraws it from the room without restarting it. It doesn't delete files the module created or its saved settings. The modules that ship with MADRE don't show that button: they aren't removed, they're turned off.
290
+
291
+ ## What a module cannot touch
292
+
293
+ A module runs inside MADRE's process with your permissions: install only what you've read. MADRE, for its part, protects its core like this:
294
+
295
+ - Its HTTP routes live under `/api/x/<id>/`; a module with routes outside that doesn't load, so none can impersonate `/api/state`, `/api/messages`, or any route of MADRE's own.
296
+ - It cannot use the `id` of a built-in module or of another one already loaded.
297
+ - `record()` rejects the reserved event types (`message.*`, `agent.*`); it cannot fabricate turns or messages.
298
+ - It receives nobody's credentials; like MADRE, it uses the sessions that already live on the machine.
299
+ - An error in `toolsForTurn` hands over nothing; in a command, the card states the error; at load time, the board warns how many didn't load and «Create your module» says which file and why. None of that stops the room.
300
+
301
+ ## Testing it
302
+
303
+ 1. Copy the file to `~/.pulse/modules/`.
304
+ 2. In the room, MODULES → «Create your module» → «Reload modules». If the file has an error, it tells you right there with the exact line.
305
+ 3. Turn it on with its switch. Type `/tu-comando` in the composer.
306
+ 4. Change the file and reload again: no need to restart the room.
307
+
308
+ With an AI: give it this document and `hello-module.mjs`, describe what you want, and ask it for a single `.mjs` file with `export default { … }`. MADRE does the rest.
@@ -0,0 +1,59 @@
1
+ # MADRE AI · train the project's model
2
+
3
+ Roadmap 2c. The project exports what it remembers as chat pairs; you train a small model with them on your machine; Ollama serves it; `@madre` uses it as soon as it exists. All local.
4
+
5
+ ## 1 · Export
6
+
7
+ From **Settings › What it remembers › Train your own AI › Export** (when it finishes it tells you which folder it used), or in the terminal:
8
+
9
+ ```
10
+ npx @jossuealcala/madre dataset # in the project folder
11
+ ```
12
+
13
+ It writes `~/.pulse/rooms/<project>/dataset/{train.jsonl, valid.jsonl, manifest.json}`. Each line is `{"messages":[{role:"system"},{role:"user"},{role:"assistant"}]}`: the project's real answers, redacted (no paths, names, emails or keys), plus the summarized notes as recall pairs. Messages sent in #0 INCOGNITO are never there.
14
+
15
+ How much you need: with fewer than ~200 pairs the model learns the tone and little more; from ~1000 on it starts to be worth it. Export every so often; the split is deterministic, so lines don't switch sides.
16
+
17
+ ## 2 · Train (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/<project>
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
+ ### Linux with NVIDIA (experimental)
28
+
29
+ MLX publishes a CUDA package for Linux (CUDA 12, compute capability 7.5 or higher, driver 550.54.14 or higher, glibc 2.35 or newer, Python 3.10 or newer): <https://ml-explore.github.io/mlx/build/html/install.html>. mlx-lm only documents Apple silicon, so test it first:
30
+
31
+ ```
32
+ python3 -m venv ~/.madre-train && source ~/.madre-train/bin/activate
33
+ pip install "mlx[cuda12]" mlx-lm
34
+ python3 -c "import mlx.core as mx; print('CUDA:', mx.cuda.is_available())" # must say True
35
+ ```
36
+
37
+ If it says `True`, the training commands above (from `cd ~/.pulse/rooms/<project>`) and steps 3 and 4 are the same. If not, there's no tested path on Linux yet.
38
+
39
+ [`train.sh`](../../training/train.sh) in `docs/training/` does the same with checks. On 16 GB use the 1.5B; with 32 GB or more, `Qwen/Qwen2.5-3B-Instruct` or `Qwen/Qwen2.5-Coder-7B-Instruct` with `--batch-size 1`. A round of 600 iterations takes 10 to 40 minutes.
40
+
41
+ ## 3 · Serve in Ollama
42
+
43
+ ```
44
+ mlx_lm.fuse --model Qwen/Qwen2.5-1.5B-Instruct --adapter-path adapters --save-path fused
45
+ ```
46
+
47
+ Ollama reads GGUF. For Llama and Mistral `mlx_lm.fuse` accepts `--export-gguf`; for Qwen convert with llama.cpp:
48
+
49
+ ```
50
+ git clone --depth 1 https://github.com/ggml-org/llama.cpp && pip install -r llama.cpp/requirements.txt
51
+ python3 llama.cpp/convert_hf_to_gguf.py fused --outfile madre.gguf --outtype q8_0
52
+ cp <MADRE folder>/docs/training/Modelfile . && ollama create madre-<project> -f Modelfile
53
+ ```
54
+
55
+ The name matters: `madre-<project>` in lowercase, with hyphens. At the next **RECHECK** in Modules › Local AI, `@madre` switches to that model and What it remembers says so. The `Modelfile` comes in `docs/training/` of the MADRE repository and of the npm package.
56
+
57
+ ## 4 · Evaluate before trusting
58
+
59
+ Before promoting a new model, ask `@madre` the ten things the project did decide and the five it never discussed. It should get the first ones right and say "the project never discussed it" for the second ones. If it makes things up, go back to the base model (`ollama rm madre-<project>`) and train with more pairs or fewer iterations.
@@ -1,16 +1,16 @@
1
1
  # MADRE AI · entrenar el modelo del proyecto
2
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.
3
+ Roadmap 2c. El proyecto 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
4
 
5
5
  ## 1 · Exportar
6
6
 
7
- Desde MU/TH/UR → `⚙ CONNECTIONS` → `MEMORY` → `EXPORT DATASET`, o en terminal:
7
+ Desde **Ajustes › Lo que recuerda › Entrena tu propia IA › Exportar** (al terminar te dice en qué carpeta quedó), o en terminal:
8
8
 
9
9
  ```
10
- madre dataset # en la carpeta del proyecto
10
+ npx @jossuealcala/madre dataset # en la carpeta del proyecto
11
11
  ```
12
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á.
13
+ Escribe `~/.pulse/rooms/<proyecto>/dataset/{train.jsonl, valid.jsonl, manifest.json}`. Cada línea es `{"messages":[{role:"system"},{role:"user"},{role:"assistant"}]}`: las respuestas reales del proyecto, redactados (sin rutas, nombres, correos ni claves), más las notas resumidas como pares de recuerdo. Lo que se envió en #0 INCÓGNITO nunca está.
14
14
 
15
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
16
 
@@ -19,12 +19,44 @@ Cuánto hace falta: con menos de ~200 pares el modelo aprende el tono y poco má
19
19
  ```
20
20
  python3 -m venv ~/.madre-train && source ~/.madre-train/bin/activate
21
21
  pip install mlx-lm
22
- cd ~/.pulse/rooms/<sala>
22
+ cd ~/.pulse/rooms/<proyecto>
23
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
24
  mlx_lm.lora --model Qwen/Qwen2.5-1.5B-Instruct --adapter-path adapters --data dataset --test
25
25
  ```
26
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.
27
+ ### Linux con NVIDIA (experimental)
28
+
29
+ MLX publica un paquete para CUDA en Linux (CUDA 12, capacidad de cómputo 7.5 o mayor, controlador 550.54.14 o mayor, glibc 2.35 o mayor, Python 3.10 o mayor): <https://ml-explore.github.io/mlx/build/html/install.html>. mlx-lm solo documenta Apple silicon, así que pruébalo primero:
30
+
31
+ ```
32
+ python3 -m venv ~/.madre-train && source ~/.madre-train/bin/activate
33
+ pip install "mlx[cuda12]" mlx-lm
34
+ python3 -c "import mlx.core as mx; print('CUDA:', mx.cuda.is_available())" # debe decir True
35
+ ```
36
+
37
+ Si dice `True`, los comandos de entrenamiento de arriba (desde `cd ~/.pulse/rooms/<proyecto>`) y los pasos 3 y 4 son los mismos. Si no, no hay ruta probada en Linux todavía.
38
+
39
+ `train.sh` en esta carpeta hace lo mismo con comprobaciones (`bash train.sh <carpeta del proyecto> <base>`).
40
+
41
+ ### Qué tamaño entrenar
42
+
43
+ No depende de una máquina en particular, sino de la memoria de la tuya. MADRE la mide (Módulos › IA local › Tu equipo) y propone el tamaño más grande que tu computadora entrena y luego corre. Los mínimos son para la computadora completa, con el sistema y el navegador abiertos:
44
+
45
+ | Modelo | Base para entrenar | Para correrlo | Para entrenarlo |
46
+ |---|---|---|---|
47
+ | Qwen2.5 0.5B | `Qwen/Qwen2.5-0.5B-Instruct` | 4 GB | 8 GB |
48
+ | Qwen2.5 1.5B | `Qwen/Qwen2.5-1.5B-Instruct` | 6 GB | 12 GB |
49
+ | Qwen2.5 3B | `mlx-community/Qwen2.5-3B-Instruct-4bit` | 8 GB | 16 GB |
50
+ | Qwen2.5 7B | `mlx-community/Qwen2.5-7B-Instruct-4bit` | 12 GB | 24 GB |
51
+ | Qwen2.5 14B | `mlx-community/Qwen2.5-14B-Instruct-4bit` | 20 GB | 36 GB |
52
+ | Qwen2.5 32B | `mlx-community/Qwen2.5-32B-Instruct-4bit` | 36 GB | 64 GB |
53
+ | Qwen2.5 72B | `mlx-community/Qwen2.5-72B-Instruct-4bit` | 64 GB | 128 GB |
54
+
55
+ - En una Mac con chip Apple la memoria es compartida: cuenta toda.
56
+ - Con una tarjeta NVIDIA cuenta la memoria de la tarjeta (VRAM), que rinde un tercio más porque el modelo la tiene para él solo.
57
+ - Sin ninguna de las dos, un modelo corre en el procesador, más lento, y no se entrena: un LoRA en procesador tarda días.
58
+
59
+ Desde 3B la base viene en 4 bits (QLoRA), y desde 7B `train.sh` agrega `--grad-checkpoint`. Una ronda de 600 iteraciones tarda de 10 a 40 minutos hasta 3B, y una hora o más por encima. El disco libre que hace falta ronda 5.5 GB por cada mil millones de parámetros, más 2 GB.
28
60
 
29
61
  ## 3 · Servir en Ollama
30
62
 
@@ -37,11 +69,18 @@ Ollama lee GGUF. Para Llama y Mistral `mlx_lm.fuse` acepta `--export-gguf`; para
37
69
  ```
38
70
  git clone --depth 1 https://github.com/ggml-org/llama.cpp && pip install -r llama.cpp/requirements.txt
39
71
  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
72
+ cp <carpeta de MADRE>/docs/training/Modelfile . && ollama create madre-<proyecto> -f Modelfile
41
73
  ```
42
74
 
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.
75
+ Con una base en 4 bits (3B en adelante) el paso cambia en tres puntos:
76
+ 1. `mlx_lm.fuse` lleva `--de-quantize`, para que llama.cpp pueda leer el resultado.
77
+ 2. La conversión usa `--outtype f16`.
78
+ 3. `ollama create` lleva `--quantize q4_K_M`, que lo deja en 4 bits, el tamaño que cuenta la tabla.
79
+
80
+ La pantalla de entrenamiento de MADRE ya escribe así los comandos para el tamaño que elijas.
81
+
82
+ El nombre importa: `madre-<proyecto>` en minúsculas, con guiones. Al siguiente **REVISAR OTRA VEZ** en Módulos › IA local, `@madre` cambia a ese modelo y Lo que recuerda lo dice. El `Modelfile` viene en `docs/training/` del repositorio de MADRE y del paquete de npm.
44
83
 
45
84
  ## 4 · Evaluar antes de confiar
46
85
 
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.
86
+ Antes de promover un modelo nuevo, pregúntale a `@madre` las diez cosas que el proyecto sí decidió y las cinco que nunca discutió. Debe acertar las primeras y decir "el proyecto 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.
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bash
2
- # MADRE AI · one LoRA round on this room's dataset with mlx-lm (Apple Silicon).
2
+ # MADRE AI · one LoRA round on this room's dataset with mlx-lm (Apple Silicon; Linux with an
3
+ # NVIDIA card through mlx[cuda12] is experimental: mlx-lm only promises Apple chips).
3
4
  # docs/training/train.sh <room-dir> [base-model] [iters]
4
5
  set -euo pipefail
5
6
  ROOM="${1:?room dir, e.g. ~/.pulse/rooms/<sala>}"
@@ -10,8 +11,12 @@ PAIRS=$(wc -l < "$ROOM/dataset/train.jsonl")
10
11
  [ "$PAIRS" -ge 50 ] || { echo "only $PAIRS training pairs; let the room grow (aim for a few hundred)"; exit 3; }
11
12
  python3 -c "import mlx_lm" 2>/dev/null || { echo "pip install mlx-lm (inside a venv) first"; exit 4; }
12
13
  cd "$ROOM"
14
+ # From 7B up, recompute instead of keeping every activation: slower, and it fits the memory the
15
+ # room's table promises for that size (src/modules/local-models.mjs).
16
+ EXTRA=()
17
+ if [[ "$BASE" =~ -([0-9]+)B- ]] && [ "${BASH_REMATCH[1]}" -ge 7 ]; then EXTRA+=(--grad-checkpoint); fi
13
18
  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
19
+ mlx_lm.lora --model "$BASE" --train --data dataset --iters "$ITERS" --batch-size 2 --learning-rate 1e-5 --adapter-path adapters ${EXTRA[@]+"${EXTRA[@]}"}
15
20
  mlx_lm.lora --model "$BASE" --adapter-path adapters --data dataset --test
16
21
  echo
17
22
  echo "adapters in $ROOM/adapters · next: mlx_lm.fuse, convert to GGUF, ollama create madre-<project> (see README.md)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jossuealcala/madre",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "MADRE · one local room where the AI coding agents already on your machine (Codex, Claude Code, Gemini CLI, OpenCode) work on your project together, share one memory you can see and explore, and answer to you. Read-only by default, with per-message permission modes and checkpoints you can undo. Nothing leaves your machine on its own.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -36,7 +36,7 @@
36
36
  "url": "https://jossuealcala.com/en/"
37
37
  },
38
38
  "type": "module",
39
- "license": "Apache-2.0",
39
+ "license": "AGPL-3.0-only",
40
40
  "files": [
41
41
  "bin",
42
42
  "src",
@@ -54,11 +54,19 @@
54
54
  "docs/INTERNALS.md",
55
55
  "docs/REFERENCE.md",
56
56
  "SECURITY.md",
57
- "CONTRIBUTING.md"
57
+ "CONTRIBUTING.md",
58
+ "README.en.md",
59
+ "CHANGELOG.en.md",
60
+ "TRADEMARKS.en.md",
61
+ "ADDITIONAL-TERMS.md",
62
+ "docs/en/REFERENCE.md",
63
+ "docs/en/SDK.md",
64
+ "docs/en/INTERNALS.md",
65
+ "docs/en/training"
58
66
  ],
59
67
  "bin": {
60
- "madre": "./bin/madre.mjs",
61
- "pulse": "./bin/madre.mjs"
68
+ "madre": "./bin/madre.cjs",
69
+ "pulse": "./bin/madre.cjs"
62
70
  },
63
71
  "engines": {
64
72
  "node": ">=22.5.0"
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // MADRE · © 2026 Jossue Alcalá · GNU AGPL v3 with additional terms (Section 7): ADDITIONAL-TERMS.md
1
3
  // ABDUCTION — the one joke in the room, and the only thing here that is not work.
2
4
  //
3
5
  // Type MADRE into the box, alone, and send it. Not @madre: that is the local agent and it has a