@jossuealcala/madre 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/ADDITIONAL-TERMS.md +93 -0
  2. package/CHANGELOG.en.md +1945 -0
  3. package/CHANGELOG.md +34 -1
  4. package/CONTRIBUTING.md +1 -1
  5. package/LICENSE +661 -202
  6. package/NOTICE +26 -14
  7. package/README.en.md +245 -0
  8. package/README.md +19 -10
  9. package/TRADEMARKS.en.md +50 -0
  10. package/TRADEMARKS.md +33 -16
  11. package/bin/madre.mjs +2 -0
  12. package/docs/INTERNALS.md +6 -0
  13. package/docs/REFERENCE.md +11 -2
  14. package/docs/en/INTERNALS.md +103 -0
  15. package/docs/en/REFERENCE.md +339 -0
  16. package/docs/en/SDK.md +306 -0
  17. package/docs/en/training/README.md +59 -0
  18. package/docs/training/README.md +20 -8
  19. package/docs/training/train.sh +2 -1
  20. package/package.json +11 -3
  21. package/public/abduction.js +2 -0
  22. package/public/app.js +1549 -409
  23. package/public/attribution.js +71 -0
  24. package/public/brands.js +3 -1
  25. package/public/editor.js +2 -0
  26. package/public/es.js +620 -400
  27. package/public/i18n.js +25 -1
  28. package/public/index.html +13 -10
  29. package/public/inquiry.js +2 -0
  30. package/public/loader.js +2 -0
  31. package/public/macroverso.js +2 -0
  32. package/public/nostromo-engine.js +2 -0
  33. package/public/resay.js +6 -0
  34. package/public/review-ask.js +2 -0
  35. package/public/routing.js +23 -1
  36. package/public/salas-mac.css +21 -4
  37. package/public/salas-mac.html +5 -1
  38. package/public/salas-mac.js +53 -28
  39. package/public/salas.css +2 -0
  40. package/public/salas.html +1 -0
  41. package/public/salas.js +4 -2
  42. package/public/styles.css +957 -18
  43. package/public/syntax.js +2 -0
  44. package/public/touch.js +2 -0
  45. package/public/tour-chapters.js +2 -0
  46. package/public/tour.js +37 -0
  47. package/public/troubleshooting.js +18 -16
  48. package/src/adapters/claude.mjs +2 -0
  49. package/src/adapters/codex.mjs +2 -0
  50. package/src/adapters/gemini.mjs +3 -1
  51. package/src/adapters/madre.mjs +3 -1
  52. package/src/adapters/opencode.mjs +7 -3
  53. package/src/adapters/process.mjs +2 -0
  54. package/src/asking.mjs +2 -0
  55. package/src/auth-probe.mjs +3 -1
  56. package/src/bridge/devices.mjs +2 -0
  57. package/src/bridge/handoff.mjs +2 -0
  58. package/src/bridge/host.mjs +2 -0
  59. package/src/bridge/network.mjs +2 -0
  60. package/src/bridge/policy.mjs +3 -1
  61. package/src/bridge/qr.mjs +2 -0
  62. package/src/bridge/server.mjs +2 -0
  63. package/src/capabilities.mjs +2 -0
  64. package/src/chats.mjs +2 -0
  65. package/src/checkpoint.mjs +2 -0
  66. package/src/choices.mjs +2 -0
  67. package/src/cli-args.mjs +2 -0
  68. package/src/cold.mjs +2 -0
  69. package/src/commands.mjs +2 -0
  70. package/src/config.mjs +2 -0
  71. package/src/conversation-context.mjs +15 -1
  72. package/src/credentials.mjs +32 -3
  73. package/src/dataset.mjs +2 -0
  74. package/src/directives.mjs +2 -0
  75. package/src/distiller.mjs +2 -0
  76. package/src/embeddings.mjs +2 -0
  77. package/src/enlaces.mjs +6 -4
  78. package/src/event-store.mjs +2 -0
  79. package/src/exam.mjs +6 -4
  80. package/src/extensions.mjs +2 -0
  81. package/src/eyecat-watch.mjs +2 -0
  82. package/src/eyecat.mjs +2 -0
  83. package/src/file-ops.mjs +2 -0
  84. package/src/files.mjs +32 -0
  85. package/src/github.mjs +2 -0
  86. package/src/heartbeat.mjs +2 -0
  87. package/src/i18n.mjs +15 -1
  88. package/src/image-studio.mjs +2 -0
  89. package/src/json-file.mjs +2 -0
  90. package/src/launch.mjs +2 -0
  91. package/src/lease.mjs +5 -1
  92. package/src/lobby-work.mjs +2 -0
  93. package/src/local-ai.mjs +2 -0
  94. package/src/looks.mjs +2 -0
  95. package/src/maturity.mjs +3 -1
  96. package/src/mcp/connect.mjs +345 -0
  97. package/src/mcp/github-server.mjs +2 -0
  98. package/src/mcp/image-server.mjs +2 -0
  99. package/src/mcp/memory-server.mjs +2 -0
  100. package/src/mcp/proxy.mjs +153 -0
  101. package/src/mcp/smtp-server.mjs +2 -0
  102. package/src/memory-dashboard.mjs +2 -0
  103. package/src/memory-tools.mjs +2 -0
  104. package/src/memory.mjs +2 -0
  105. package/src/models.mjs +45 -3
  106. package/src/modules/ahp.mjs +2 -0
  107. package/src/modules/ash-policy.mjs +2 -0
  108. package/src/modules/ash.mjs +3 -1
  109. package/src/modules/bishop-plan.mjs +5 -3
  110. package/src/modules/bishop.mjs +13 -11
  111. package/src/modules/choices.mjs +2 -0
  112. package/src/modules/correo.mjs +2 -0
  113. package/src/modules/enlaces.mjs +2 -0
  114. package/src/modules/git-pulse.mjs +2 -0
  115. package/src/modules/github.mjs +2 -0
  116. package/src/modules/helpers.mjs +2 -0
  117. package/src/modules/image-studio.mjs +3 -1
  118. package/src/modules/index.mjs +4 -1
  119. package/src/modules/intents-calibration.mjs +2 -0
  120. package/src/modules/intents-desk.mjs +4 -2
  121. package/src/modules/intents-observe.mjs +2 -0
  122. package/src/modules/intents-policy.mjs +4 -1
  123. package/src/modules/intents-try.mjs +2 -0
  124. package/src/modules/intents.mjs +8 -6
  125. package/src/modules/mcp-connect.mjs +293 -0
  126. package/src/modules/ollama.mjs +3 -1
  127. package/src/modules/playwright.mjs +25 -10
  128. package/src/modules/ripley.mjs +2 -0
  129. package/src/modules/runs.mjs +5 -3
  130. package/src/modules/sdk.mjs +2 -0
  131. package/src/modules/updates.mjs +2 -0
  132. package/src/mother.mjs +2 -0
  133. package/src/ollama.mjs +2 -0
  134. package/src/outbound.mjs +7 -5
  135. package/src/override.mjs +2 -0
  136. package/src/ports.mjs +2 -0
  137. package/src/prices.mjs +2 -0
  138. package/src/privacy.mjs +2 -0
  139. package/src/quota-monitor.mjs +2 -0
  140. package/src/quota-sources.mjs +2 -0
  141. package/src/request-guard.mjs +2 -0
  142. package/src/review-ask.mjs +2 -0
  143. package/src/room/archivist.mjs +2 -0
  144. package/src/room/attachments.mjs +2 -0
  145. package/src/room/budget.mjs +2 -0
  146. package/src/room/context.mjs +2 -0
  147. package/src/room/control.mjs +7 -1
  148. package/src/room/copilot.mjs +76 -0
  149. package/src/room/economy.mjs +2 -0
  150. package/src/room/escalation.mjs +2 -0
  151. package/src/room/ghost.mjs +2 -0
  152. package/src/room/guard.mjs +2 -0
  153. package/src/room/prompt.mjs +13 -4
  154. package/src/room/returns.mjs +82 -0
  155. package/src/room/runs.mjs +4 -0
  156. package/src/room/vectors.mjs +2 -0
  157. package/src/room.mjs +209 -31
  158. package/src/router.mjs +2 -0
  159. package/src/runs.mjs +2 -0
  160. package/src/runtime-detection.mjs +2 -0
  161. package/src/salas.mjs +2 -0
  162. package/src/sentinel-errors.mjs +2 -0
  163. package/src/server-sentinel.mjs +2 -0
  164. package/src/server.mjs +141 -34
  165. package/src/setup.mjs +2 -0
  166. package/src/smtp.mjs +2 -0
  167. package/src/tour.mjs +2 -0
  168. package/src/updates.mjs +2 -0
  169. package/src/usage-sentinel.mjs +2 -0
  170. package/src/vault.mjs +2 -0
  171. package/src/verdict.mjs +3 -1
  172. package/src/whats-new.mjs +2 -0
@@ -0,0 +1,103 @@
1
+ # MADRE under the hood
2
+
3
+ What the README does not need to tell you to use the room, but anyone who wants to understand it, run it under unusual conditions or write a module does. Every claim here corresponds to code in `src/` and has a test in `test/`.
4
+
5
+ ## The ledger
6
+
7
+ Each project has a stable room under `PULSE_HOME` (by default `~/.pulse/rooms/<sala>/`). Its source of truth is `events.jsonl`: one event per line, increasing sequence, append-only for the room. MADRE rebuilds the conversation window from there even if it restarts or is opened from another IDE.
8
+
9
+ Writes are serialized across local processes with an on-disk lock, so two IDEs on the same room never produce repeated sequences. The only operation that rewrites the ledger is the privacy purge, under the same lock, atomic (temporary file and rename), preserving sequences.
10
+
11
+ When the replying agent changes, the room records `handoff.created` with origin, destination and the range of sequences handed over. The transcript remains the durable source; the project is not touched.
12
+
13
+ An agent's errors are stored, bounded, in `message.failed`: one line of up to 500 characters, without stack traces, and with private terms replaced.
14
+
15
+ ## The stream
16
+
17
+ `/api/events` is fed from the ledger, not from the process's memory: events that another MADRE process adds to the same room reach the open pages. Polling reads only the new bytes every 500 ms (`PULSE_BROADCAST_INTERVAL_MS`); a file that shrinks, after a purge, resets the offset. Each frame carries `id: <secuencia>`, so a client that reconnects asks from where it left off. A client that stops consuming is disconnected once it accumulates 1 MiB undrained (`PULSE_SSE_MAX_BUFFERED_BYTES`). GHOST events have no sequence: they reach the open pages and never the ledger.
18
+
19
+ The context window an agent receives is 16,000 characters (`PULSE_CONTEXT_MAX_CHARS`); older messages are omitted before recent ones. A message of more than 20,000 characters (`PULSE_MAX_MESSAGE_CHARS`) is recorded and rejected without invoking the agent.
20
+
21
+ ## The memory
22
+
23
+ `memory.sqlite` lives next to the ledger and is derived from it: if it is missing or its schema changed, it is rebuilt from `events.jsonl`. It contains:
24
+
25
+ - `entries` with trigram FTS5: every message, failure and command card outside GHOST, with its sequence. MADRE's canned replies (`synthetic`) are not included.
26
+ - `memories` with FTS5: the distilled notes, typed (`decision`, `fact`, `preference`, `question`), with the sequences that support them, who wrote them and their origin (`distilled` or `noted`).
27
+ - `entry_vectors` and `memory_vectors`: 768-dimension embeddings, computed in the background and never on a turn's critical path.
28
+
29
+ **Conversations.** A project has one memory and many conversations. The archive, the crew, the modules and the privacy list belong to the project; a conversation is only the record of one line of work. The first one is the `events.jsonl` that was always there —no file is moved to add this—, the others live in `<sala>/chats/<id>/events.jsonl`, and `<sala>/chats.json` keeps their names and which one is open. Numbering belongs to the project, not to the conversation: opening one starts from the highest sequence any other one reached, so `#1411` means an exchange of this project and the memory index, the citations and NOSTROMO still hold. There are gaps in a ledger and that is fine: sequences are an order, not a count.
30
+
31
+ Only one conversation at a time drives the crew —two threads editing the same working tree is not a feature, it is a way to lose work—, so opening another one is refused while a turn is running. And one room per project: `<sala>/open.json` holds the pid and port of the server that has it, and another start on the same project is refused with the address of the open room. Without that, two servers writing different conversations of the same project would hand out the same sequence twice and the archive would silently keep only one of them.
32
+
33
+ **Recall.** When the transcript exceeds the window, each turn also receives, within the same budget (`PULSE_RECALL_SHARE`, 30% by default), the earlier notes and exchanges that match the request. The lexical search weights each term by its rarity in the room: a path or a name weighs more than a common word. With vectors, it is fused with cosine similarity.
34
+
35
+ **Cascade activation.** Each memory that enters a turn leaves a row with the batch it shared, so the room knows which notes arrive together. From that comes an association —Jaccard over the turns where each one was found by the search itself— and recall keeps two slots for it: when it brings a note, it also brings the one that accompanies it, even if they do not share a single word. Only the turns where the search found them on their own merit vote, never the ones the cascade created, or the network would close in on itself within a few days. The strength is a ratio: a pair that stops co-occurring fades on its own. Threshold 0.34, at least two co-occurrences, and the search never loses a slot to the association. `PULSE_RECALL_CASCADE=0` or the switch in MU/TH/UR turn it off.
36
+
37
+ **Cold zones.** A memory is cold when three things hold at once: no turn has ever carried it, it shares no topic with any other —so it cannot be reached sideways either— and the archive has been opened at least twelve times since it was written. The third is the one that matters: never-recalled is what every note is on the day it is born; cold is the opportunity that passed it by. Opportunities are counted in turns that actually went into the archive, and only from the day the room started keeping track. NOSTROMO counts them in its header and surrounds them with a faint ring when asked to.
38
+
39
+ **What to ask.** The room writes the questions whose answer it is missing, always with the words it already has and never inventing a topic nobody raised. Three wells: the questions the archivist recorded as open and nobody answered, the cold memories —asking is the honest alternative to throwing away something that never had its chance— and the kind of note the archive is short on (decisions, preferences, facts; not questions, because an archive short on questions is not fixed by asking for more). They are taken in turns so that a full well is not the whole list, and two ways of asking the same thing count as one. Nothing is sent: the question goes to the composer and the human decides who answers.
40
+
41
+ **The verdict.** `GET /api/maturity` gathers the six readings, the three tests, the cold zones and the pending questions, and returns a sentence and an instruction. The order is not decided by the score: first what is false (open contradictions), then what the archive cannot answer —and there it points to the questions the room already wrote—, then the weakest reading quoting its own advice, and finally the test nobody has run. Consistency is computed on read; coverage refreshes itself once a day, in the background and only with local embeddings.
42
+
43
+ **The three tests.** The maturity reading tells what the archive is made of; it does not say whether it works. A test says that, and a test is only worth something if it can fail. `COVERAGE` takes real questions from the history, runs recall at the exact point where each one was asked and compares it with the answer that was actually given. `CONSISTENCY` looks at the contradictions EYECAT still holds, what was taken out of circulation and whether aberrations are being archived more often lately or less. `MATCH` asks the local model again questions that a frontier CLI answered and compares. None of them spends a provider turn; the third runs in the background and can be stopped.
44
+
45
+ All three are measured **against a control**: inside a room everything talks about the same topics, so to an embedder any pair of texts seems close —the first COVERAGE run scored thirty out of thirty—. To count, what the archive delivered has to beat what it would have delivered for another question, by a margin. Each result says how many cases it had, what it measured with (meaning or words), the bar and the mean against the control.
46
+
47
+ **Distillation.** Every `PULSE_DISTILL_EVERY` undistilled exchanges, or after `PULSE_DISTILL_IDLE_MS` idle, the archivist reads a batch bounded by `PULSE_DISTILL_MAX_CHARS`, from most recent backward, and writes up to five notes. The archivist is the cheapest allowed one in the order Ollama, Gemini, OpenCode, Codex, Claude; the one that fails sits on the bench for thirty minutes and the next one steps in. A single call per batch, never during a turn. For local models, strict JSON is requested.
48
+
49
+ **Embeddings.** `PULSE_EMBED_PROVIDER=auto` uses Ollama if it is running with an embeddings model (`nomic-embed-text`), otherwise the Gemini key (`gemini-embedding-001`, the same key the Gemini CLI uses, including the one in the macOS keychain). Batches of up to 100 texts per call. `PULSE_EMBED=0` leaves recall lexical.
50
+
51
+ **MCP tools.** Each turn attaches to the CLI the `pulse-memory` server with per-run isolated configuration: `memory_search`, `memory_recall`, `memory_notes`, `memory_timeline`, `project_state` and `memory_note`. `memory_note` is signed with the agent and the turn's message, is rejected in GHOST and its notes are marked `noted`.
52
+
53
+ **NOSTROMO and CODE000.** The server requires the project's designation on `GET /api/memory` and `DELETE /api/memory/:id`. Eight taps on the heart within thirty seconds seal the archive for ten minutes (both routes return 423), eject the console and fire a message encrypted with AES-256-GCM under the room's seal (`<proyecto>/.pulse/mother.env`) that all online agents receive decoded as requester `mother`. If the seal changes or disappears, the room detects it and warns.
54
+
55
+ **Privacy.** The terms in `config.json` are replaced at four points: the agent's reply before recording it, the index on insert, the notes when saving them and the dataset when exporting it. The purge rewrites ledger, index and notes preserving sequences and the distilled mark. The server rereads the terms before each human message, because `config.json` is shared by all the rooms on the machine.
56
+
57
+ ## The limits sentinel
58
+
59
+ Each sphere in the bar carries a ring. It shows the provider's real limit when the CLI publishes it, otherwise the local window.
60
+
61
+ - **Codex** writes in each session rollout (`~/.codex/sessions`) its account windows, 5-hour and weekly, with percentage used and reset time. MADRE reads the most recent one; there is no network involved.
62
+ - **Claude Code** publishes `/usage` on Anthropic's OAuth endpoint. With `PULSE_CLAUDE_USAGE=1`, MADRE queries it with the token Claude Code stores in the keychain or in `~/.claude/.credentials.json`; the token only travels to `api.anthropic.com`, as the CLI itself does. It is optional because it involves reading a credential. `PULSE_OFFICIAL_QUOTA=0` disables all provider reads.
63
+ - **Gemini and OpenCode** do not publish anything locally: their ring is the local window.
64
+
65
+ The local window is a soft budget per agent (500,000 tokens) over a rolling 5-hour window; turns drop out of the count as they age, cache reads weigh one tenth and `@madre`'s tokens weigh zero. It warns at 80, 90 and 100% and suggests other agents. A window whose reset time has already passed counts as empty; the monitor rereads the sources every minute and announces `limit.cleared` when a full window goes back to normal.
66
+
67
+ A quota reader implements `{ id, agent, read() }` and `read()` returns `null` or `{ usedPercent, resetAt, windows?, stale? }`. MADRE never infers the provider's quota from local tokens.
68
+
69
+ ## The adapters
70
+
71
+ Each agent runs as a process in its own group, with an isolated home that receives only its existing credentials. If it does not respond before the timeout (180 s by default), MADRE terminates the whole tree: SIGTERM and, after a grace period, SIGKILL.
72
+
73
+ - **Codex**: read-only query; `-C <carpeta> --sandbox workspace-write` in CREATE; in CONTROL, a write sandbox over the project. It generates images with `image_generation` using its ChatGPT account.
74
+ - **Claude Code**: local read tools, non-persistent sessions, MCP limited to MADRE's servers. In CREATE, `--allowedTools Write(//<carpeta>/**),Edit(//<carpeta>/**)` under `dontAsk`: the double slash is the absolute form; with a single one, Claude reads the path as relative to the project and denies every write. In CONTROL, writing allowed in the project and denied in the forbidden zones.
75
+ - **Gemini CLI**: Plan Mode and an ephemeral read-only policy, extended in CREATE with `allow` rules for `write_file` and `edit` whose `file_path` starts with the folder. It runs with a temporary `GEMINI_CLI_HOME`: OAuth tokens and `~/.gemini/.env` yes; hooks, extensions, MCP servers and memory from the real `~/.gemini` no. Gemini reads `@algo` as a file to include, so MADRE escapes each mention as `\@nombre` and unescapes it in the reply. Under 503 or 429, the CLI retries with backoff for minutes and only writes to stderr: MADRE reads it live, cuts off after `PULSE_GEMINI_IDLE_MS`, retries once with `PULSE_GEMINI_FALLBACK_MODEL` and, if that fails too, says so with the name and the model tried.
76
+ - **OpenCode**: ephemeral permissions injected per run, without touching the global configuration; per-pattern `permission.edit` in CREATE and CONTROL. If your configuration does not set a model, `run` picks the default provider, which may not be the one with a session: `PULSE_OPENCODE_MODEL=proveedor/modelo` sets it.
77
+ - **@madre**: it is not a CLI. It is a local adapter on top of Ollama that receives the recent transcript, what the memory recalls about the question and the question; never the CLIs' briefing. With an 8,192-token window, because the default 4,096 one truncates the system prompt. What it can resolve without a model, it resolves: identity, orders that are not its to take, requests to save memory and the round table, which is a plan written by the room with one step per online CLI and its wrap-up turn.
78
+
79
+ The image scopes of Claude, Gemini and OpenCode are fulfilled with **Image Studio**: the MCP server `src/mcp/image-server.mjs`, attached only inside a lease with the scope turned on, which generates with the Gemini images API and saves the file in the turn's folder.
80
+
81
+ ## CREATE under the hood
82
+
83
+ A turn in `#2` takes the same snapshot as CONTROL, without a seat: several `#2` turns can run at once. When it ends, `diff` against the snapshot: added files are kept and recorded as `artifacts.created` with their path in the project; modified, renamed or deleted ones are restored from the snapshot and announced in `create.reverted`. Forbidden zones are restored the same way as in CONTROL. Each CLI receives its write tools over the project: Claude Code denies `Write` if `Edit` is not allowed on the same path and OpenCode leaves no write tool if `edit` is denied (both verified with the real CLI), so in `#2` they go together and the "add only" guarantee is the restore afterward, not the rule beforehand. Gemini receives only `write_file`. The `scratchDir` under `.pulse/out/` still exists for what has no place and for Image Studio.
84
+
85
+ In a plan, each step's mode is the minimum of what the orchestrator asked for (`@agente #n:`; without a number, `#1`, or `#2` if there is a lease), the plan's ceiling (the mode of the human message) and the agent's `MAX MODE`. `#4` never reaches a delegate through the ceiling: only with that agent's key. Under a `#3` ceiling, a `#2` step receives a project lease issued in the orchestrator's name and a `#3` step takes CONTROL with its own checkpoint, one at a time. Under a `#1` ceiling, a `#2` step goes through escalation to the human. A `#3` or `#4` step that exceeds the ceiling asks the human for the key for that agent; granting it for the plan does not raise the others' ceiling.
86
+
87
+ ## CONTROL under the hood
88
+
89
+ Before the turn, MADRE snapshots the project as a real commit under `refs/madre/checkpoints/` with a temporary index (in a project without git, in a shadow repository under the system's temporary directory, with the project as the working tree): it includes untracked files, respects `.gitignore`, does not touch your branch, your index or your stash, and works in repositories with no commits. While the turn lasts, `.env*`, `.pulse/`, `.madre/` and `.claude/settings.local.json` are read-only at the file-system level and get their permissions back when it ends. Afterwards, `git diff` against the checkpoint gives the list of changes; any write into a forbidden zone that got through is reverted from the checkpoint and named. `UNDO` restores the full checkpoint.
90
+
91
+ ## Commands that come back and the copilot
92
+
93
+ A ```pulse-run stores the mode of the turn that asked for it. When every line that can run has an answer —it finished, or it opened a port and is serving—, `src/room/returns.mjs` builds what the agent reads: why it asked, what it was answering, the end of what it had said and each line's output (head and tail, about 10,000 characters across all of them), and the room opens a human turn marked `auto: 'runs'` with that block, at the mode of the original turn and never above `#3` (`#2` if a line was pressed from the phone). If the agent is still answering or a plan is running, it waits until the room is free; `STOP ALL` holds it until the human hands it back from its card. A request is handed back once. In the shared window, a command's output weighs at most ~1,200 characters: five long outputs no longer push the human's request out.
94
+
95
+ The copilot is a server window (`/api/copilot`), in memory like the passes: the `#3` key opens it for a time and `STOP ALL` or a restart close it. Each conversation checks it when accepting a message: one in `#3` marked `copilot` does not spend a pass and reaches any agent whose CLI writes. Its turn carries the `copilot` block (`src/room/copilot.mjs`); when it settles, what it deleted is restored from the restore point (`deletesReverted`). Its command requests run on their own when the turn releases the project, only the lines on the safe list, and the hand-back still belongs to the copilot while the window lasts. Eight solo rounds in a row and it stops with an alert.
96
+
97
+ ## Operational recovery
98
+
99
+ If MADRE stops in the middle of a turn, on startup it detects the `agent.started` events with no close and records a recovered `message.failed` for each one. When closing with Ctrl+C or `SIGTERM`, it interrupts the agent processes in progress, records those turns as failed, delivers the pending events to the open pages and exits. Plans run in sequence and delegates do not delegate. The orchestrator reviews the replies and can open another stretch, up to three per request; `STOPALL` cuts off anything in progress.
100
+
101
+ ## Packaging and tests
102
+
103
+ `npm test` runs the suite with `PULSE_OLLAMA=0` so as not to touch a real Ollama; no test calls a model. `npm run pack:check` packs, installs into an empty directory and runs the installed CLI: `--help`, `doctor` and a server start that serves the room and closes cleanly with `SIGTERM`. `PULSE_TEST_MODE=1` enables `/api/test/limits` to simulate quota windows.
@@ -0,0 +1,339 @@
1
+ # MADRE · REFERENCE
2
+
3
+ Everything MADRE does, with the exact numbers. To get started in five minutes, see the [README](../../README.en.md).
4
+
5
+ - [Getting started](#getting-started--the-first-five-minutes) · [The project](#the-project) · [Language](#language)
6
+ - [Permission modes](#permission-modes) · [What each agent can do](#what-each-agent-can-do) · [Plans](#plans)
7
+ - [Memory](#memory) · [Your model](#your-model) · [What is sent](#what-is-sent) · [Diagnostics](#diagnostics) · [Modules](#modules)
8
+ - [What leaves the machine](#what-leaves-the-machine) · [Config and variables](#reference)
9
+
10
+ ---
11
+
12
+ ## GETTING STARTED · THE FIRST FIVE MINUTES
13
+
14
+ You need Node 22.5 or later and at least one of these CLIs with a signed-in session: **Codex**, **Claude Code**, **Gemini CLI**, **OpenCode**. If **Ollama** is also running with a chat model, the project gets a fifth, local agent.
15
+
16
+ 1. Run `npx @jossuealcala/madre` from any folder: it opens Home, with all your projects and the Coordinator at the top. The first time, a three-step assistant walks you through it: connect the agents (each with its own button to install it and sign in, right there; once for all projects), add the projects (you choose folders inside your user folder; adding does not open them) and open the ones you are going to use. `npx @jossuealcala/madre start` inside a folder still opens that project directly; if there are no agents, the project opens anyway on Connect your agents so you can install them and sign in.
17
+ 2. The project opens at `http://127.0.0.1:4317`. Pick an agent in the selector or type `@claude …`. The chip next to `to @agente` says which mode the message goes out in; `#1 CHAT ONLY`, read-only, is the default.
18
+ 3. To add or reconnect an AI later: Settings → Agents (the settings button in the bar, or ⌘, / Ctrl+,), where the agents live alongside the rest of the settings. Codex and Claude Code sign in with one click; Gemini and OpenCode accept their key right there. MADRE does not store provider credentials: each key goes to its own CLI's file.
19
+ 4. With Ollama, the Local AI module (Modules, in the bar) is already on: memory is embedded locally and `@madre` appears in the row.
20
+ 5. Settings → Memory decides who distills the memory and how often. The Memory map, from the Diagnostics header, shows what the project remembers.
21
+
22
+ ```bash
23
+ npx @jossuealcala/madre doctor # which agents exist, who is signed in, whether there is a new version
24
+ npx @jossuealcala/madre setup # the same setup, from the terminal, if you prefer it
25
+ npx @jossuealcala/madre start --no-open --project RUTA
26
+ ```
27
+
28
+ **Three names.** **MADRE** is the product. **Diagnostics** is its operational voice: failures, connections, settings. **Log** is the channel the project runs on: the event record, the plan block, the `.pulse/` folder where artifacts land; those identifiers keep their old name, PULSE.
29
+
30
+ ---
31
+
32
+ ## THE PROJECT
33
+
34
+ **Connect your agents.** With no agents online, the project opens on Connect your agents: one card per agent with its real status and the one action that applies to it, `INSTALL` or `SIGN IN`. Everything runs on your machine, with the command in view, and the output streams to the same screen. Codex and Claude Code sign in with one click because their CLI opens the browser; Gemini and OpenCode accept their key right there, which MADRE writes where that CLI looks for it, with the file locked to your user and without keeping a copy anywhere, only from this computer. Each card also says which account that agent signs in with and whether there is a free entry, so choosing is not a blind guess. That screen folds away as soon as an agent is ready and does not come back: it is the first contact of a project with no one inside. From then on the agents live in `⚙ CONNECTIONS`, with the same buttons and, alongside, each agent's modes, permissions and keys.
35
+
36
+ **The bar.** The brand with its heartbeat, the project root, the agents, `LIVE`, the alerts (`STOP ALL`, new version), `MODULES`, `Diagnostics`, theme and files panel. Each agent sphere carries its usage, what it has consumed: the provider's real limit when the CLI publishes it, otherwise MADRE's local window. One click expands it.
37
+
38
+ **The bubbles.** Each reply says who is speaking, to whom, in which mode and with which model; below, the time, the turn's tokens and the running total. Full Markdown, tables, code blocks with COPY. Paths an agent mentions (`src/room.mjs:42`) open the viewer. On hover: rate it good or bad, copy, reply with another agent.
39
+
40
+ **The Write box.**
41
+
42
+ | You type | What happens |
43
+ |---|---|
44
+ | `@codex`, `@claude`, `@gemini`, `@opencode`, `@madre` | Mentions an agent; `@` opens the list |
45
+ | `!src/room.mjs:12-20` | Attaches a project file, with lines if you give them; `!` searches the files |
46
+ | `#0` to `#4` | Sets that message's permission mode. `#3` and `#4` open the unlock, just like the chip: a mode that asks for two keys with the mouse does not come free by typing it |
47
+ | `/create …`, `/image …`, `/stopall`, `/git …`, `/ahp …` | Commands; `/` opens the menu. `/git push` shows what would go out; only `/git push confirm` sends it |
48
+ | `STOPALL` | Master brake |
49
+ | Clip, drag or paste an image | Attachment for the project, never inside its folder |
50
+ | `@madre, pregúntale a los agentes …` | Ask everyone: one step per online agent, with a cited wrap-up |
51
+
52
+ A second click on the chosen sphere, or the `default model ▾` chip, picks the model for that request: Codex, Claude, Gemini and OpenCode with their real lists, or a free-form name. It is remembered per agent.
53
+
54
+ **Files.** The icon on the right opens the project tree in read-only mode. The viewer numbers lines; click and Shift+click select a range and `REVIEW WITH` sends it to an agent. With **Preview** turned on in `MODULES`, HTML, SVG and Markdown are rendered in a sealed frame instead of showing their code, with a back/reload bar and automatic reload when an agent changes the file.
55
+
56
+ **Theme.** Sun/moon in the bar: automatic, light or dark. The light theme does not glare; the Diagnostics screen stays phosphor.
57
+
58
+ **Language.** The project speaks **Spanish** by default. The `EN` button in the bar switches it to English and the browser remembers it; `PULSE_LANGUAGE=en` overrides the config on the next start. A language is only how things read: what was written in the ledger keeps the words it was written with, and when shown it is said again in the project's language.
59
+
60
+ The **terminal stays in English on purpose**: `madre doctor` and the startup print what people paste into an issue or search for in a search engine, and in English it can be found. What a CLI prints on its own is never touched either.
61
+
62
+ ---
63
+
64
+ ## PERMISSION MODES
65
+
66
+ Every message goes out with a mode. Your mode is the ceiling of any plan that message starts.
67
+
68
+ | Mode | Name | What it allows |
69
+ |---|---|---|
70
+ | `#0` | **INCOGNITO** | Off the record. Nothing is written to the ledger, no one remembers it, it disappears on reload. Tokens do count. |
71
+ | `#1` | **CHAT ONLY** | Read the project and coordinate. The default. |
72
+ | `#2` | **CREATE** | Add new files and folders where they belong in the project. What already existed does not change: if an agent touches it, MADRE restores it when the turn ends and says so. |
73
+ | `#3` | **EDIT** | Edit the real project without per-action approval. One holder per project, a restore point before, a list of changes and `UNDO` after. |
74
+ | `#4` | **FULL ACCESS** | Everything in EDIT plus running commands: tests, builds, `git push`, deploys with the CLIs and sessions already on the machine. Files come back with `UNDO`; what leaves the ship does not. The unlock asks for the same key twice: the project name (or your phrase), typed twice. |
75
+
76
+ **CREATE under the hood.** The agent decides where new things go according to the project's conventions, and creates folders if needed; `.pulse/out/<turno>/` remains as a scratch area for what has no place. MADRE takes a restore point before the turn and, when it ends, keeps what appeared, shows it under the reply as artifacts, and restores any pre-existing file that was modified, renamed or deleted, with a notice in the project. The CLIs receive their write tools over the project and the instruction not to touch what exists; the guarantee comes from MADRE's restore at the end, not from the rule beforehand.
77
+
78
+ **EDIT under the hood.** Before the turn, a real commit under `refs/madre/checkpoints/` that does not touch your branch, your index or your stash. During the turn, `.git/`, `.pulse/`, `.madre/`, the `.env` files and `.claude/settings.local.json` are read-only at the file-system level and get their permissions back when it ends. Afterwards, the list of added, modified and deleted files, and `UNDO` restores the restore point. Unlocking `#3` asks for the project name; unlocking `#4` asks for it twice. In `#4` each CLI receives its command tool (Codex without a network sandbox, Claude `Bash`, Gemini `run_shell_command`, OpenCode `bash`) and the instruction to say in one line what is going to go out and where before it does.
79
+
80
+ **Permission request.** If a plan in `#1` reaches a step that wants to create something, the project stops and asks: `GRANT ONCE · GRANT FOR PLAN · DENY`, with a three-minute timer. Only the human grants; a permission written by an agent inside the conversation does not count. A step that asks for `#3` or `#4` also stops: it is unlocked with the key for that mode and that agent. Granting it for the plan does not unlock the other agents.
81
+
82
+ **A permission with a time limit.** An agent that needs more asks for it in one line with the mode and for how long ("I need #3 for 15 min: …"). Its reply carries a card with the mode, the time it asked for and the options available (#3: 5, 15 or 30 min; #4: 5 min) or just that message; the key opens that window for that agent.
83
+
84
+ **Copilot.** The robot next to mode · model · effort. It is turned on with the `#3` key, once, for 30 min, 1, 4, 8 or 24 h; `STOP ALL`, turning it off or a restart end it. While it lasts, a message in `#3` does not ask for the key and goes to the agent you are writing to, even if its Max mode is `#2`, as long as its CLI can write. That agent edits the project, builds plans and gives each step up to `#3`, and the commands it asks for that are safe —reading (`ls`, `cat`, `rg`…), tests and builds (`npm test`, `npm run build`, `node --test`, `pytest`, `go test`…), local git (`status`, `diff`, `log`, `add`, `commit`)— run on their own and their result goes back to it; any other line waits for your button. What it deletes comes back when the turn ends, it never touches `.git/`, `.pulse/`, `.madre/` or the `.env` files, and `#4` still asks for its own key. After eight rounds of commands without you writing, it stops and lets you know.
85
+
86
+ **Mode per step.** An orchestrator can ask for each step's mode: `@codex #2: crea la página`, `@claude #3: arregla el router`. Without a number, the step only reads, or creates if the plan can already create: `#3` is asked for by name. MADRE respects each agent's `MAX MODE`. With your message in `#3`, the orchestrator's word is enough for a `#3` step; with your message in `#1`, a `#2` step goes through the permission request and `#3` or `#4` asks for your key. A `#4` step always asks for that agent's key, even if your message is in `#4`.
87
+
88
+ **Two controls per agent.** The Max mode, in Settings → Permissions, says how far a message addressed to each agent can go; the Starting mode, in Settings → Agents, says where it starts: `#1` read-only until you arm CREATE, or `#2` so that every turn can add files without asking. Separately, two abilities: generating images and web.
89
+
90
+ **Commands an agent asks for.** With the **Commands** module on, an agent in `#1`, `#2` or `#3` that needs a command it cannot run (the tests, a build, a linter) ends its reply with a `pulse-run` block: the reason on the first line and one command per line, each with `$`. MADRE shows each line as a button and runs nothing until you press it. Each line runs on its own, from the project root and **without a shell**: what you read on the button is exactly what runs, so lines with `|`, `&&`, `;`, redirections, `$VARIABLES`, wildcards, `~` or `cd` are shown with the reason and cannot be run. Before running, MADRE takes a restore point; the output stays in the project as a collapsed card and, once all the lines that can run have run, **it goes back to the agent that asked for them** in a turn of its own, with the mode it had (up to `#3`; from the phone, up to `#2`), what it was answering and each line's output. If that agent is still answering, it waits; `STOP ALL` holds it. **Run all** runs the lines one after another and **Hand back what ran** delivers what there is without the rest. If the command changed files, `UNDO` brings them back. Whatever the command sent off the machine does not come back. One command at a time, ten minutes at most, and `STOP` on its card or `STOP ALL` stop it. A command that opens a port is a server: it has no time limit, its card says where it listens and opens it in YOUR SERVERS, and while it serves you can run another command. Agents know that a server for the project listens only on `127.0.0.1`. In `#4` the agent runs its own commands and is not shown the block.
91
+
92
+ ---
93
+
94
+ ## WHAT EACH AGENT CAN DO
95
+
96
+ | | Reads the project | Receives images | Creates files, scoped | Generates images | Web |
97
+ |---|---|---|---|---|---|
98
+ | **Codex** | yes | `-i` | write sandbox | yes, native, with its ChatGPT account | `web_search` |
99
+ | **Claude Code** | yes | reads the path | per-path permission rules | yes, with **Images** | WebFetch / WebSearch |
100
+ | **Gemini CLI** | yes | `read_file` | per-pattern policy | yes, with **Images** | `google_web_search` |
101
+ | **OpenCode** | yes | `-f` | per-pattern `edit` permissions | yes, with **Images** | webfetch / websearch |
102
+ | **@madre** | the memory | no | no | no | no |
103
+
104
+ **Images** is a MADRE module: its own MCP server that exposes `generate_image` on top of the Gemini API's image models, with your own key and your credits. Today **only Gemini**, and for a reason: it is the only agent account whose key MADRE already finds without asking you for a new one, and it has a free tier. Anthropic does not generate images —Claude reads them, it does not make them—, the ChatGPT account Codex signs in with does not give access to the images API, and OpenCode depends on the provider you point it at. It is connected to Claude, Gemini and OpenCode only inside a CREATE permission with the image scope turned on, in their isolated homes, and the image lands in the turn's folder like any artifact. `/image <petición>` sets up the permission and routes to the agent that can generate. With all four agents you can ask for an image; Codex makes it with its own tools, the others with Images.
105
+
106
+ Web access is a permanent per-agent permission, off by default, turned on in Settings → Agents, with Web access.
107
+
108
+ ---
109
+
110
+ ## PLANS
111
+
112
+ An agent can put the others to work. If you ask it to coordinate, it ends its reply with a `pulse` block, one step per line:
113
+
114
+ ```
115
+ @gemini: Sintetiza en un párrafo quién es el autor, separando hechos de inferencias.
116
+ @codex: Misma pregunta; señala la afirmación menos sustentada.
117
+ @claude: Compara ambas síntesis y marca dónde divergen.
118
+ ```
119
+
120
+ MADRE runs the steps as normal turns: each one stays in the ledger and goes through handoff, budget and timeout. After the replies, the orchestrator gets a wrap-up turn even if it did not write it as a step. It can propose the next stretch if there is still work within the permissions granted; MADRE allows up to three stretches per request. Delegates do not open plans of their own. Each stretch has at most four steps plus the wrap-up.
121
+
122
+ **TURNS.** In Diagnostics, next to the sentinel. On by default: a conversation that is still working when you open another one does not stop, it keeps writing its record and the conversations panel marks it until it finishes. Two limits: conversations working at the same time (2) and turns at the same time in each one (3); a message that would exceed them is rejected with the reason before it starts. All conversations share a single holder of EDIT or FULL ACCESS. When it is off, a single conversation drives the agents and you cannot switch away from one that is working. `STOP ALL` stops them all.
123
+
124
+ **STOP ALL.** The button in the bar, `STOPALL` in the Write box or `curl -X POST http://127.0.0.1:4317/api/stop-all` stop all plans and kill all agent processes. Diagnostics warns in red when the project gets out of hand: three agents at once, one agent with two overlapping turns, a plan longer than five minutes.
125
+
126
+ ---
127
+
128
+ ## MEMORY
129
+
130
+ Everything said outside INCOGNITO is indexed alongside the ledger, in `~/.pulse/rooms/<sala>/memory.sqlite`. None of this needs a command: it happens on its own.
131
+
132
+ **Recall.** When the conversation exceeds the context window, each turn receives the earlier exchanges that match the request, quoted with their sequence number, for any agent.
133
+
134
+ **Distilled notes.** Every ten exchanges or after ten minutes idle, the archivist reads what has not been distilled and saves up to five typed notes: decision, fact, preference, open question. The archivist is the cheapest allowed agent; with Ollama it is the local model and costs nothing.
135
+
136
+ **By meaning.** With Ollama (`nomic-embed-text`) or with a Gemini key, exchanges and notes are embedded in the background; a question in Spanish finds a decision written in English.
137
+
138
+ **Tools.** Each turn has the `pulse-memory` MCP server attached: `memory_search`, `memory_recall`, `memory_notes`, `memory_timeline`, `project_state` and `memory_note`, which saves a note when you explicitly ask to remember something. The bubble shows `◉ memory saved`.
139
+
140
+ **Memory map.** The memory as a map, behind the project name: MADRE is a beating red sun, each memory a planet in the color of its type, joined by pulsing veins. You can navigate it and read it, and the only thing you can do to it is delete, with double confirmation. Eight taps on the heart activate the Temporary lock and seal the archive for ten minutes.
141
+
142
+ **@madre.** With Ollama and a chat model, the memory speaks: `@madre` answers from the whole archive with `[#n]` citations, says when the project never discussed something, does not write or run anything, and summons the agents if you ask it to. Its tokens are local and do not count. When there is a model trained on the project, it uses it.
143
+
144
+ **Settings.** Settings → Memory: who distills, who may, how often, where embedding happens, how much context recall can take up. All in `~/.pulse/config.json`, without restarting.
145
+
146
+ **Privacy.** A CLI runs with its own private context and can write it into a reply. In Settings → Privacy you name the terms that must not travel through the project: MADRE replaces them with `[ENTIDAD-ORG]` before they reach the ledger, the archivist, the other agents or the dataset, and Erase private data cleans what the project already had. The terms live in `config.json`; the project only records how many there are.
147
+
148
+ ---
149
+
150
+ ## YOUR MODEL
151
+
152
+ The project gathers training material while you work. `MEMORY` shows live how many clean pairs it has toward a LoRA, with 300 as the goal: human→agent turns, plan steps and distilled notes; left out are `@madre`'s replies, canned replies and whatever you mark as a bad reply with each bubble's thumb.
153
+
154
+ `EXPORT DATASET` writes `train.jsonl` and `valid.jsonl` next to the ledger, redacted. The `TRAIN` card brings the commands already filled in with your project folder and the base model that fits on your machine. Training runs outside MADRE, with mlx on Apple Silicon; the recipe lives in [`docs/training/`](training/README.md). As soon as Ollama has a `madre-<proyecto>` model, `@madre` answers with it and the other CLIs are told to ask it first: the project's memory stops costing tokens.
155
+
156
+ **Ollama.** If it runs on the machine, MADRE uses it without any configuration: local smart search, local archivist, `@madre`. The Local AI module, in Modules, shows the server, models and roles, downloads the recommended ones and lets you turn off each role. `qwen2.5:7b` on 16 GB, `qwen2.5:3b` on 8 GB; MADRE prefers general chat models over the `-coder` ones.
157
+
158
+ ---
159
+
160
+ ## WHAT IS SENT
161
+
162
+ Enter the **Memory map** from the Diagnostics header and click the core, the star in the center. Every turn, the project writes a document on your behalf and hands it to a process; until now that document existed only for the instant the process read it. There it is in full: block by block, with what each one weighs and the exact words the agent receives.
163
+
164
+ Change who it goes to and the words change; raise the mode and the permission it would be given appears, written out —without creating a folder or taking a restore point to show it—. Asking what the project would say is not the project saying it: nothing is counted, nothing is saved, nothing goes out. And it is read, never written: what MADRE promises about the agents is true because those words are fixed.
165
+
166
+ **THE LAUNCH.** Below the document, the exact command MADRE would run to deliver it: the executable, the directory, every flag and the place where the briefing goes in. It is not a description — it is built by the same adapters that would build it for real. Below that, what keeps the run inside the turn (the session that does not persist, the temporary home that is deleted when it ends) and the MCP servers it could call, with their tools counted. **No environment value from that command is ever printed, only the names**: a command line is something people take photos of.
167
+
168
+ **Outbound.** The record of what went out: every destination MADRE or an agent called, with its count. Never bodies, headers or query values — only where and how many times.
169
+
170
+ **The console.** Inside the core, Diagnostics answers from what the project already has. Three answers it does not understand and the interface closes.
171
+
172
+ ## DIAGNOSTICS
173
+
174
+ The button in the bar opens the diagnostics screen. Type a symptom, an agent or a word and Diagnostics ranks the conditions recorded in this project against its catalog, with the remedy for your operating system; when the project can apply it, the remedy comes with Apply. The same catalog in the terminal: `madre doctor --catalog [texto]`. Each CLI's session, the modes, the abilities, the timeouts, the memory and privacy are in Settings.
175
+
176
+ | In the header | What it does |
177
+ |---|---|
178
+ | Memory map (brain) | The memory as a map. It is also in the top bar |
179
+ | Settings (gear) | Opens Settings › Version and reports, where the sentinel lives: the failures no condition explains and the process crashes, with paths, users, emails and keys removed. Each report is read before it is sent; auto-reporting comes turned off |
180
+ | Not fixed? | At the foot of each remedy: reports that it did not work, with the condition's code |
181
+ | `?` | The five-stop tour, the same one that opens the first time. If you left the First steps list half done and hid it, it also brings it back |
182
+
183
+ ---
184
+
185
+ ## MODULES
186
+
187
+ `MODULES` in the bar lists the available ones and their status. None of them writes to the project except the Continuity install, which shows the command and asks for confirmation.
188
+
189
+ | Module | What it adds |
190
+ |---|---|
191
+ | **Git** | `/git status`, `/git log [n]`, `/git diff`, `/git branches`: facts about the repository as a card in the thread, which the agents also read. `/git commit "mensaje"` and `/git push confirm`: your hand on the repository, with a preview of what would go out |
192
+ | **Images** | `generate_image` for Claude, Gemini and OpenCode, with your Gemini key, inside CREATE |
193
+ | **Preview** | The viewer renders HTML, SVG and Markdown in a sealed frame, with automatic reload |
194
+ | **Local AI** | Smart search, archivist and `@madre` locally, free and without an account. It is installed, woken up and downloads its model from Connect your agents |
195
+ | **Test browser** | A headless browser in turns that ask to see, test or capture a page. It only reaches this MADRE and the servers you started from COMMANDS: open the Preview or the served app, click, read the console, screenshots to the turn's scratch area. When you turn it on, MADRE checks that the server starts with its browser. Requires `@playwright/mcp` |
196
+ | **GitHub** | `/gh`: open pull requests, your branch's CI and open issues as a card. `/gh pr [n]`, `/gh ci`, `/gh issues`. `/gh pr create "título"`, `/gh comment <n> "texto"` and `/gh issue "título"` first show what would be published and only publish with `confirm`. Agents read in any mode and write only in `#4` FULL ACCESS. It signs in with your `gh` session; without it, with a fine-grained access token stored in MADRE's vault |
197
+ | **Commands** | An agent asks you to run a command its mode does not let it run; each line is a button, runs without a shell from the project root, with a restore point before, and when it finishes the output goes back to the agent that asked for it so it can continue. A command that opens a port is a server: it keeps running until you stop it from its card, and while it serves you can run another one. It costs about 300 tokens of instructions per turn below FULL ACCESS while it is on |
198
+ | **Token saver** | The project's token economy. The switch asks the agents for replies in compact prose; the rest is always on and goes unnoticed: the briefing carries only the blocks the turn can use, what never changes is read first so the cache recognizes it, and the transcript stays still instead of sliding. Nothing you write is altered. In its window, in Modules, you can see where the tokens go |
199
+ | **Suggested effort** | Under the box, how much Claude Code or Codex should think for the message you are writing: go up when the request seems to need more, go down only when it has been seen or measured that it is enough. It learns first from your real use, without spending tokens: it reads in the project's record which level you used for each kind of request and whether it was enough (you moved on to something else) or fell short (failure, bad rating or you asked again within 15 minutes); that reading lives only in memory. The quick and full tests on its card measure faster, with real questions from the project and a blind judgment, which level is enough for each kind of question. The measurements live in `~/.pulse/rooms/<sala>/intents.jsonl`. Nothing changes on its own |
200
+ | **Continuity** | Optional external integration: verified project state, checkpoints and handoffs in `.ahp/`; `/ahp status`, `/ahp check`, `/ahp context` |
201
+
202
+ **Outside tools (MCP)** (formerly "Conectar MCP") lives in each project's **Settings › Outside tools (MCP)**, not in Modules. Add an MCP server by local command or by web address (no session, with a token or signing in with OAuth: MADRE registers as a public client, with no secret, and the callback lands in the project itself), or bring it in from `.mcp.json`, `opencode.json`, Claude Code, Codex, Gemini CLI or Cursor; when importing, only the names are read and the values go to the vault. Before handing it to a turn, MADRE starts it and asks for its tools: if it does not respond, it stays out and its row says why. Tools the server marks as read-only are available from `#1`; the ones that act, from the mode you choose per server (`#4` if you do not lower it). All four CLIs start the same MADRE intermediary (`src/mcp/proxy.mjs`), which reads the secrets from the vault, lets through only the allowed tools and speaks HTTP with remote servers: no secret ends up on the command line or in a project file. The list lives next to the project's record (`~/.pulse/rooms/<sala>/mcp.json`).
203
+
204
+ Each module is one file. Yours go in `~/.pulse/modules/` (all projects) or in `<proyecto>/.madre/modules/` (that project): an `.mjs` with `export default { … }`, no build or registration, with a switch, settings, `/nombre` commands, MCP tools for the agents and its own routes. `RELOAD MODULES` reloads it without restarting. Guide and ready-to-copy example in [`docs/SDK.md`](SDK.md). How to write one, in [CONTRIBUTING.md](../../CONTRIBUTING.md#writing-a-module).
205
+
206
+ ---
207
+
208
+ ## HOME · ALL YOUR PROJECTS
209
+
210
+ **Home** brings together all your projects: the three-circles key at the start of the bar. It shows the projects open on this Mac (who is waiting for you, who is working, their latest conversation and how many memories they keep, by type) and the **asleep** ones: closed projects whose folder is still on disk. The full plan lives in `docs/MACROVERSO.md`.
211
+
212
+ | In Home | What happens |
213
+ |---|---|
214
+ | **Open** | Takes you to that project on its port; with ⌘ it opens alongside |
215
+ | **Close** | Stops what is running in that project and closes it, like `Ctrl+C` in its terminal. It asks first |
216
+ | **Wake** | Opens an asleep project the way `madre start --project <carpeta>` would; what it says on startup stays in `start.log`, next to its record |
217
+ | **Stop all** | Stops all the agents in all the projects |
218
+ | **Remove from MADRE** (⋯ on its card, or right-click) | Takes it out of Home. If it is open, it closes it first, and ends its connections. Its folder on the Mac is not touched, and its memory stays in MADRE: if you add it again, it is there. It asks first |
219
+
220
+ In a project, the key next to the house **switches project**: its indicator says who is waiting for you (a number), who is working (it pulses) and who finished while you were in another one (green). It opens a panel with the other open projects; one click takes you there and ⌘-click opens another tab. It reads this from `GET /api/salas/open`: the open rooms, each with its summary and without the census; this Mac only.
221
+
222
+ **The Project map**, from Home on a screen 900 px wide or more: your projects in open space, and each one is a Memory map drawn by the same engine as its project's (`public/nostromo-engine.js`). Drag the space to move it, scroll to zoom in, **Recenter** to go back home. Click or ← → to fly to one: the chosen project is the only one alive, with its magma and its pulses; drag it to rotate it, tap a memory to read it in the card, Esc to let it go and Esc again to go back. From afar each project is read from its own process without the words of its memories (`GET /api/salas/universe?id=`); only the chosen one asks for them (`&full=1`).
223
+
224
+ **Connections.** A connection is a contract between two projects that you sign in Home (**Connect projects**, or by dragging one project onto another in the Project map): who reads from whom (or both), which types cross over and until when. Only distilled notes that travel to turns cross over (hold and bridge), cleaned by the privacy guard of the project that delivers them; never the record, files, keys, medbay or airlock; and read-only. In the project that can read, each turn carries the `pulse-enlaces` MCP server (`enlace_rooms`, `enlace_search`); without a contract it does not exist. Signing and revoking leave a line in both projects; each read is counted (`enlace.read` in the one that delivers, `enlace.received` in the one that reads) and can be seen in Home and as pulses on the connection in the Project map.
225
+
226
+ **Who read.** Each read belongs to a turn: the tool states its agent and its turn, and the reading project checks that the turn is running there, for that agent and above INCOGNITO; if not, it reads nothing (and does not say whether the connection exists). The read is recorded with its agent and its turn in the project that reads, with the agent in the one that delivers, and under that turn's reply a line says "read 3 notes from gumball". In Home, each connection says who read last.
227
+
228
+ **Always include.** One checkbox per connection, off by default, on the signing sheet and on each connection in Home. When checked, each turn of the reading project receives, without asking for them, up to 3 notes from the other project that match the question (in a block of the prompt, "recalled 3 notes from gumball" under the reply). Each such turn counts as one read against the connection's hourly cap; past the cap, the turn continues without notes. Never in INCOGNITO, never for `@madre`, never in the Coordinator's project. Only you check or uncheck it, from Home; the Coordinator never checks it on the connections it signs.
229
+
230
+ | Route | What | Who |
231
+ |---|---|---|
232
+ | `POST /api/salas/enlaces` · `POST /api/salas/enlaces/revoke` | Sign and revoke. Two projects connect only once: while there is a current connection between them, in either direction, signing another one returns 409 | The Home page |
233
+ | `POST /api/salas/forget` | Remove a project from MADRE: closes it if it is open, revokes its connections and sets its `project.json` aside as `project.forgotten.json`. Never the Coordinator's | The Home page with its `Origin`, never a process |
234
+ | `GET /api/tour` · `POST /api/tour` | The 1.0 tour: whether the bonjour is due, whether the person comes from 0.7.2, chapters read, where they left off, hints seen. Saved in `~/.pulse/tour.json`, one per person, not one per port | The pages on this Mac |
235
+ | `GET /api/looks` · `POST /api/looks` | The appearance that Home and all projects share: theme, accent, background and its two dials, bubbles and text. Saved in `~/.pulse/looks.json`, one per person; each page reads it when it opens and when it becomes visible again, and writes it when it changes. What Home chooses for its cards stays in its browser | The pages on this Mac |
236
+ | `GET /api/tour/projects` · `POST /api/tour/projects` | The 0.7.2 projects that Home cannot list (without `project.json`) and bringing one in: its folder is looked up by name in the usual folders and confirmed by the hash of its id. Projects removed on purpose do not come back | The pages on this Mac |
237
+ | `POST /api/override/arm` | The #3 and #4 key, checked by the project (`src/override.mjs`): what was typed, once or twice, and a pass for that agent and that mode. A message at #3 or #4 goes out only with its pass; without a remembered permission it opens one message, with it, as many as fit in its minutes. STOP ALL and a restart revoke them. Eight wrong keys in one minute return 429. The phrase's fingerprint never goes out through `GET /api/settings` or `/api/state` | The pages on this Mac |
238
+ | `GET /api/copilot` · `POST /api/copilot` · `POST /api/copilot/off` | The copilot: whether it is on and until when; turning it on with the `#3` key (`{ minutes, words }`, 30 to 1440 min) and turning it off. A message with `copilot: true` in `#3` goes without a pass while it lasts; when off it returns 409 with `copilotOff`. Never from a phone | The pages on this Mac |
239
+ | `POST /api/runs/return` | Hand back to the agent what ran from its command request without the rest (`{ responseMessageId }`). When all its lines run, it is handed back on its own | The project's pages |
240
+ | `GET/POST /api/x/mcp/servers` · `POST /api/x/mcp/servers/<id>/check · toggle · actions · remove · signin` · `GET/POST /api/x/mcp/import` · `GET /api/x/mcp/oauth/callback` | Outside tools (MCP): the list without values, add and check, turn on, from which mode it acts, remove (with its secrets), sign in with OAuth and its callback, and what can be brought in from other apps | The pages on this Mac; the OAuth callback, the browser |
241
+ | `GET /api/enlace/memories` | What this project delivers under a contract: only `travels()` and the contract's types, redacted; 404 if the contract does not serve whoever asks, 423 sealed, 429 over the cap | Another MADRE process with the channel key (`~/.pulse/credentials/enlaces.json`), without `Origin` |
242
+ | `POST /api/enlace/ask` | What this project asks of another; only for a turn running here (409 if not); records `enlace.received` with agent and turn | A turn's `pulse-enlaces` server, with the key |
243
+ | `POST /api/salas/enlaces/recall` | Check or uncheck "Always include" on a connection | The Home page, never a process |
244
+ | `POST /api/enlace/notice` | The Diagnostics line when signing or revoking | The project that serves Home, with the key |
245
+
246
+ Contracts live in `~/.pulse/config.json` under `enlaces` and the crossings in `enlaces.jsonl` next to each project's record.
247
+
248
+ Each project remembers where its folder is (`project.json`, next to its record); a project last opened with an earlier MADRE appears when it is opened again.
249
+
250
+ **The Coordinator's project.** `madre salas` opens a project that lives in a MADRE folder (`~/.pulse/salas`, created the first time): the front door when you are not in any project, and also what plain `madre` opens from your home folder. It is a project like the others —its conversation, its memory, its modes— and in Home it comes first, with its badge. Its bar carries the **Project map** key. It never delivers notes through a connection, and it is the only one that can receive permission to give orders to another (the signing sheet asks for it with that project's name).
251
+
252
+ **The Coordinator**, the guardian of your projects, lives in its own project: that is also where what it knows about all of them lives (contracts, census and notes from the connected projects). In its MODULES card you choose which ready agent speaks for it (`@madre` by default if Ollama is ready) and its orders mode. With `@madre`, the Coordinator only answers: it does not propose orders or connections. With any other agent, if you ask it to act or connect, it closes its reply with a `pulse-salas` block: the reason, up to 4 orders `@sala/agente #modo: tarea` and up to 2 connections `enlace A → B: tipos; 7 días; órdenes #1`. The project turns it into a card with one row per order and per connection. If a question needs a project with no connection, the Coordinator proposes the connection on its own.
253
+
254
+ | Mode (Coordinator card) | `#0`–`#1` | `#2` | `#3`–`#4` | Connections |
255
+ |---|---|---|---|---|
256
+ | **Manual** (default) | Waits for **Send** | Waits for **Send** | Reaches its project as a proposal | See below |
257
+ | **Hybrid** | Goes out on its own within the contract | Waits for **Send** | Reaches its project as a proposal | See below |
258
+ | **Automatic** | Goes out on its own within the contract | Goes out on its own within the contract | Reaches its project as a proposal | See below |
259
+
260
+ | Rule | Where it is enforced |
261
+ |---|---|
262
+ | Only the Coordinator gives orders, and only in reply to a message you wrote in its project; never in reply to a question brought from another project | The module, in the Coordinator's project |
263
+ | A read-only connection, without orders, is signed by the Coordinator when it proposes it, for 7 days at most; the row says "Signed by the Coordinator" and has **Revoke**. In the card, "Connections to read: you" leaves them all to you. A connection with orders, which allows editing, is always signed by you: **Sign** on its row, with the name of the project that would receive orders. Once signed, the plan's orders that were waiting for it are released | The contract (`src/enlaces.mjs`) and the same signature as the Home sheet |
264
+ | An order reaches up to the mode the contract signed and never goes beyond `#2`. `#3` and `#4` reach their project as an **Unlock and send** card, which writes it into the box; when you send it, the project asks for the usual key. Home shows it as "Waiting for you" | The receiving project |
265
+ | One order at a time per project; it never interrupts a project that is working; the contract's hourly cap on orders, counted separately from reads | The receiving project |
266
+ | What goes out on its own goes out once: if it cannot, it is held with its reason and waits for your button. An order that fails or a STOP ALL in the Coordinator's project stop the plan's automatic sending | The module, in the Coordinator's project |
267
+ | The ordered project answers in its conversation ("from the Coordinator · order n of m") and cannot build a plan or give orders. An order in progress is stopped from its row | The core: the order runs at depth 1 and without a plan |
268
+ | The reply comes back to the plan's conversation as a card (≤ 1200 characters, starts with the project and the agent) and does not start any turn; one line closes the plan | The Coordinator's project |
269
+ | An order or a question brought by the Coordinator is not your word: it does not go into the training dataset | `src/dataset.mjs` |
270
+
271
+ **Calling the Coordinator from any project:** `/bishop ¿qué decidió gumball sobre los pagos?`. If the Coordinator's project is asleep, it wakes it; the question runs there, with what the Coordinator knows about the connected projects, and the answer comes back to the project where you asked as a card **only for you**: that project's agents do not read it, because reading another project is what a connection does.
272
+
273
+ | Route | What | Who |
274
+ |---|---|---|
275
+ | `POST /api/x/bishop/send` · `skip` · `propose` · `stop` · `link` | Send, skip, take a proposal to its project, stop an order in progress, sign a proposed connection; the server acts on what it recorded, never on what the page says | The Coordinator's project page |
276
+ | `POST /api/x/bishop/order` · `proposal` · `halt` | An order, a `#3`/`#4` proposal or a halt arriving at the project it is meant for; the project checks key, contract, origin, mode, agent, busy state and cap | The Coordinator's project, with the channel key |
277
+ | `POST /api/x/bishop/result` · `consult` | The reply to an order, and a `/bishop` question | The project that obeyed or that asked, with the key |
278
+ | `POST /api/x/bishop/answer` | The answer to `/bishop`, as `bishop.answer` | The Coordinator's project, with the key |
279
+
280
+ Plans live in `bishop-plans.json` next to the record of the Coordinator's project (the last 40) and each order received is counted in `enlaces.jsonl` of the project that received it.
281
+
282
+ ---
283
+
284
+ ## WHAT LEAVES THE MACHINE
285
+
286
+ - **No cloud, no account.** MADRE has no account and no backend that stores your things. It does not store provider credentials.
287
+ - **What an agent reads travels to its provider.** Codex to OpenAI, Claude Code to Anthropic, Gemini CLI to Google, OpenCode to whatever it is configured with. If `OPENAI_BASE_URL` or `ANTHROPIC_BASE_URL` changes that destination, MADRE shows only the hostname and blocks the turn before building the briefing; a verified gateway is authorized per agent with `PULSE_ALLOW_CUSTOM_AGENT_ENDPOINTS`. The account, limits and terms of the effective destination apply. `@madre` and the archivist with Ollama do not leave the machine.
288
+ - **A daily notice that it is still in use, always on.** Once a day each copy tells madre.run that it is in use: a random identifier the copy created for itself (`~/.pulse/install-id`), the MADRE version, the operating system and the Node major version. Nothing else: no name, no email, no project, no paths, no agents, nothing of what is said in a project; madre.run does not keep the IP. It is how the author knows how many people use MADRE, which versions are running and whether they come back. It goes out through the same record as everything else, so it appears in "What is sent". Without a network, it fails silently. (`src/heartbeat.mjs`)
289
+ - **Two sends of its own under your switch.** The sentinel, off by default, sends redacted reports to the project's collector. The release channel, on by default, asks npm for the latest version: only the package name travels, the same request `npx` makes. `PULSE_UPDATE_CHECK=0` turns it off.
290
+ - **Writing.** In `#1` no one writes. In `#2` things are only added: what existed is restored when the turn ends. In `#3` the whole project except the forbidden zones, with a restore point and `UNDO`. In a project without git, MADRE keeps its snapshots in a shadow repository outside the project. A command an agent asks for is run by you, with a restore point before and `UNDO` after.
291
+ - **Memory.** Everything said outside INCOGNITO stays in `~/.pulse/rooms/<sala>/` and comes back into the prompts of all the agents in that project. INCOGNITO is the way out for what must not be remembered; PRIVACY, for names that must never appear.
292
+
293
+ ---
294
+
295
+ ## REFERENCE
296
+
297
+ **`~/.pulse/config.json`**, or `PULSE_HOME/config.json`. Diagnostics writes it; environment variables take precedence on the next start.
298
+
299
+ ```json
300
+ {
301
+ "opencode": { "model": "openai/gpt-5.6-sol" },
302
+ "timeouts": { "default": 300000, "claude": 600000 },
303
+ "room": { "softTokenBudget": 500000, "delegation": true, "maxPlanSteps": 4 },
304
+ "memory": { "archivist": "auto", "every": 10, "idleMinutes": 10, "embedProvider": "auto", "recallShare": 0.3 },
305
+ "privacy": { "terms": [], "marker": "[ENTIDAD-ORG]" },
306
+ "updates": { "check": true },
307
+ "telemetry": { "autoReport": false }
308
+ }
309
+ ```
310
+
311
+ **Environment variables**
312
+
313
+ | Variable | Default | Effect |
314
+ |---|---|---|
315
+ | `PULSE_HOME` | `~/.pulse` | Root of the projects and the config |
316
+ | `PULSE_LANGUAGE` | from the config, otherwise `es` | `es` or `en`; takes precedence over the config and over what the browser remembers |
317
+ | `PULSE_SOFT_TOKEN_BUDGET` | `500000` | Local token budget per agent, rolling 5 h window |
318
+ | `PULSE_CONTEXT_MAX_CHARS` | `16000` | Injected transcript window |
319
+ | `PULSE_RECALL_SHARE` | `0.3` | Share of the window for recalled memory (`0` turns it off) |
320
+ | `PULSE_DISTILL` · `_EVERY` · `_IDLE_MS` · `_MAX_CHARS` · `_AGENT` · `_MODEL` | `1` · `10` · `600000` · `6000` · — · — | Note distillation |
321
+ | `PULSE_EMBED` · `PULSE_EMBED_PROVIDER` | `1` · `auto` | Smart search; `ollama`, `gemini`, `auto` |
322
+ | `PULSE_OLLAMA` · `_HOST` · `_MODEL` · `_EMBED_MODEL` | `1` · `http://127.0.0.1:11434` · the best · the best | Ollama |
323
+ | `PULSE_MEMORY_TOOLS` | `1` | `pulse-memory` MCP server on every turn |
324
+ | `PULSE_PRIVATE_TERMS` · `PULSE_PRIVATE_MARKER` | — · `[ENTIDAD-ORG]` | Extra hidden data and its marker |
325
+ | `PULSE_UPDATE_CHECK` | `1` | `0` turns off the daily npm check |
326
+ | `PULSE_GH` | `1` | `0` makes the GitHub module ignore the `gh` session and sign in only with the token you pasted |
327
+ | `PULSE_REPORT_URL` · `PULSE_AUTO_REPORT` | the project's collector · `0` | Sentinel |
328
+ | `PULSE_AGENT_TIMEOUT_MS` · `PULSE_<AGENTE>_TIMEOUT_MS` | `180000` · — | Timeouts |
329
+ | `PULSE_ALLOW_CUSTOM_AGENT_ENDPOINTS` | — | Comma-separated list (`codex`, `claude`) of gateways the human verified and allows; without it, an unofficial base address is blocked |
330
+ | `PULSE_MAX_MESSAGE_CHARS` | `20000` | Maximum size of a message |
331
+ | `PULSE_DELEGATION` · `PULSE_MAX_PLAN_STEPS` | `1` · `4` | Plans |
332
+ | `PULSE_ESCALATION_MS` | `180000` | Permission request timer |
333
+ | `PULSE_OPENCODE_MODEL` | from the config | `proveedor/modelo` for OpenCode |
334
+ | `PULSE_CLAUDE_USAGE` · `PULSE_OFFICIAL_QUOTA` | `0` · `1` | Claude's official quota (reads the keychain); `0` turns off all provider reads |
335
+ | `PULSE_GEMINI_IDLE_MS` · `PULSE_GEMINI_RETRIES` · `PULSE_GEMINI_FALLBACK_MODEL` | `90000` · `1` · `gemini-2.5-flash` | Gemini under load |
336
+
337
+ How the ledger, the stream, the memory, the adapters and recovery work under the hood: [`docs/INTERNALS.md`](INTERNALS.md).
338
+
339
+ ---