bots-garden/mini-mepublic Fork
⑂ main
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

Memory search #36

Merged@k33g wants to merge feature/memory-search into main
Merged as ddb9b4324fe6.
55 files changed
modified .tickets/issues/0048-add-a-builtin-tool-to-search-into-the-mm-session.yaml +207 -4
@@ -1,12 +1,12 @@
11 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
22 id: 48
33 title: Add a builtin tool to search into the mm sessions
4-state: open
4+state: closed
55 author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-09-27T03:45:48.121Z
9-updatedAt: 2026-10-20T05:44:21.627Z
9+updatedAt: 2026-10-20T18:00:00.000Z
1010 labels: []
1111 milestone: v0.8.0
1212 epic: Agent Memory
@@ -17,5 +17,208 @@ body: |
1717 enabled: true
1818 ```
1919 use a /memory command to search information into the sessions files
20-tasks: []
21-comments: []
20+tasks:
21+ - id: 1
22+ title: "Agree on the command, the config keys and the tool name"
23+ state: closed
24+ priority: none
25+ author:
26+ name: k33g
27+ email: ph.charriere@gmail.com
28+ createdAt: 2026-10-20T12:00:00.000Z
29+ updatedAt: 2026-10-20T12:00:00.000Z
30+ - id: 2
31+ title: "store: Search(query, limit) — words, case and accents folded, ranked by distinct words then recency, snippets; skips mm notes and the errors array; current session excluded — with tests"
32+ state: closed
33+ priority: none
34+ author:
35+ name: k33g
36+ email: ph.charriere@gmail.com
37+ createdAt: 2026-10-20T12:00:00.000Z
38+ updatedAt: 2026-10-20T12:00:00.000Z
39+ - id: 3
40+ title: "config: sessions.searchMemory and sessions.autoSearchMemory (both default false), banner — with tests"
41+ state: closed
42+ priority: none
43+ author:
44+ name: k33g
45+ email: ph.charriere@gmail.com
46+ createdAt: 2026-10-20T12:00:00.000Z
47+ updatedAt: 2026-10-20T12:00:00.000Z
48+ - id: 4
49+ title: "/memory <words> in the command table (Terminal | Window | Editor), offered only when sessions.enabled and sessions.searchMemory — with tests"
50+ state: closed
51+ priority: none
52+ author:
53+ name: k33g
54+ email: ph.charriere@gmail.com
55+ createdAt: 2026-10-20T12:00:00.000Z
56+ updatedAt: 2026-10-20T12:00:00.000Z
57+ - id: 5
58+ title: "built-in tool search_memory, declared only when sessions.enabled and sessions.autoSearchMemory; read-only, never asks — with tests"
59+ state: closed
60+ priority: none
61+ author:
62+ name: k33g
63+ email: ph.charriere@gmail.com
64+ createdAt: 2026-10-20T12:00:00.000Z
65+ updatedAt: 2026-10-20T12:00:00.000Z
66+ - id: 6
67+ title: "Measure the tool on a small model (llmman): called when needed, not otherwise"
68+ state: closed
69+ priority: none
70+ author:
71+ name: k33g
72+ email: ph.charriere@gmail.com
73+ createdAt: 2026-10-20T12:00:00.000Z
74+ updatedAt: 2026-10-20T12:00:00.000Z
75+ - id: 7
76+ title: "Docs EN+FR (reference configuration, slash-commands, tools; how-to), quality gate, .memory"
77+ state: closed
78+ priority: none
79+ author:
80+ name: k33g
81+ email: ph.charriere@gmail.com
82+ createdAt: 2026-10-20T12:00:00.000Z
83+ updatedAt: 2026-10-20T12:00:00.000Z
84+comments:
85+ - id: 1
86+ author:
87+ name: k33g
88+ email: ph.charriere@gmail.com
89+ createdAt: 2026-10-20T12:00:00.000Z
90+ body: |
91+ Decided by the user (2026-10-20):
92+ - /memory <words>: the user's search, available only when
93+ sessions.enabled AND sessions.searchMemory: true (default false);
94+ - built-in tool search_memory: usable by the model only when
95+ sessions.autoSearchMemory: true (default false) — and sessions on;
96+ - tool name: search_memory.
97+ Kept from the proposal (not discussed, to confirm while reviewing):
98+ the two keys are independent (autoSearchMemory without searchMemory
99+ gives the tool and no command); lexical search, no embeddings (ticket
100+ 74's ground); /compact summaries searched, mm notes and errors not;
101+ current session excluded; v1 searches only — no "read one exchange in
102+ full" mode; read-only tool, never asks for permission.
103+ - id: 2
104+ author:
105+ name: k33g
106+ email: ph.charriere@gmail.com
107+ createdAt: 2026-10-20T13:00:00.000Z
108+ body: |
109+ Tasks 2-5 done on feature/memory-search (go test ./... green, gofmt/vet clean):
110+ - store/search.go: Store.Search(query, known, limit) / Store.Memory /
111+ Keeper.Memory / FormatHits. Words folded (lower case, accents dropped
112+ rune for rune with x/text norm, so a snippet cuts the original at the
113+ folded position), OR of the words, ranked by distinct words then
114+ session date then turn; questions (hook context cut), answers,
115+ /compact summaries; not tool calls/outputs, mm notes, errors.
116+ Default 10 hits, cap 50; snippet 80 runes before / 160 after.
117+ - Change from the proposal: the conversation in progress is left out BY
118+ CONTENT (a message with the same role and text as one in the current
119+ history is not a hit), not by session id — no front end tells a tool
120+ which file it saves to (the REPL has no sink at all), and a resumed or
121+ compacted session's file holds exactly the messages in memory.
122+ - config: sessions.searchMemory, sessions.autoSearchMemory (default
123+ false), MemoryCommand()/MemoryTool()/MemoryWarning() — a key set with
124+ sessions off is a banner warning; search_memory reserved.
125+ - command/memory.go: SetMemory; /memory <words> in the REPL, the window
126+ (notice) and ACP (agent text, advertised with an input hint).
127+ - tools/searchmemory.go: search_memory {query, limit?}, never asks, ACP
128+ kind "search" (new mapping to ToolKindSearch), sessions dir through
129+ ui.Resolve, output capped by maxOutput.
130+ - id: 3
131+ author:
132+ name: k33g
133+ email: ph.charriere@gmail.com
134+ createdAt: 2026-10-20T14:00:00.000Z
135+ body: |
136+ Measured (task 6): mm -p, llmman (host), Qwen3.5-4B Q4_K_M,
137+ contextWindow 16384, bash + edit tools + search_memory, a fresh copy of a
138+ throwaway project per run with two stored sessions (API port 8417;
139+ "Postgres or SQLite for the storage?" → SQLite in data/app.db).
140+ - Words present in a session: "What port did we decide for the API
141+ server last time?" and "Write config.go with a const Port set to the
142+ API port we agreed on before." → search_memory called and right answer
143+ 9/9 (warm-up + 3 + 3 + 1 + 1 after the last change); config.go written
144+ with `const Port = 8417` 4/4. 5-17 s.
145+ - Not needed: "hello", "What is 17 times 3?", "List the files of this
146+ directory.", "Write hello.go that prints Hello." → never called, 0/12.
147+ - LIMIT: French question on an English session ("Rappelle-moi quelle
148+ base de données on avait choisie…"): search "base de données" → no hit;
149+ the model then read the JSON files itself and answered right (2/3, the
150+ 3rd a server stall: no first token after 3m). Added a no-hit line in
151+ the tool's output (try synonyms / English): the model then retried with
152+ "database" 3/3 — still no hit, the session says "storage"/"SQLite" —
153+ and again read the files (3/3 right). Lexical search cannot bridge a
154+ vocabulary gap; an embedding search (embeddinggemma-300m is on the
155+ llmman here) would — ticket 74's ground, not done.
156+ - /memory checked live in the REPL (piped stdin): listed in /help, 3
157+ hits ranked as expected; the sessions-off warning shows.
158+ Docs EN+FR: reference configuration (two keys + warning, reserved name),
159+ slash-commands (terminal + ACP rows), tools (search_memory), how-to
160+ search-earlier-sessions (new), keep-sessions (variant), explanation
161+ persistent-sessions (why words, the measurement, rejected alternative),
162+ both indexes; packages.drawio tools → store.
163+ Task 7 stays open: qlty quality gate NOT run (qlty absent here).
164+ - id: 4
165+ author:
166+ name: k33g
167+ email: ph.charriere@gmail.com
168+ createdAt: 2026-10-20T16:00:00.000Z
169+ body: |
170+ demos/memory-search/ (user's request): Bob, Qwen3.5 4B on llmman,
171+ searchMemory + autoSearchMemory, seed/ = four earlier sessions of a
172+ "bookshelf" Go app (port; storage + migrations; logs in FR; deployment
173+ as a /compact summary), reset.sh copies them to .mm/sessions (git-
174+ ignored). READMEs EN+FR with measured results, root README row + line.
175+ Building it found four engine defects, all fixed with tests:
176+ 1. a question hit without its answer ("format logs" → only "Quel format
177+ pour les logs ?"; the model said nothing was decided) → a matching
178+ question now carries its turn's FINAL answer (Hit.Answer, "→" line),
179+ the answer is no separate hit, the score counts both;
180+ 2. one/two-letter words matched inside words ("de" → Deployment,
181+ modernc, Module: the whole history came back, right answer by luck)
182+ → dropped beside longer words (minWordRunes 3);
183+ 3. snippet cut 160 runes after the FIRST word (summary lost its backups
184+ line, wrong answer) → spans first..last word, max 600 runes;
185+ 4. the summary's wrapper line and the model's fixed acknowledgement
186+ ("Understood — I will re-check files…") were hits → compact.
187+ InSummaryPair / SummaryNotes; only the notes are searched.
188+ Final measurement (temperature 0, 3 runs each, identical): port 3/3,
189+ config.go written with 8417 + data/bookshelf.db 3/3, deploy + backups
190+ from the summary 3/3, logs (FR) 3/3, migrations (FR question, EN
191+ session) 3/3, "Quelle base de données ?" NOT found 3/3 — honest "I
192+ don't know" (the session says storage/SQLite), greeting and a general
193+ Go question: no search 6/6. Prompt lessons kept in the README: "do not
194+ only show the code" (else config.go printed, 3/3), "how do we
195+ handle…" examples (else no search, 3/3), examples in English only
196+ (French examples → English question answered in French, 3/3).
197+ Not this ticket: the line-mode REPL reads only the FIRST line of piped
198+ stdin (a new bufio.Reader per prompt, internal/agent/agent.go:78) —
199+ pre-existing, seen with /sessions + /help too.
200+ - id: 5
201+ author:
202+ name: k33g
203+ email: ph.charriere@gmail.com
204+ createdAt: 2026-10-20T17:00:00.000Z
205+ body: |
206+ The piped-stdin defect noted in comment 4 is fixed: ticket 103.
207+ - id: 6
208+ author:
209+ name: k33g
210+ email: ph.charriere@gmail.com
211+ createdAt: 2026-10-20T18:00:00.000Z
212+ body: |
213+ Documentation complete (EN + FR): reference configuration (two keys,
214+ warning, reserved name), slash-commands (terminal + ACP), tools
215+ (search_memory, with a pointer to /memory), acp (tool kind `search`),
216+ how-to search-earlier-sessions, keep-sessions (variant), explanation
217+ persistent-sessions (why words, measurements, the demo's four fixes,
218+ rejected alternatives), both indexes, root README (feature line + demo
219+ row), demos/memory-search READMEs; packages.drawio (store and tools
220+ edges). Links of the new pages checked.
221+ Closed at the user's request. The qlty quality gate was NOT run (qlty
222+ is not installed in this sandbox); gofmt and go vet clean, go test
223+ ./... green.
224+
@@ -1,12 +1,12 @@
1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2 id: 482 id: 48
3 title: Add a builtin tool to search into the mm sessions3 title: Add a builtin tool to search into the mm sessions
4-state: open4+state: closed
5 author:5 author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-09-27T03:45:48.121Z8 createdAt: 2026-09-27T03:45:48.121Z
9-updatedAt: 2026-10-20T05:44:21.627Z9+updatedAt: 2026-10-20T18:00:00.000Z
10 labels: []10 labels: []
11 milestone: v0.8.011 milestone: v0.8.0
12 epic: Agent Memory12 epic: Agent Memory
@@ -17,5 +17,208 @@ body: |
17 enabled: true17 enabled: true
18 ```18 ```
19 use a /memory command to search information into the sessions files19 use a /memory command to search information into the sessions files
20-tasks: []20+tasks:
21-comments: []21+ - id: 1
22+ title: "Agree on the command, the config keys and the tool name"
23+ state: closed
24+ priority: none
25+ author:
26+ name: k33g
27+ email: ph.charriere@gmail.com
28+ createdAt: 2026-10-20T12:00:00.000Z
29+ updatedAt: 2026-10-20T12:00:00.000Z
30+ - id: 2
31+ title: "store: Search(query, limit) — words, case and accents folded, ranked by distinct words then recency, snippets; skips mm notes and the errors array; current session excluded — with tests"
32+ state: closed
33+ priority: none
34+ author:
35+ name: k33g
36+ email: ph.charriere@gmail.com
37+ createdAt: 2026-10-20T12:00:00.000Z
38+ updatedAt: 2026-10-20T12:00:00.000Z
39+ - id: 3
40+ title: "config: sessions.searchMemory and sessions.autoSearchMemory (both default false), banner — with tests"
41+ state: closed
42+ priority: none
43+ author:
44+ name: k33g
45+ email: ph.charriere@gmail.com
46+ createdAt: 2026-10-20T12:00:00.000Z
47+ updatedAt: 2026-10-20T12:00:00.000Z
48+ - id: 4
49+ title: "/memory <words> in the command table (Terminal | Window | Editor), offered only when sessions.enabled and sessions.searchMemory — with tests"
50+ state: closed
51+ priority: none
52+ author:
53+ name: k33g
54+ email: ph.charriere@gmail.com
55+ createdAt: 2026-10-20T12:00:00.000Z
56+ updatedAt: 2026-10-20T12:00:00.000Z
57+ - id: 5
58+ title: "built-in tool search_memory, declared only when sessions.enabled and sessions.autoSearchMemory; read-only, never asks — with tests"
59+ state: closed
60+ priority: none
61+ author:
62+ name: k33g
63+ email: ph.charriere@gmail.com
64+ createdAt: 2026-10-20T12:00:00.000Z
65+ updatedAt: 2026-10-20T12:00:00.000Z
66+ - id: 6
67+ title: "Measure the tool on a small model (llmman): called when needed, not otherwise"
68+ state: closed
69+ priority: none
70+ author:
71+ name: k33g
72+ email: ph.charriere@gmail.com
73+ createdAt: 2026-10-20T12:00:00.000Z
74+ updatedAt: 2026-10-20T12:00:00.000Z
75+ - id: 7
76+ title: "Docs EN+FR (reference configuration, slash-commands, tools; how-to), quality gate, .memory"
77+ state: closed
78+ priority: none
79+ author:
80+ name: k33g
81+ email: ph.charriere@gmail.com
82+ createdAt: 2026-10-20T12:00:00.000Z
83+ updatedAt: 2026-10-20T12:00:00.000Z
84+comments:
85+ - id: 1
86+ author:
87+ name: k33g
88+ email: ph.charriere@gmail.com
89+ createdAt: 2026-10-20T12:00:00.000Z
90+ body: |
91+ Decided by the user (2026-10-20):
92+ - /memory <words>: the user's search, available only when
93+ sessions.enabled AND sessions.searchMemory: true (default false);
94+ - built-in tool search_memory: usable by the model only when
95+ sessions.autoSearchMemory: true (default false) — and sessions on;
96+ - tool name: search_memory.
97+ Kept from the proposal (not discussed, to confirm while reviewing):
98+ the two keys are independent (autoSearchMemory without searchMemory
99+ gives the tool and no command); lexical search, no embeddings (ticket
100+ 74's ground); /compact summaries searched, mm notes and errors not;
101+ current session excluded; v1 searches only — no "read one exchange in
102+ full" mode; read-only tool, never asks for permission.
103+ - id: 2
104+ author:
105+ name: k33g
106+ email: ph.charriere@gmail.com
107+ createdAt: 2026-10-20T13:00:00.000Z
108+ body: |
109+ Tasks 2-5 done on feature/memory-search (go test ./... green, gofmt/vet clean):
110+ - store/search.go: Store.Search(query, known, limit) / Store.Memory /
111+ Keeper.Memory / FormatHits. Words folded (lower case, accents dropped
112+ rune for rune with x/text norm, so a snippet cuts the original at the
113+ folded position), OR of the words, ranked by distinct words then
114+ session date then turn; questions (hook context cut), answers,
115+ /compact summaries; not tool calls/outputs, mm notes, errors.
116+ Default 10 hits, cap 50; snippet 80 runes before / 160 after.
117+ - Change from the proposal: the conversation in progress is left out BY
118+ CONTENT (a message with the same role and text as one in the current
119+ history is not a hit), not by session id — no front end tells a tool
120+ which file it saves to (the REPL has no sink at all), and a resumed or
121+ compacted session's file holds exactly the messages in memory.
122+ - config: sessions.searchMemory, sessions.autoSearchMemory (default
123+ false), MemoryCommand()/MemoryTool()/MemoryWarning() — a key set with
124+ sessions off is a banner warning; search_memory reserved.
125+ - command/memory.go: SetMemory; /memory <words> in the REPL, the window
126+ (notice) and ACP (agent text, advertised with an input hint).
127+ - tools/searchmemory.go: search_memory {query, limit?}, never asks, ACP
128+ kind "search" (new mapping to ToolKindSearch), sessions dir through
129+ ui.Resolve, output capped by maxOutput.
130+ - id: 3
131+ author:
132+ name: k33g
133+ email: ph.charriere@gmail.com
134+ createdAt: 2026-10-20T14:00:00.000Z
135+ body: |
136+ Measured (task 6): mm -p, llmman (host), Qwen3.5-4B Q4_K_M,
137+ contextWindow 16384, bash + edit tools + search_memory, a fresh copy of a
138+ throwaway project per run with two stored sessions (API port 8417;
139+ "Postgres or SQLite for the storage?" → SQLite in data/app.db).
140+ - Words present in a session: "What port did we decide for the API
141+ server last time?" and "Write config.go with a const Port set to the
142+ API port we agreed on before." → search_memory called and right answer
143+ 9/9 (warm-up + 3 + 3 + 1 + 1 after the last change); config.go written
144+ with `const Port = 8417` 4/4. 5-17 s.
145+ - Not needed: "hello", "What is 17 times 3?", "List the files of this
146+ directory.", "Write hello.go that prints Hello." → never called, 0/12.
147+ - LIMIT: French question on an English session ("Rappelle-moi quelle
148+ base de données on avait choisie…"): search "base de données" → no hit;
149+ the model then read the JSON files itself and answered right (2/3, the
150+ 3rd a server stall: no first token after 3m). Added a no-hit line in
151+ the tool's output (try synonyms / English): the model then retried with
152+ "database" 3/3 — still no hit, the session says "storage"/"SQLite" —
153+ and again read the files (3/3 right). Lexical search cannot bridge a
154+ vocabulary gap; an embedding search (embeddinggemma-300m is on the
155+ llmman here) would — ticket 74's ground, not done.
156+ - /memory checked live in the REPL (piped stdin): listed in /help, 3
157+ hits ranked as expected; the sessions-off warning shows.
158+ Docs EN+FR: reference configuration (two keys + warning, reserved name),
159+ slash-commands (terminal + ACP rows), tools (search_memory), how-to
160+ search-earlier-sessions (new), keep-sessions (variant), explanation
161+ persistent-sessions (why words, the measurement, rejected alternative),
162+ both indexes; packages.drawio tools → store.
163+ Task 7 stays open: qlty quality gate NOT run (qlty absent here).
164+ - id: 4
165+ author:
166+ name: k33g
167+ email: ph.charriere@gmail.com
168+ createdAt: 2026-10-20T16:00:00.000Z
169+ body: |
170+ demos/memory-search/ (user's request): Bob, Qwen3.5 4B on llmman,
171+ searchMemory + autoSearchMemory, seed/ = four earlier sessions of a
172+ "bookshelf" Go app (port; storage + migrations; logs in FR; deployment
173+ as a /compact summary), reset.sh copies them to .mm/sessions (git-
174+ ignored). READMEs EN+FR with measured results, root README row + line.
175+ Building it found four engine defects, all fixed with tests:
176+ 1. a question hit without its answer ("format logs" → only "Quel format
177+ pour les logs ?"; the model said nothing was decided) → a matching
178+ question now carries its turn's FINAL answer (Hit.Answer, "→" line),
179+ the answer is no separate hit, the score counts both;
180+ 2. one/two-letter words matched inside words ("de" → Deployment,
181+ modernc, Module: the whole history came back, right answer by luck)
182+ → dropped beside longer words (minWordRunes 3);
183+ 3. snippet cut 160 runes after the FIRST word (summary lost its backups
184+ line, wrong answer) → spans first..last word, max 600 runes;
185+ 4. the summary's wrapper line and the model's fixed acknowledgement
186+ ("Understood — I will re-check files…") were hits → compact.
187+ InSummaryPair / SummaryNotes; only the notes are searched.
188+ Final measurement (temperature 0, 3 runs each, identical): port 3/3,
189+ config.go written with 8417 + data/bookshelf.db 3/3, deploy + backups
190+ from the summary 3/3, logs (FR) 3/3, migrations (FR question, EN
191+ session) 3/3, "Quelle base de données ?" NOT found 3/3 — honest "I
192+ don't know" (the session says storage/SQLite), greeting and a general
193+ Go question: no search 6/6. Prompt lessons kept in the README: "do not
194+ only show the code" (else config.go printed, 3/3), "how do we
195+ handle…" examples (else no search, 3/3), examples in English only
196+ (French examples → English question answered in French, 3/3).
197+ Not this ticket: the line-mode REPL reads only the FIRST line of piped
198+ stdin (a new bufio.Reader per prompt, internal/agent/agent.go:78) —
199+ pre-existing, seen with /sessions + /help too.
200+ - id: 5
201+ author:
202+ name: k33g
203+ email: ph.charriere@gmail.com
204+ createdAt: 2026-10-20T17:00:00.000Z
205+ body: |
206+ The piped-stdin defect noted in comment 4 is fixed: ticket 103.
207+ - id: 6
208+ author:
209+ name: k33g
210+ email: ph.charriere@gmail.com
211+ createdAt: 2026-10-20T18:00:00.000Z
212+ body: |
213+ Documentation complete (EN + FR): reference configuration (two keys,
214+ warning, reserved name), slash-commands (terminal + ACP), tools
215+ (search_memory, with a pointer to /memory), acp (tool kind `search`),
216+ how-to search-earlier-sessions, keep-sessions (variant), explanation
217+ persistent-sessions (why words, measurements, the demo's four fixes,
218+ rejected alternatives), both indexes, root README (feature line + demo
219+ row), demos/memory-search READMEs; packages.drawio (store and tools
220+ edges). Links of the new pages checked.
221+ Closed at the user's request. The qlty quality gate was NOT run (qlty
222+ is not installed in this sandbox); gofmt and go vet clean, go test
223+ ./... green.
224+
renamed .tickets/issues/0093-save-an-answer-to-a-file-without-regenerating-it.yaml +7 -7
similarity index 94%
rename from .tickets/issues/0093-save-an-answer-without-regenerating-it.yaml
rename to .tickets/issues/0093-save-an-answer-to-a-file-without-regenerating-it.yaml
@@ -1,15 +1,16 @@
11 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
22 id: 93
33 title: Save an answer to a file without regenerating it (/save, save_answer)
4-state: open
4+state: closed
55 author:
66 name: k33g
77 email: ph.charriere@gmail.com
88 createdAt: 2026-10-17T16:00:00.000Z
9-updatedAt: 2026-10-17T16:00:00.000Z
9+updatedAt: 2026-10-20T06:49:43.311Z
1010 labels:
1111 - kind::feature
1212 - builtin tool
13+milestone: v0.7.0
1314 epic: Builtin tools
1415 body: |
1516 ## Why
@@ -34,10 +35,9 @@ body: |
3435 When the model writes a short sentence beside the call ("I'll save it."), that sentence is what gets saved. The tool description tells the model to call it alone to save a previous answer; to be measured with the mini-tutorial agent (`wip2/`).
3536 ## Measured with the mini-tutorial agent (wip2/, 2026-10-17)
3637 8 cases × 2 runs, three configs (Mellum2.1 thinking 13/16, Mellum2.1 no thinking 11/16, Qwen3.5-9B 14/16). **"save it" after the answer: 6/6** — the file is the exact answer, in seconds. **"explain X and save it" in one request: 0/6**: Mellum2.1 thinking wrote the call as TEXT with wrong tags (`<tools>{…}</tools>`), Qwen3.5-9B never called the tool, Mellum2.1 without thinking called it FIRST ("no answer yet"), then once claimed it was saved, once saved its own 1,536-word deliberation + tutorial. Open: a way to save the answer being written (see wip2/README).
37-
3838 tasks:
3939 - id: 1
40- title: "internal/saved + /save command, with tests"
40+ title: internal/saved + /save command, with tests
4141 state: closed
4242 priority: high
4343 author:
@@ -47,7 +47,7 @@ tasks:
4747 updatedAt: 2026-10-17T16:00:00.000Z
4848 closedAt: 2026-10-17T16:00:00.000Z
4949 - id: 2
50- title: "save_answer tool + engine.Reply, with tests"
50+ title: save_answer tool + engine.Reply, with tests
5151 state: closed
5252 priority: high
5353 author:
@@ -57,7 +57,7 @@ tasks:
5757 updatedAt: 2026-10-17T16:00:00.000Z
5858 closedAt: 2026-10-17T16:00:00.000Z
5959 - id: 3
60- title: "Docs EN+FR, diagram"
60+ title: Docs EN+FR, diagram
6161 state: closed
6262 priority: medium
6363 author:
@@ -67,7 +67,7 @@ tasks:
6767 updatedAt: 2026-10-17T16:00:00.000Z
6868 closedAt: 2026-10-17T16:00:00.000Z
6969 - id: 4
70- title: "Measure save_answer live with the mini-tutorial agent (wip2/)"
70+ title: Measure save_answer live with the mini-tutorial agent (wip2/)
7171 state: closed
7272 priority: medium
7373 author:
similarity index 94%
rename from .tickets/issues/0093-save-an-answer-without-regenerating-it.yaml
rename to .tickets/issues/0093-save-an-answer-to-a-file-without-regenerating-it.yaml
@@ -1,15 +1,16 @@
1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.1 # Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2 id: 932 id: 93
3 title: Save an answer to a file without regenerating it (/save, save_answer)3 title: Save an answer to a file without regenerating it (/save, save_answer)
4-state: open4+state: closed
5 author:5 author:
6 name: k33g6 name: k33g
7 email: ph.charriere@gmail.com7 email: ph.charriere@gmail.com
8 createdAt: 2026-10-17T16:00:00.000Z8 createdAt: 2026-10-17T16:00:00.000Z
9-updatedAt: 2026-10-17T16:00:00.000Z9+updatedAt: 2026-10-20T06:49:43.311Z
10 labels:10 labels:
11 - kind::feature11 - kind::feature
12 - builtin tool12 - builtin tool
13+milestone: v0.7.0
13 epic: Builtin tools14 epic: Builtin tools
14 body: |15 body: |
15 ## Why16 ## Why
@@ -34,10 +35,9 @@ body: |
34 When the model writes a short sentence beside the call ("I'll save it."), that sentence is what gets saved. The tool description tells the model to call it alone to save a previous answer; to be measured with the mini-tutorial agent (`wip2/`).35 When the model writes a short sentence beside the call ("I'll save it."), that sentence is what gets saved. The tool description tells the model to call it alone to save a previous answer; to be measured with the mini-tutorial agent (`wip2/`).
35 ## Measured with the mini-tutorial agent (wip2/, 2026-10-17)36 ## Measured with the mini-tutorial agent (wip2/, 2026-10-17)
36 8 cases × 2 runs, three configs (Mellum2.1 thinking 13/16, Mellum2.1 no thinking 11/16, Qwen3.5-9B 14/16). **"save it" after the answer: 6/6** — the file is the exact answer, in seconds. **"explain X and save it" in one request: 0/6**: Mellum2.1 thinking wrote the call as TEXT with wrong tags (`<tools>{…}</tools>`), Qwen3.5-9B never called the tool, Mellum2.1 without thinking called it FIRST ("no answer yet"), then once claimed it was saved, once saved its own 1,536-word deliberation + tutorial. Open: a way to save the answer being written (see wip2/README).37 8 cases × 2 runs, three configs (Mellum2.1 thinking 13/16, Mellum2.1 no thinking 11/16, Qwen3.5-9B 14/16). **"save it" after the answer: 6/6** — the file is the exact answer, in seconds. **"explain X and save it" in one request: 0/6**: Mellum2.1 thinking wrote the call as TEXT with wrong tags (`<tools>{…}</tools>`), Qwen3.5-9B never called the tool, Mellum2.1 without thinking called it FIRST ("no answer yet"), then once claimed it was saved, once saved its own 1,536-word deliberation + tutorial. Open: a way to save the answer being written (see wip2/README).
37-
38 tasks:38 tasks:
39 - id: 139 - id: 1
40- title: "internal/saved + /save command, with tests"40+ title: internal/saved + /save command, with tests
41 state: closed41 state: closed
42 priority: high42 priority: high
43 author:43 author:
@@ -47,7 +47,7 @@ tasks:
47 updatedAt: 2026-10-17T16:00:00.000Z47 updatedAt: 2026-10-17T16:00:00.000Z
48 closedAt: 2026-10-17T16:00:00.000Z48 closedAt: 2026-10-17T16:00:00.000Z
49 - id: 249 - id: 2
50- title: "save_answer tool + engine.Reply, with tests"50+ title: save_answer tool + engine.Reply, with tests
51 state: closed51 state: closed
52 priority: high52 priority: high
53 author:53 author:
@@ -57,7 +57,7 @@ tasks:
57 updatedAt: 2026-10-17T16:00:00.000Z57 updatedAt: 2026-10-17T16:00:00.000Z
58 closedAt: 2026-10-17T16:00:00.000Z58 closedAt: 2026-10-17T16:00:00.000Z
59 - id: 359 - id: 3
60- title: "Docs EN+FR, diagram"60+ title: Docs EN+FR, diagram
61 state: closed61 state: closed
62 priority: medium62 priority: medium
63 author:63 author:
@@ -67,7 +67,7 @@ tasks:
67 updatedAt: 2026-10-17T16:00:00.000Z67 updatedAt: 2026-10-17T16:00:00.000Z
68 closedAt: 2026-10-17T16:00:00.000Z68 closedAt: 2026-10-17T16:00:00.000Z
69 - id: 469 - id: 4
70- title: "Measure save_answer live with the mini-tutorial agent (wip2/)"70+ title: Measure save_answer live with the mini-tutorial agent (wip2/)
71 state: closed71 state: closed
72 priority: medium72 priority: medium
73 author:73 author:
added .tickets/issues/0102-run-sub-agents-in-background.yaml +13 -0
new file mode 100644
@@ -0,0 +1,13 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 102
3+title: Run sub agents in background
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-20T06:48:30.439Z
9+updatedAt: 2026-10-20T06:48:30.439Z
10+labels: []
11+body: ""
12+tasks: []
13+comments: []
new file mode 100644
@@ -0,0 +1,13 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 102
3+title: Run sub agents in background
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-20T06:48:30.439Z
9+updatedAt: 2026-10-20T06:48:30.439Z
10+labels: []
11+body: ""
12+tasks: []
13+comments: []
added .tickets/issues/0103-line-mode-only-the-first-of-several-piped-lines.yaml +48 -0
new file mode 100644
@@ -0,0 +1,48 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 103
3+title: Line mode reads only the first of several piped lines
4+state: closed
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-20T17:00:00.000Z
9+updatedAt: 2026-10-20T17:00:00.000Z
10+labels:
11+ - kind::bug
12+related:
13+ - 48
14+body: |
15+ Found while measuring demos/memory-search (ticket 48). In the line mode
16+ (the REPL, no -tui, no -acp), several lines arriving at once are lost but
17+ the first:
18+
19+ printf '/memory logs\n/memory port\n/quit\n' | mm agent.yaml
20+ mm agent.yaml < commands.txt
21+
22+ run /memory logs and nothing else. Typing at the keyboard is not affected:
23+ the terminal hands over one line per Enter. The window (-tui), ACP and
24+ `mm -p` do not use this code.
25+
26+ Cause: internal/agent/agent.go made a NEW bufio.Reader for every line. A
27+ bufio.Reader reads ahead (up to 4 KB); the first one took all the piped
28+ lines, returned the first, and was dropped with the rest in its buffer.
29+tasks: []
30+comments:
31+ - id: 1
32+ author:
33+ name: k33g
34+ email: ph.charriere@gmail.com
35+ createdAt: 2026-10-20T17:00:00.000Z
36+ body: |
37+ Fixed on feature/memory-search (user's request: "corrige directement").
38+ internal/agent/agent.go: the reader goroutine is now readInput(ctx, r,
39+ out) — ONE bufio.Reader for the whole input; also sends a last line
40+ that has no newline (it used to be dropped at EOF), then closes the
41+ channel as before; other read errors retry as before.
42+ Tests (internal/agent/input_test.go): three piped lines all come
43+ through; one byte per read (iotest.OneByteReader) + last line without
44+ newline; empty input closes; a cancelled context stops the reader.
45+ Live: `printf '/memory logs\n/memory port\n/sessions' | mm agent.yaml`
46+ runs all three and exits at EOF; through a pty, two typed lines both
47+ run and Ctrl-C at the prompt still prints Goodbye and quits.
48+ go test ./... green, gofmt/vet clean.
new file mode 100644
@@ -0,0 +1,48 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 103
3+title: Line mode reads only the first of several piped lines
4+state: closed
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-20T17:00:00.000Z
9+updatedAt: 2026-10-20T17:00:00.000Z
10+labels:
11+ - kind::bug
12+related:
13+ - 48
14+body: |
15+ Found while measuring demos/memory-search (ticket 48). In the line mode
16+ (the REPL, no -tui, no -acp), several lines arriving at once are lost but
17+ the first:
18+
19+ printf '/memory logs\n/memory port\n/quit\n' | mm agent.yaml
20+ mm agent.yaml < commands.txt
21+
22+ run /memory logs and nothing else. Typing at the keyboard is not affected:
23+ the terminal hands over one line per Enter. The window (-tui), ACP and
24+ `mm -p` do not use this code.
25+
26+ Cause: internal/agent/agent.go made a NEW bufio.Reader for every line. A
27+ bufio.Reader reads ahead (up to 4 KB); the first one took all the piped
28+ lines, returned the first, and was dropped with the rest in its buffer.
29+tasks: []
30+comments:
31+ - id: 1
32+ author:
33+ name: k33g
34+ email: ph.charriere@gmail.com
35+ createdAt: 2026-10-20T17:00:00.000Z
36+ body: |
37+ Fixed on feature/memory-search (user's request: "corrige directement").
38+ internal/agent/agent.go: the reader goroutine is now readInput(ctx, r,
39+ out) — ONE bufio.Reader for the whole input; also sends a last line
40+ that has no newline (it used to be dropped at EOF), then closes the
41+ channel as before; other read errors retry as before.
42+ Tests (internal/agent/input_test.go): three piped lines all come
43+ through; one byte per read (iotest.OneByteReader) + last line without
44+ newline; empty input closes; a cancelled context stops the reader.
45+ Live: `printf '/memory logs\n/memory port\n/sessions' | mm agent.yaml`
46+ runs all three and exits at EOF; through a pty, two typed lines both
47+ run and Ctrl-C at the prompt still prints Goodbye and quits.
48+ go test ./... green, gofmt/vet clean.
modified README.md +2 -0
@@ -121,6 +121,7 @@ Anything that speaks ACP can host `mm -acp` the same way: **JetBrains IDEs** (In
121121 - **Plans**: the built-in `plan` tool lets the agent turn a list of tasks into a tracked plan and show its progress after each answer. See [Manage plans and tasks](docs/en/how-to/manage-plans-and-tasks.md).
122122 - **Save an answer**: `/save` writes the last answer to a Markdown file; with `saveAnswerTool: true`, the model does it itself when you ask in your own words (`save_answer`). Never overwrites a file. See [Save an answer to a file](docs/en/how-to/save-an-answer.md).
123123 - **Unload a model**: `/unload [model]` frees a model from the server's memory — in the terminal, the window and an editor —, and the `unload_model` tool lets the agent do it itself, e.g. on another agent's model once it has answered; llmman, Ollama and llama-server in router mode. `unloadModels: false` turns both off. See [Free a model's memory](docs/en/how-to/unload-a-model.md) and `demos/unload-models/`.
124+- **Search earlier sessions**: with sessions on, `/memory <words>` searches the project's stored conversations (`sessions.searchMemory`), and the `search_memory` tool lets the model do it when a question refers to something decided before (`sessions.autoSearchMemory`); both off by default. The search matches words, not meanings. See [Search earlier sessions](docs/en/how-to/search-earlier-sessions.md) and `demos/memory-search/`.
124125 - **Docker Sandboxes**: the sandbox kit lives in its own repository, [mini-me-kit](https://rickub.com/bots-garden/mini-me-kit); `sbx/` explains how to use it (`sbx run …`), with two mixins (`go-toolchain`, `cli-tools`) and ready-made configurations — see `sbx/README.md` and [Run mini-me in a Docker Sandbox](docs/en/how-to/run-in-a-docker-sandbox.md).
125126
126127 ## Demos
@@ -154,6 +155,7 @@ The `demos/` directory holds ready-made set-ups (most with a README explaining h
154155 | `demos/guard/` | one guard model (Granite Guardian 3.2 3B-A800M on llmman) answering `Yes`/`No` to "is this question harmful?"; why its `system:` line is a risk name, not a prompt; custom risks |
155156 | `demos/guards/` | an assistant (Gemma 4 E4B) protected by seven guard agents, one per risk: a Node.js `preGeneration` hook asks them in parallel without the history, the assistant refuses or answers according to their verdicts; `displayHooks: true`; measured results |
156157 | `demos/unload-models/` | a coordinator (Qwen3.5 9B) hands programming questions to an expert (Qwen3.5 4B) with `ask_agent`, a `preAsk` hook unloads the coordinator's own model before the expert starts and a `postAsk` hook unloads the expert's once it has answered — the two models are never loaded together; `/unload` and `unload_model` on request; llmman, measured results |
158+| `demos/memory-search/` | an assistant that remembers a project's decisions: four earlier sessions (port, storage, logs in French, deployment as a `/compact` summary), `/memory <words>` for you and the `search_memory` tool for the model; Qwen3.5 4B on llmman, measured results — including what a word search cannot find |
157159 | `demos/declared-tools/` | an ops desk with no `bash` and no skills, acting only through four tools declared under `tools:` — release, version bump, service logs, slow requests — covering every parameter type (string, enum, boolean, integer, number), a safe default (`dryRun: true`) and an optional argument; Mellum2 12B on DMR, measured results |
158160
159161 ## Learn more
@@ -121,6 +121,7 @@ Anything that speaks ACP can host `mm -acp` the same way: **JetBrains IDEs** (In
121 - **Plans**: the built-in `plan` tool lets the agent turn a list of tasks into a tracked plan and show its progress after each answer. See [Manage plans and tasks](docs/en/how-to/manage-plans-and-tasks.md).121 - **Plans**: the built-in `plan` tool lets the agent turn a list of tasks into a tracked plan and show its progress after each answer. See [Manage plans and tasks](docs/en/how-to/manage-plans-and-tasks.md).
122 - **Save an answer**: `/save` writes the last answer to a Markdown file; with `saveAnswerTool: true`, the model does it itself when you ask in your own words (`save_answer`). Never overwrites a file. See [Save an answer to a file](docs/en/how-to/save-an-answer.md).122 - **Save an answer**: `/save` writes the last answer to a Markdown file; with `saveAnswerTool: true`, the model does it itself when you ask in your own words (`save_answer`). Never overwrites a file. See [Save an answer to a file](docs/en/how-to/save-an-answer.md).
123 - **Unload a model**: `/unload [model]` frees a model from the server's memory — in the terminal, the window and an editor —, and the `unload_model` tool lets the agent do it itself, e.g. on another agent's model once it has answered; llmman, Ollama and llama-server in router mode. `unloadModels: false` turns both off. See [Free a model's memory](docs/en/how-to/unload-a-model.md) and `demos/unload-models/`.123 - **Unload a model**: `/unload [model]` frees a model from the server's memory — in the terminal, the window and an editor —, and the `unload_model` tool lets the agent do it itself, e.g. on another agent's model once it has answered; llmman, Ollama and llama-server in router mode. `unloadModels: false` turns both off. See [Free a model's memory](docs/en/how-to/unload-a-model.md) and `demos/unload-models/`.
124+- **Search earlier sessions**: with sessions on, `/memory <words>` searches the project's stored conversations (`sessions.searchMemory`), and the `search_memory` tool lets the model do it when a question refers to something decided before (`sessions.autoSearchMemory`); both off by default. The search matches words, not meanings. See [Search earlier sessions](docs/en/how-to/search-earlier-sessions.md) and `demos/memory-search/`.
124 - **Docker Sandboxes**: the sandbox kit lives in its own repository, [mini-me-kit](https://rickub.com/bots-garden/mini-me-kit); `sbx/` explains how to use it (`sbx run …`), with two mixins (`go-toolchain`, `cli-tools`) and ready-made configurations — see `sbx/README.md` and [Run mini-me in a Docker Sandbox](docs/en/how-to/run-in-a-docker-sandbox.md).125 - **Docker Sandboxes**: the sandbox kit lives in its own repository, [mini-me-kit](https://rickub.com/bots-garden/mini-me-kit); `sbx/` explains how to use it (`sbx run …`), with two mixins (`go-toolchain`, `cli-tools`) and ready-made configurations — see `sbx/README.md` and [Run mini-me in a Docker Sandbox](docs/en/how-to/run-in-a-docker-sandbox.md).
125 126
126 ## Demos127 ## Demos
@@ -154,6 +155,7 @@ The `demos/` directory holds ready-made set-ups (most with a README explaining h
154 | `demos/guard/` | one guard model (Granite Guardian 3.2 3B-A800M on llmman) answering `Yes`/`No` to "is this question harmful?"; why its `system:` line is a risk name, not a prompt; custom risks |155 | `demos/guard/` | one guard model (Granite Guardian 3.2 3B-A800M on llmman) answering `Yes`/`No` to "is this question harmful?"; why its `system:` line is a risk name, not a prompt; custom risks |
155 | `demos/guards/` | an assistant (Gemma 4 E4B) protected by seven guard agents, one per risk: a Node.js `preGeneration` hook asks them in parallel without the history, the assistant refuses or answers according to their verdicts; `displayHooks: true`; measured results |156 | `demos/guards/` | an assistant (Gemma 4 E4B) protected by seven guard agents, one per risk: a Node.js `preGeneration` hook asks them in parallel without the history, the assistant refuses or answers according to their verdicts; `displayHooks: true`; measured results |
156 | `demos/unload-models/` | a coordinator (Qwen3.5 9B) hands programming questions to an expert (Qwen3.5 4B) with `ask_agent`, a `preAsk` hook unloads the coordinator's own model before the expert starts and a `postAsk` hook unloads the expert's once it has answered — the two models are never loaded together; `/unload` and `unload_model` on request; llmman, measured results |157 | `demos/unload-models/` | a coordinator (Qwen3.5 9B) hands programming questions to an expert (Qwen3.5 4B) with `ask_agent`, a `preAsk` hook unloads the coordinator's own model before the expert starts and a `postAsk` hook unloads the expert's once it has answered — the two models are never loaded together; `/unload` and `unload_model` on request; llmman, measured results |
158+| `demos/memory-search/` | an assistant that remembers a project's decisions: four earlier sessions (port, storage, logs in French, deployment as a `/compact` summary), `/memory <words>` for you and the `search_memory` tool for the model; Qwen3.5 4B on llmman, measured results — including what a word search cannot find |
157 | `demos/declared-tools/` | an ops desk with no `bash` and no skills, acting only through four tools declared under `tools:` — release, version bump, service logs, slow requests — covering every parameter type (string, enum, boolean, integer, number), a safe default (`dryRun: true`) and an optional argument; Mellum2 12B on DMR, measured results |159 | `demos/declared-tools/` | an ops desk with no `bash` and no skills, acting only through four tools declared under `tools:` — release, version bump, service logs, slow requests — covering every parameter type (string, enum, boolean, integer, number), a safe default (`dryRun: true`) and an optional argument; Mellum2 12B on DMR, measured results |
158 160
159 ## Learn more161 ## Learn more
added demos/memory-search/README.en.md +75 -0
new file mode 100644
@@ -0,0 +1,75 @@
1+# mini-me demo: searching earlier sessions
2+
3+*[Version française](README.fr.md)*
4+
5+Bob helps build **bookshelf**, a small Go web app. The project already has four earlier conversations, in which the API port, the storage, the logs and the deployment were decided. Bob does not remember them — each start is a new session — but he can search them: you with `/memory <words>`, Bob himself with the `search_memory` tool. The model is Qwen3.5 4B, served by [llmman](https://github.com/llmmanorg/llmman).
6+
7+## What is here
8+
9+| File | Role |
10+|---|---|
11+| `agent.yaml` | Bob: sessions on, `searchMemory: true` (the `/memory` command), `autoSearchMemory: true` (the `search_memory` tool), `write_file` to show the decisions being used. No `bash`. |
12+| `seed/` | The four earlier sessions, as mm writes them: the API port and the module (EN), the storage and the migrations (EN), the logs and the HTTP errors (FR), the deployment as a `/compact` summary (EN). |
13+| `reset.sh` | Copies `seed/` to `.mm/sessions/` (git-ignored) and removes the `*.go` files the agent wrote. Run it before the demo, and again to start over: every run adds its own session. |
14+
15+## Run the demo
16+
17+```bash
18+llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
19+cd demos/memory-search
20+./reset.sh
21+mm -tui agent.yaml
22+```
23+
24+Search by hand:
25+
26+```text
27+/memory storage sqlite
28+```
29+
30+```text
31+🔎 2 hit(s) for "storage sqlite" in …/demos/memory-search/.mm/sessions
32+20261008-140000-b2c3d4e5 · 2026-10-08 14:35 · turn 1 · question
33+ Postgres or SQLite for the storage?
34+ → SQLite: one user, nothing to run beside the app. The file is data/bookshelf.db, opened with modernc.org/sqlite (pure Go, no cgo).
35+20261015-163000-d4e5f6a7 · 2026-10-15 17:20 · turn 1 · summary
36+ …oxy to 127.0.0.1:8417. - Backups: a nightly cron copies data/bookshelf.db with `sqlite3 .backup` to /var/backups/bookshelf/, 14 days kept.
37+```
38+
39+Then ask Bob, who searches by himself:
40+
41+```text
42+Which port did we choose for the API?
43+Write config.go with the constants we decided before: the API port and the database file.
44+How do we deploy bookshelf, and where are the backups?
45+Quel format de logs avait-on choisi ?
46+```
47+
48+In the terminal each search shows as `🔎 search_memory: "<words>"` followed by its hits.
49+
50+## Measured results (2026-10-20, `mm -p`, llmman)
51+
52+Qwen3.5 4B Q4_K_M, `temperature: 0`, thinking off, this `agent.yaml`, a fresh copy of the demo after `./reset.sh` for every run. Three runs per question; identical results each time.
53+
54+| Question | Searched | Result | |
55+|---|---|---|---|
56+| Which port did we choose for the API? | `API port` | 8417, and why (8080 is the admin UI) | 3/3 |
57+| Write config.go with the constants we decided before: the API port and the database file. | `API port database file config` | `config.go` written with `8417` and `data/bookshelf.db` | 3/3 |
58+| How do we deploy bookshelf, and where are the backups? | `deploy bookshelf backups` | binary + scp + systemd + Caddy; nightly backup to `/var/backups/bookshelf/`, 14 days — from the `/compact` summary | 3/3 |
59+| Quel format de logs avait-on choisi ? | `format logs` | slog in JSON on stdout, `BOOKSHELF_DEBUG=1`, answered in French | 3/3 |
60+| Comment gère-t-on les migrations du schéma ? | `migrations schéma` | numbered SQL files in `migrations/`, `schema_version` table — a French question found an English session: `migrations` is the same word, and `schéma` finds `schema_version` (accents do not count) | 3/3 |
61+| Quelle base de données avait-on choisie ? | `base de données choisie`, `database choice`, `database` | "I find nothing about it" — **not found**: the session says *storage* and *SQLite*, never *database*. Nothing invented. | 3/3 |
62+| Bonjour, qui es-tu ? | — | a one-line answer in French, no search | 3/3 |
63+| What does defer do in Go? One sentence. | — | answered directly, no search | 3/3 |
64+
65+1 to 11 s per question, model loaded.
66+
67+## Good to know
68+
69+- **The search matches words, not meanings.** A question in another language than the session, or with other words for the same thing, finds nothing (the database question above). Ask with the words that were written, or search yourself with `/memory` — `/memory sqlite` finds it at once. When the tool finds nothing, its output tells the model to try synonyms or English; here it did (`database`), and then said it did not know, as `agent.yaml` asks.
70+- **A question comes back with its answer.** A hit on a question shows the answer its turn ended on (`→ …`): "Quel format pour les logs ?" alone would say what was asked, not what was decided.
71+- **The conversation in progress is never a hit**: Bob already reads it.
72+- **Each key on its own.** `searchMemory` gives you `/memory`; `autoSearchMemory` gives Bob `search_memory`. Both need `sessions.enabled: true`, both are off by default.
73+- **What the prompt had to say.** Without "do not only show the code", Bob printed `config.go` instead of writing it (3/3). Without examples like "how do we handle…", "Comment gère-t-on les migrations ?" was answered from general knowledge, without a search (3/3). French examples in the prompt made Bob answer an English question in French (3/3): the examples are in English.
74+
75+See also: [How to search earlier sessions](../../docs/en/how-to/search-earlier-sessions.md), [`search_memory`](../../docs/en/reference/tools.md#search_memory).
new file mode 100644
@@ -0,0 +1,75 @@
1+# mini-me demo: searching earlier sessions
2+
3+*[Version française](README.fr.md)*
4+
5+Bob helps build **bookshelf**, a small Go web app. The project already has four earlier conversations, in which the API port, the storage, the logs and the deployment were decided. Bob does not remember them — each start is a new session — but he can search them: you with `/memory <words>`, Bob himself with the `search_memory` tool. The model is Qwen3.5 4B, served by [llmman](https://github.com/llmmanorg/llmman).
6+
7+## What is here
8+
9+| File | Role |
10+|---|---|
11+| `agent.yaml` | Bob: sessions on, `searchMemory: true` (the `/memory` command), `autoSearchMemory: true` (the `search_memory` tool), `write_file` to show the decisions being used. No `bash`. |
12+| `seed/` | The four earlier sessions, as mm writes them: the API port and the module (EN), the storage and the migrations (EN), the logs and the HTTP errors (FR), the deployment as a `/compact` summary (EN). |
13+| `reset.sh` | Copies `seed/` to `.mm/sessions/` (git-ignored) and removes the `*.go` files the agent wrote. Run it before the demo, and again to start over: every run adds its own session. |
14+
15+## Run the demo
16+
17+```bash
18+llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
19+cd demos/memory-search
20+./reset.sh
21+mm -tui agent.yaml
22+```
23+
24+Search by hand:
25+
26+```text
27+/memory storage sqlite
28+```
29+
30+```text
31+🔎 2 hit(s) for "storage sqlite" in …/demos/memory-search/.mm/sessions
32+20261008-140000-b2c3d4e5 · 2026-10-08 14:35 · turn 1 · question
33+ Postgres or SQLite for the storage?
34+ → SQLite: one user, nothing to run beside the app. The file is data/bookshelf.db, opened with modernc.org/sqlite (pure Go, no cgo).
35+20261015-163000-d4e5f6a7 · 2026-10-15 17:20 · turn 1 · summary
36+ …oxy to 127.0.0.1:8417. - Backups: a nightly cron copies data/bookshelf.db with `sqlite3 .backup` to /var/backups/bookshelf/, 14 days kept.
37+```
38+
39+Then ask Bob, who searches by himself:
40+
41+```text
42+Which port did we choose for the API?
43+Write config.go with the constants we decided before: the API port and the database file.
44+How do we deploy bookshelf, and where are the backups?
45+Quel format de logs avait-on choisi ?
46+```
47+
48+In the terminal each search shows as `🔎 search_memory: "<words>"` followed by its hits.
49+
50+## Measured results (2026-10-20, `mm -p`, llmman)
51+
52+Qwen3.5 4B Q4_K_M, `temperature: 0`, thinking off, this `agent.yaml`, a fresh copy of the demo after `./reset.sh` for every run. Three runs per question; identical results each time.
53+
54+| Question | Searched | Result | |
55+|---|---|---|---|
56+| Which port did we choose for the API? | `API port` | 8417, and why (8080 is the admin UI) | 3/3 |
57+| Write config.go with the constants we decided before: the API port and the database file. | `API port database file config` | `config.go` written with `8417` and `data/bookshelf.db` | 3/3 |
58+| How do we deploy bookshelf, and where are the backups? | `deploy bookshelf backups` | binary + scp + systemd + Caddy; nightly backup to `/var/backups/bookshelf/`, 14 days — from the `/compact` summary | 3/3 |
59+| Quel format de logs avait-on choisi ? | `format logs` | slog in JSON on stdout, `BOOKSHELF_DEBUG=1`, answered in French | 3/3 |
60+| Comment gère-t-on les migrations du schéma ? | `migrations schéma` | numbered SQL files in `migrations/`, `schema_version` table — a French question found an English session: `migrations` is the same word, and `schéma` finds `schema_version` (accents do not count) | 3/3 |
61+| Quelle base de données avait-on choisie ? | `base de données choisie`, `database choice`, `database` | "I find nothing about it" — **not found**: the session says *storage* and *SQLite*, never *database*. Nothing invented. | 3/3 |
62+| Bonjour, qui es-tu ? | — | a one-line answer in French, no search | 3/3 |
63+| What does defer do in Go? One sentence. | — | answered directly, no search | 3/3 |
64+
65+1 to 11 s per question, model loaded.
66+
67+## Good to know
68+
69+- **The search matches words, not meanings.** A question in another language than the session, or with other words for the same thing, finds nothing (the database question above). Ask with the words that were written, or search yourself with `/memory` — `/memory sqlite` finds it at once. When the tool finds nothing, its output tells the model to try synonyms or English; here it did (`database`), and then said it did not know, as `agent.yaml` asks.
70+- **A question comes back with its answer.** A hit on a question shows the answer its turn ended on (`→ …`): "Quel format pour les logs ?" alone would say what was asked, not what was decided.
71+- **The conversation in progress is never a hit**: Bob already reads it.
72+- **Each key on its own.** `searchMemory` gives you `/memory`; `autoSearchMemory` gives Bob `search_memory`. Both need `sessions.enabled: true`, both are off by default.
73+- **What the prompt had to say.** Without "do not only show the code", Bob printed `config.go` instead of writing it (3/3). Without examples like "how do we handle…", "Comment gère-t-on les migrations ?" was answered from general knowledge, without a search (3/3). French examples in the prompt made Bob answer an English question in French (3/3): the examples are in English.
74+
75+See also: [How to search earlier sessions](../../docs/en/how-to/search-earlier-sessions.md), [`search_memory`](../../docs/en/reference/tools.md#search_memory).
added demos/memory-search/README.fr.md +75 -0
new file mode 100644
@@ -0,0 +1,75 @@
1+# Démo mini-me : chercher dans les sessions précédentes
2+
3+*[English version](README.en.md)*
4+
5+Bob aide à construire **bookshelf**, une petite application web en Go. Le projet compte déjà quatre conversations, dans lesquelles ont été décidés le port de l'API, le stockage, les logs et le déploiement. Bob ne s'en souvient pas — chaque lancement est une nouvelle session — mais il peut les fouiller : vous avec `/memory <mots>`, Bob lui-même avec l'outil `search_memory`. Le modèle est Qwen3.5 4B, servi par [llmman](https://github.com/llmmanorg/llmman).
6+
7+## Contenu
8+
9+| Fichier | Rôle |
10+|---|---|
11+| `agent.yaml` | Bob : sessions activées, `searchMemory: true` (la commande `/memory`), `autoSearchMemory: true` (l'outil `search_memory`), `write_file` pour montrer les décisions en action. Pas de `bash`. |
12+| `seed/` | Les quatre sessions précédentes, telles que mm les écrit : le port de l'API et le module (EN), le stockage et les migrations (EN), les logs et les erreurs HTTP (FR), le déploiement sous forme de résumé `/compact` (EN). |
13+| `reset.sh` | Copie `seed/` dans `.mm/sessions/` (ignoré par git) et supprime les fichiers `*.go` écrits par l'agent. À lancer avant la démo, puis à nouveau pour repartir de zéro : chaque exécution ajoute sa propre session. |
14+
15+## Lancer la démo
16+
17+```bash
18+llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
19+cd demos/memory-search
20+./reset.sh
21+mm -tui agent.yaml
22+```
23+
24+Chercher à la main :
25+
26+```text
27+/memory storage sqlite
28+```
29+
30+```text
31+🔎 2 hit(s) for "storage sqlite" in …/demos/memory-search/.mm/sessions
32+20261008-140000-b2c3d4e5 · 2026-10-08 14:35 · turn 1 · question
33+ Postgres or SQLite for the storage?
34+ → SQLite: one user, nothing to run beside the app. The file is data/bookshelf.db, opened with modernc.org/sqlite (pure Go, no cgo).
35+20261015-163000-d4e5f6a7 · 2026-10-15 17:20 · turn 1 · summary
36+ …oxy to 127.0.0.1:8417. - Backups: a nightly cron copies data/bookshelf.db with `sqlite3 .backup` to /var/backups/bookshelf/, 14 days kept.
37+```
38+
39+Puis demander à Bob, qui cherche tout seul :
40+
41+```text
42+Which port did we choose for the API?
43+Write config.go with the constants we decided before: the API port and the database file.
44+How do we deploy bookshelf, and where are the backups?
45+Quel format de logs avait-on choisi ?
46+```
47+
48+Dans le terminal, chaque recherche s'affiche sous la forme `🔎 search_memory: "<mots>"` suivie de ses résultats.
49+
50+## Résultats mesurés (2026-10-20, `mm -p`, llmman)
51+
52+Qwen3.5 4B Q4_K_M, `temperature: 0`, réflexion désactivée, cet `agent.yaml`, une copie neuve de la démo après `./reset.sh` à chaque exécution. Trois exécutions par question ; résultats identiques à chaque fois.
53+
54+| Question | Recherché | Résultat | |
55+|---|---|---|---|
56+| Which port did we choose for the API? | `API port` | 8417, et pourquoi (8080 est l'interface d'administration) | 3/3 |
57+| Write config.go with the constants we decided before: the API port and the database file. | `API port database file config` | `config.go` écrit avec `8417` et `data/bookshelf.db` | 3/3 |
58+| How do we deploy bookshelf, and where are the backups? | `deploy bookshelf backups` | binaire + scp + systemd + Caddy ; sauvegarde nocturne vers `/var/backups/bookshelf/`, 14 jours — tiré du résumé `/compact` | 3/3 |
59+| Quel format de logs avait-on choisi ? | `format logs` | slog en JSON sur la sortie standard, `BOOKSHELF_DEBUG=1`, réponse en français | 3/3 |
60+| Comment gère-t-on les migrations du schéma ? | `migrations schéma` | fichiers SQL numérotés dans `migrations/`, table `schema_version` — une question en français a trouvé une session en anglais : `migrations` est le même mot, et `schéma` trouve `schema_version` (les accents ne comptent pas) | 3/3 |
61+| Quelle base de données avait-on choisie ? | `base de données choisie`, `database choice`, `database` | « je ne trouve rien » — **pas trouvé** : la session dit *storage* et *SQLite*, jamais *database*. Rien d'inventé. | 3/3 |
62+| Bonjour, qui es-tu ? | — | une réponse d'une ligne en français, sans recherche | 3/3 |
63+| What does defer do in Go? One sentence. | — | réponse directe, sans recherche | 3/3 |
64+
65+De 1 à 11 s par question, modèle chargé.
66+
67+## Bon à savoir
68+
69+- **La recherche porte sur les mots, pas sur le sens.** Une question dans une autre langue que la session, ou avec d'autres mots pour la même chose, ne trouve rien (la question sur la base de données ci-dessus). Posez la question avec les mots qui ont été écrits, ou cherchez vous-même avec `/memory` — `/memory sqlite` la trouve aussitôt. Quand l'outil ne trouve rien, sa sortie invite le modèle à essayer des synonymes ou l'anglais ; ici il l'a fait (`database`), puis a dit qu'il ne savait pas, comme le demande `agent.yaml`.
70+- **Une question revient avec sa réponse.** Un résultat sur une question montre la réponse sur laquelle son tour s'est terminé (`→ …`) : « Quel format pour les logs ? » seule dirait ce qui a été demandé, pas ce qui a été décidé.
71+- **La conversation en cours n'est jamais un résultat** : Bob la lit déjà.
72+- **Chaque clé séparément.** `searchMemory` vous donne `/memory` ; `autoSearchMemory` donne `search_memory` à Bob. Les deux demandent `sessions.enabled: true`, les deux sont désactivées par défaut.
73+- **Ce que le prompt a dû dire.** Sans « do not only show the code », Bob affichait `config.go` au lieu de l'écrire (3/3). Sans exemples comme « how do we handle… », « Comment gère-t-on les migrations ? » recevait une réponse de culture générale, sans recherche (3/3). Des exemples en français dans le prompt faisaient répondre Bob en français à une question en anglais (3/3) : les exemples sont en anglais.
74+
75+Voir aussi : [Chercher dans les sessions précédentes](../../docs/fr/how-to/search-earlier-sessions.md), [`search_memory`](../../docs/fr/reference/tools.md#search_memory).
new file mode 100644
@@ -0,0 +1,75 @@
1+# Démo mini-me : chercher dans les sessions précédentes
2+
3+*[English version](README.en.md)*
4+
5+Bob aide à construire **bookshelf**, une petite application web en Go. Le projet compte déjà quatre conversations, dans lesquelles ont été décidés le port de l'API, le stockage, les logs et le déploiement. Bob ne s'en souvient pas — chaque lancement est une nouvelle session — mais il peut les fouiller : vous avec `/memory <mots>`, Bob lui-même avec l'outil `search_memory`. Le modèle est Qwen3.5 4B, servi par [llmman](https://github.com/llmmanorg/llmman).
6+
7+## Contenu
8+
9+| Fichier | Rôle |
10+|---|---|
11+| `agent.yaml` | Bob : sessions activées, `searchMemory: true` (la commande `/memory`), `autoSearchMemory: true` (l'outil `search_memory`), `write_file` pour montrer les décisions en action. Pas de `bash`. |
12+| `seed/` | Les quatre sessions précédentes, telles que mm les écrit : le port de l'API et le module (EN), le stockage et les migrations (EN), les logs et les erreurs HTTP (FR), le déploiement sous forme de résumé `/compact` (EN). |
13+| `reset.sh` | Copie `seed/` dans `.mm/sessions/` (ignoré par git) et supprime les fichiers `*.go` écrits par l'agent. À lancer avant la démo, puis à nouveau pour repartir de zéro : chaque exécution ajoute sa propre session. |
14+
15+## Lancer la démo
16+
17+```bash
18+llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
19+cd demos/memory-search
20+./reset.sh
21+mm -tui agent.yaml
22+```
23+
24+Chercher à la main :
25+
26+```text
27+/memory storage sqlite
28+```
29+
30+```text
31+🔎 2 hit(s) for "storage sqlite" in …/demos/memory-search/.mm/sessions
32+20261008-140000-b2c3d4e5 · 2026-10-08 14:35 · turn 1 · question
33+ Postgres or SQLite for the storage?
34+ → SQLite: one user, nothing to run beside the app. The file is data/bookshelf.db, opened with modernc.org/sqlite (pure Go, no cgo).
35+20261015-163000-d4e5f6a7 · 2026-10-15 17:20 · turn 1 · summary
36+ …oxy to 127.0.0.1:8417. - Backups: a nightly cron copies data/bookshelf.db with `sqlite3 .backup` to /var/backups/bookshelf/, 14 days kept.
37+```
38+
39+Puis demander à Bob, qui cherche tout seul :
40+
41+```text
42+Which port did we choose for the API?
43+Write config.go with the constants we decided before: the API port and the database file.
44+How do we deploy bookshelf, and where are the backups?
45+Quel format de logs avait-on choisi ?
46+```
47+
48+Dans le terminal, chaque recherche s'affiche sous la forme `🔎 search_memory: "<mots>"` suivie de ses résultats.
49+
50+## Résultats mesurés (2026-10-20, `mm -p`, llmman)
51+
52+Qwen3.5 4B Q4_K_M, `temperature: 0`, réflexion désactivée, cet `agent.yaml`, une copie neuve de la démo après `./reset.sh` à chaque exécution. Trois exécutions par question ; résultats identiques à chaque fois.
53+
54+| Question | Recherché | Résultat | |
55+|---|---|---|---|
56+| Which port did we choose for the API? | `API port` | 8417, et pourquoi (8080 est l'interface d'administration) | 3/3 |
57+| Write config.go with the constants we decided before: the API port and the database file. | `API port database file config` | `config.go` écrit avec `8417` et `data/bookshelf.db` | 3/3 |
58+| How do we deploy bookshelf, and where are the backups? | `deploy bookshelf backups` | binaire + scp + systemd + Caddy ; sauvegarde nocturne vers `/var/backups/bookshelf/`, 14 jours — tiré du résumé `/compact` | 3/3 |
59+| Quel format de logs avait-on choisi ? | `format logs` | slog en JSON sur la sortie standard, `BOOKSHELF_DEBUG=1`, réponse en français | 3/3 |
60+| Comment gère-t-on les migrations du schéma ? | `migrations schéma` | fichiers SQL numérotés dans `migrations/`, table `schema_version` — une question en français a trouvé une session en anglais : `migrations` est le même mot, et `schéma` trouve `schema_version` (les accents ne comptent pas) | 3/3 |
61+| Quelle base de données avait-on choisie ? | `base de données choisie`, `database choice`, `database` | « je ne trouve rien » — **pas trouvé** : la session dit *storage* et *SQLite*, jamais *database*. Rien d'inventé. | 3/3 |
62+| Bonjour, qui es-tu ? | — | une réponse d'une ligne en français, sans recherche | 3/3 |
63+| What does defer do in Go? One sentence. | — | réponse directe, sans recherche | 3/3 |
64+
65+De 1 à 11 s par question, modèle chargé.
66+
67+## Bon à savoir
68+
69+- **La recherche porte sur les mots, pas sur le sens.** Une question dans une autre langue que la session, ou avec d'autres mots pour la même chose, ne trouve rien (la question sur la base de données ci-dessus). Posez la question avec les mots qui ont été écrits, ou cherchez vous-même avec `/memory` — `/memory sqlite` la trouve aussitôt. Quand l'outil ne trouve rien, sa sortie invite le modèle à essayer des synonymes ou l'anglais ; ici il l'a fait (`database`), puis a dit qu'il ne savait pas, comme le demande `agent.yaml`.
70+- **Une question revient avec sa réponse.** Un résultat sur une question montre la réponse sur laquelle son tour s'est terminé (`→ …`) : « Quel format pour les logs ? » seule dirait ce qui a été demandé, pas ce qui a été décidé.
71+- **La conversation en cours n'est jamais un résultat** : Bob la lit déjà.
72+- **Chaque clé séparément.** `searchMemory` vous donne `/memory` ; `autoSearchMemory` donne `search_memory` à Bob. Les deux demandent `sessions.enabled: true`, les deux sont désactivées par défaut.
73+- **Ce que le prompt a dû dire.** Sans « do not only show the code », Bob affichait `config.go` au lieu de l'écrire (3/3). Sans exemples comme « how do we handle… », « Comment gère-t-on les migrations ? » recevait une réponse de culture générale, sans recherche (3/3). Des exemples en français dans le prompt faisaient répondre Bob en français à une question en anglais (3/3) : les exemples sont en anglais.
74+
75+Voir aussi : [Chercher dans les sessions précédentes](../../docs/fr/how-to/search-earlier-sessions.md), [`search_memory`](../../docs/fr/reference/tools.md#search_memory).
added demos/memory-search/agent.yaml +79 -0
new file mode 100644
@@ -0,0 +1,79 @@
1+# Memory search — an assistant that remembers what was decided in the
2+# project's earlier conversations:
3+#
4+# /memory <words> the user's search through the stored sessions
5+# (sessions.searchMemory)
6+# search_memory the same search, called by the model when a question
7+# refers to something decided before
8+# (sessions.autoSearchMemory)
9+#
10+# The project is "bookshelf", a small Go web app; seed/ holds four earlier
11+# sessions (the API port, the storage, the logs — in French —, the
12+# deployment as a /compact summary). reset.sh copies them to .mm/sessions.
13+#
14+# llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
15+# llmman serve
16+#
17+# cd demos/memory-search
18+# ./reset.sh
19+# mm -tui agent.yaml or mm -p "…" agent.yaml
20+
21+provider: llmman
22+model: hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
23+baseUrl: http://127.0.0.1:17434/v1
24+fallback: http://host.docker.internal:17434/v1
25+contextWindow: 16384
26+
27+sessions:
28+ enabled: true
29+ dir: .mm/sessions
30+ # /memory <words>, for you.
31+ searchMemory: true
32+ # search_memory, for the model.
33+ autoSearchMemory: true
34+
35+# Writing files (config.go…) is enough to show the decisions being used; no
36+# bash, so the model cannot wander off grepping the session files.
37+yolo: true
38+bashTool: false
39+editTools: true
40+planTool: false
41+askUserTool: false
42+skillsDir: no-skills
43+
44+agentsMd:
45+ enabled: false
46+
47+sampling:
48+ temperature: 0.0
49+ parallel_tool_calls: false
50+ max_tokens: 2048
51+ chat_template_kwargs:
52+ enable_thinking: false
53+
54+maxTurns: 8
55+watchdogTimeout: 2m
56+firstTokenTimeout: 3m
57+displayCommands: true
58+
59+acp:
60+ name: bob
61+ title: 📚 Bob (bookshelf, with a memory)
62+
63+system: |
64+ Your name is Bob. You help build bookshelf, a small Go web app, in this
65+ directory. When the user asks you to write or create a file, call
66+ write_file with the whole content; do not only show the code.
67+
68+ Earlier conversations about this project are stored. When the user refers
69+ to something decided or said before ("the port we chose", "like last
70+ time", "what did we decide for…"), or asks how THIS project does
71+ something ("how do we handle…", "where are…", "which … do we use"), the
72+ answer is a choice made for this project (port, storage, schema, logs,
73+ errors, deployment…): call search_memory first with the key words, then
74+ answer from what it found and name the session it came from. Never
75+ invent a decision: if search_memory finds nothing, try other words once,
76+ then say you do not know.
77+
78+ For anything else (a greeting, a general Go question), answer directly,
79+ in the user's language, without search_memory.
new file mode 100644
@@ -0,0 +1,79 @@
1+# Memory search — an assistant that remembers what was decided in the
2+# project's earlier conversations:
3+#
4+# /memory <words> the user's search through the stored sessions
5+# (sessions.searchMemory)
6+# search_memory the same search, called by the model when a question
7+# refers to something decided before
8+# (sessions.autoSearchMemory)
9+#
10+# The project is "bookshelf", a small Go web app; seed/ holds four earlier
11+# sessions (the API port, the storage, the logs — in French —, the
12+# deployment as a /compact summary). reset.sh copies them to .mm/sessions.
13+#
14+# llmman pull hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
15+# llmman serve
16+#
17+# cd demos/memory-search
18+# ./reset.sh
19+# mm -tui agent.yaml or mm -p "…" agent.yaml
20+
21+provider: llmman
22+model: hf.co/unsloth/Qwen3.5-4B-GGUF:Q4_K_M
23+baseUrl: http://127.0.0.1:17434/v1
24+fallback: http://host.docker.internal:17434/v1
25+contextWindow: 16384
26+
27+sessions:
28+ enabled: true
29+ dir: .mm/sessions
30+ # /memory <words>, for you.
31+ searchMemory: true
32+ # search_memory, for the model.
33+ autoSearchMemory: true
34+
35+# Writing files (config.go…) is enough to show the decisions being used; no
36+# bash, so the model cannot wander off grepping the session files.
37+yolo: true
38+bashTool: false
39+editTools: true
40+planTool: false
41+askUserTool: false
42+skillsDir: no-skills
43+
44+agentsMd:
45+ enabled: false
46+
47+sampling:
48+ temperature: 0.0
49+ parallel_tool_calls: false
50+ max_tokens: 2048
51+ chat_template_kwargs:
52+ enable_thinking: false
53+
54+maxTurns: 8
55+watchdogTimeout: 2m
56+firstTokenTimeout: 3m
57+displayCommands: true
58+
59+acp:
60+ name: bob
61+ title: 📚 Bob (bookshelf, with a memory)
62+
63+system: |
64+ Your name is Bob. You help build bookshelf, a small Go web app, in this
65+ directory. When the user asks you to write or create a file, call
66+ write_file with the whole content; do not only show the code.
67+
68+ Earlier conversations about this project are stored. When the user refers
69+ to something decided or said before ("the port we chose", "like last
70+ time", "what did we decide for…"), or asks how THIS project does
71+ something ("how do we handle…", "where are…", "which … do we use"), the
72+ answer is a choice made for this project (port, storage, schema, logs,
73+ errors, deployment…): call search_memory first with the key words, then
74+ answer from what it found and name the session it came from. Never
75+ invent a decision: if search_memory finds nothing, try other words once,
76+ then say you do not know.
77+
78+ For anything else (a greeting, a general Go question), answer directly,
79+ in the user's language, without search_memory.
added demos/memory-search/reset.sh +12 -0
new file mode 100755
@@ -0,0 +1,12 @@
1+#!/bin/sh
2+# reset.sh — puts the demo back as it ships: the four sessions of seed/ as the
3+# project's history, nothing else. Run it before the demo, and again to
4+# start over: every run adds its own session file, and the files the agent
5+# writes (*.go) are removed.
6+set -eu
7+cd "$(dirname "$0")"
8+rm -rf .mm
9+mkdir -p .mm/sessions
10+cp seed/*.json .mm/sessions/
11+rm -f ./*.go
12+echo "history reset: $(ls .mm/sessions | wc -l | tr -d ' ') stored session(s) in .mm/sessions"
new file mode 100755
@@ -0,0 +1,12 @@
1+#!/bin/sh
2+# reset.sh — puts the demo back as it ships: the four sessions of seed/ as the
3+# project's history, nothing else. Run it before the demo, and again to
4+# start over: every run adds its own session file, and the files the agent
5+# writes (*.go) are removed.
6+set -eu
7+cd "$(dirname "$0")"
8+rm -rf .mm
9+mkdir -p .mm/sessions
10+cp seed/*.json .mm/sessions/
11+rm -f ./*.go
12+echo "history reset: $(ls .mm/sessions | wc -l | tr -d ' ') stored session(s) in .mm/sessions"
added demos/memory-search/seed/20261005-091500-a1b2c3d4.json +48 -0
new file mode 100644
@@ -0,0 +1,48 @@
1+{
2+ "id": "20261005-091500-a1b2c3d4",
3+ "cwd": ".",
4+ "createdAt": "2026-10-05T09:15:00Z",
5+ "updatedAt": "2026-10-05T09:40:00Z",
6+ "messages": [
7+ {
8+ "role": "system",
9+ "content": [
10+ {
11+ "text": "You are Bob, the assistant of the bookshelf project."
12+ }
13+ ]
14+ },
15+ {
16+ "role": "user",
17+ "content": [
18+ {
19+ "text": "We start bookshelf, a small Go web app to track the books I read. Which port should the API server listen on?"
20+ }
21+ ]
22+ },
23+ {
24+ "role": "model",
25+ "content": [
26+ {
27+ "text": "Let's use port 8417 for the API server: 8080 is already taken by the admin UI on your machine, and 8417 is free and easy to remember."
28+ }
29+ ]
30+ },
31+ {
32+ "role": "user",
33+ "content": [
34+ {
35+ "text": "ok, keep 8417. And the module name?"
36+ }
37+ ]
38+ },
39+ {
40+ "role": "model",
41+ "content": [
42+ {
43+ "text": "Module `github.com/k33g/bookshelf`, Go 1.26, standard library only for the HTTP side (net/http with the 1.22 routing patterns)."
44+ }
45+ ]
46+ }
47+ ]
48+}
new file mode 100644
@@ -0,0 +1,48 @@
1+{
2+ "id": "20261005-091500-a1b2c3d4",
3+ "cwd": ".",
4+ "createdAt": "2026-10-05T09:15:00Z",
5+ "updatedAt": "2026-10-05T09:40:00Z",
6+ "messages": [
7+ {
8+ "role": "system",
9+ "content": [
10+ {
11+ "text": "You are Bob, the assistant of the bookshelf project."
12+ }
13+ ]
14+ },
15+ {
16+ "role": "user",
17+ "content": [
18+ {
19+ "text": "We start bookshelf, a small Go web app to track the books I read. Which port should the API server listen on?"
20+ }
21+ ]
22+ },
23+ {
24+ "role": "model",
25+ "content": [
26+ {
27+ "text": "Let's use port 8417 for the API server: 8080 is already taken by the admin UI on your machine, and 8417 is free and easy to remember."
28+ }
29+ ]
30+ },
31+ {
32+ "role": "user",
33+ "content": [
34+ {
35+ "text": "ok, keep 8417. And the module name?"
36+ }
37+ ]
38+ },
39+ {
40+ "role": "model",
41+ "content": [
42+ {
43+ "text": "Module `github.com/k33g/bookshelf`, Go 1.26, standard library only for the HTTP side (net/http with the 1.22 routing patterns)."
44+ }
45+ ]
46+ }
47+ ]
48+}
added demos/memory-search/seed/20261008-140000-b2c3d4e5.json +48 -0
new file mode 100644
@@ -0,0 +1,48 @@
1+{
2+ "id": "20261008-140000-b2c3d4e5",
3+ "cwd": ".",
4+ "createdAt": "2026-10-08T14:00:00Z",
5+ "updatedAt": "2026-10-08T14:35:00Z",
6+ "messages": [
7+ {
8+ "role": "system",
9+ "content": [
10+ {
11+ "text": "You are Bob, the assistant of the bookshelf project."
12+ }
13+ ]
14+ },
15+ {
16+ "role": "user",
17+ "content": [
18+ {
19+ "text": "Postgres or SQLite for the storage?"
20+ }
21+ ]
22+ },
23+ {
24+ "role": "model",
25+ "content": [
26+ {
27+ "text": "SQLite: one user, nothing to run beside the app. The file is data/bookshelf.db, opened with modernc.org/sqlite (pure Go, no cgo)."
28+ }
29+ ]
30+ },
31+ {
32+ "role": "user",
33+ "content": [
34+ {
35+ "text": "How do we handle schema changes?"
36+ }
37+ ]
38+ },
39+ {
40+ "role": "model",
41+ "content": [
42+ {
43+ "text": "Plain SQL files in migrations/, numbered: 001_init.sql, 002_add_rating.sql… applied in order at start-up, the last one applied stored in a schema_version table."
44+ }
45+ ]
46+ }
47+ ]
48+}
new file mode 100644
@@ -0,0 +1,48 @@
1+{
2+ "id": "20261008-140000-b2c3d4e5",
3+ "cwd": ".",
4+ "createdAt": "2026-10-08T14:00:00Z",
5+ "updatedAt": "2026-10-08T14:35:00Z",
6+ "messages": [
7+ {
8+ "role": "system",
9+ "content": [
10+ {
11+ "text": "You are Bob, the assistant of the bookshelf project."
12+ }
13+ ]
14+ },
15+ {
16+ "role": "user",
17+ "content": [
18+ {
19+ "text": "Postgres or SQLite for the storage?"
20+ }
21+ ]
22+ },
23+ {
24+ "role": "model",
25+ "content": [
26+ {
27+ "text": "SQLite: one user, nothing to run beside the app. The file is data/bookshelf.db, opened with modernc.org/sqlite (pure Go, no cgo)."
28+ }
29+ ]
30+ },
31+ {
32+ "role": "user",
33+ "content": [
34+ {
35+ "text": "How do we handle schema changes?"
36+ }
37+ ]
38+ },
39+ {
40+ "role": "model",
41+ "content": [
42+ {
43+ "text": "Plain SQL files in migrations/, numbered: 001_init.sql, 002_add_rating.sql… applied in order at start-up, the last one applied stored in a schema_version table."
44+ }
45+ ]
46+ }
47+ ]
48+}
added demos/memory-search/seed/20261012-101000-c3d4e5f6.json +48 -0
new file mode 100644
@@ -0,0 +1,48 @@
1+{
2+ "id": "20261012-101000-c3d4e5f6",
3+ "cwd": ".",
4+ "createdAt": "2026-10-12T10:10:00Z",
5+ "updatedAt": "2026-10-12T10:30:00Z",
6+ "messages": [
7+ {
8+ "role": "system",
9+ "content": [
10+ {
11+ "text": "You are Bob, the assistant of the bookshelf project."
12+ }
13+ ]
14+ },
15+ {
16+ "role": "user",
17+ "content": [
18+ {
19+ "text": "Quel format pour les logs ?"
20+ }
21+ ]
22+ },
23+ {
24+ "role": "model",
25+ "content": [
26+ {
27+ "text": "log/slog en JSON sur la sortie standard, niveau info par défaut ; BOOKSHELF_DEBUG=1 passe au niveau debug. Pas de fichier de log : c'est systemd qui les garde."
28+ }
29+ ]
30+ },
31+ {
32+ "role": "user",
33+ "content": [
34+ {
35+ "text": "Et les erreurs HTTP ?"
36+ }
37+ ]
38+ },
39+ {
40+ "role": "model",
41+ "content": [
42+ {
43+ "text": "Toujours un corps JSON {\"error\": \"…\"} avec le bon code ; jamais le texte d'une erreur Go interne vers le client — on la journalise, on renvoie un message générique."
44+ }
45+ ]
46+ }
47+ ]
48+}
new file mode 100644
@@ -0,0 +1,48 @@
1+{
2+ "id": "20261012-101000-c3d4e5f6",
3+ "cwd": ".",
4+ "createdAt": "2026-10-12T10:10:00Z",
5+ "updatedAt": "2026-10-12T10:30:00Z",
6+ "messages": [
7+ {
8+ "role": "system",
9+ "content": [
10+ {
11+ "text": "You are Bob, the assistant of the bookshelf project."
12+ }
13+ ]
14+ },
15+ {
16+ "role": "user",
17+ "content": [
18+ {
19+ "text": "Quel format pour les logs ?"
20+ }
21+ ]
22+ },
23+ {
24+ "role": "model",
25+ "content": [
26+ {
27+ "text": "log/slog en JSON sur la sortie standard, niveau info par défaut ; BOOKSHELF_DEBUG=1 passe au niveau debug. Pas de fichier de log : c'est systemd qui les garde."
28+ }
29+ ]
30+ },
31+ {
32+ "role": "user",
33+ "content": [
34+ {
35+ "text": "Et les erreurs HTTP ?"
36+ }
37+ ]
38+ },
39+ {
40+ "role": "model",
41+ "content": [
42+ {
43+ "text": "Toujours un corps JSON {\"error\": \"…\"} avec le bon code ; jamais le texte d'une erreur Go interne vers le client — on la journalise, on renvoie un message générique."
44+ }
45+ ]
46+ }
47+ ]
48+}
added demos/memory-search/seed/20261015-163000-d4e5f6a7.json +54 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/diagrams/packages.drawio +1 -1
@@ -1,3 +1,3 @@
11 <mxfile host="app.diagrams.net" modified="2026-10-06T00:00:00.000Z" agent="mm docs" version="24.0.0" type="device"><diagram id="packages" name="packages"><mxGraphModel dx="1400" dy="900" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1400" pageHeight="1060"><root><mxCell id="0" /><mxCell id="1" parent="0" /><mxCell id="main" value="&lt;b&gt;main (mm)&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;wiring: config, engine, tools, then one front end&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1"><mxGeometry x="420" y="40" width="200" height="60" as="geometry" /></mxCell><mxCell id="agent" value="&lt;b&gt;internal/agent&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal REPL: /quit /abort /compact /new&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="160" y="180" width="200" height="60" as="geometry" /></mxCell><mxCell id="acp" value="&lt;b&gt;internal/acp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;editor front end: Agent Client Protocol on stdio&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="700" y="180" width="200" height="60" as="geometry" /></mxCell><mxCell id="session" value="&lt;b&gt;internal/session&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;what a conversation starts from; the /new reset&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="compact" value="&lt;b&gt;internal/compact&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;history compression into a model-written summary&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="40" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="engine" value="&lt;b&gt;internal/engine&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;LLM connection + generation, one Provider per server&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="700" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="tools" value="&lt;b&gt;internal/tools&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;built-in tools: bash, read_skill, file tools, lsp, fetch_content; declared toolsbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content&lt;/font&gt;lt;/fontbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content&lt;/font&gt;gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="460" width="200" height="60" as="geometry" /></mxCell><mxCell id="detector" value="&lt;b&gt;internal/detector&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;repeated-action (loop) detection&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="40" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="config" value="&lt;b&gt;internal/config&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;settings with YAML overrides (agent.yaml)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="260" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="spinner" value="&lt;b&gt;internal/spinner&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal spinner and styling&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="480" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="ui" value="&lt;b&gt;internal/ui&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;human output destination + shared event sink&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="700" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="fileedit" value="&lt;b&gt;internal/fileedit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;exact-replacement file editing&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="920" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="skills" value="&lt;b&gt;internal/skills&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;markdown skills catalogue (./skills)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1140" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="genkit" value="&lt;b&gt;github.com/firebase/genkit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;ai.Message, tools, model calls&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="160" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="acpsdk" value="&lt;b&gt;github.com/coder/acp-go-sdk&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;JSON-RPC transport for ACP&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="700" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="openai" value="&lt;b&gt;github.com/openai/openai-go&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;OpenAI-compatible HTTP client&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="920" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="yaml" value="&lt;b&gt;gopkg.in/yaml.v3&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;YAML parsing&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="400" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="e0" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="agent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="version" value="&lt;b&gt;internal/version&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;which mm this is: build stamp, else the commit&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1380" y="600" width="200" height="60" as="geometry" /></mxCell>
22 <mxCell id="e61" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="version"><mxGeometry relative="1" as="geometry" /></mxCell>
3- <mxCell id="e1" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="acp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e2" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e3" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e4" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e5" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="skills"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e6" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e7" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="tools"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e8" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e9" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e10" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e11" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e12" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="acp" target="acpsdk"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e13" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="acp" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e14" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e15" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e16" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e17" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e18" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e19" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e20" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="agent" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e21" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="compact" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e22" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="compact" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e23" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="config" target="yaml"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e24" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e25" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e26" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e27" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="engine" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e28" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="engine" target="openai"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e29" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e30" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e31" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="fileedit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e32" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="skills"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e33" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e34" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e35" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="tools" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e36" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="session" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="mention" value="&lt;b&gt;internal/mention&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the @path notation of a question&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="400" width="200" height="60" as="geometry" /></mxCell><mxCell id="e37" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e38" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="store" value="&lt;b&gt;internal/store&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;per-project session files (.mm/sessions/&lt;id&gt;.json), the questions ↑ recalls&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="480" width="200" height="60" as="geometry" /></mxCell><mxCell id="e39" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e40" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="tui" value="&lt;b&gt;internal/tui&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;window front end: one screen on tcell (mm -tui)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="430" y="160" width="200" height="60" as="geometry" /></mxCell><mxCell id="command" value="&lt;b&gt;internal/command&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the one slash-command table, per front end&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="560" width="200" height="60" as="geometry" /></mxCell><mxCell id="tcell" value="&lt;b&gt;github.com/gdamore/tcell/v2&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal screen, keys, mouse&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="920" y="840" width="200" height="60" as="geometry" /></mxCell><mxCell id="e41" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="tui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e42" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e43" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e44" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e45" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e46" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e47" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e48" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e49" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e50" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e51" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="tcell"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e52" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e53" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e54" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="command" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="saved" value="&lt;b&gt;internal/saved&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;an answer to a new file: /save, save_answer&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="920" y="680" width="200" height="60" as="geometry" /></mxCell><mxCell id="e87" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e88" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e89" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="clipboard" value="&lt;b&gt;internal/clipboard&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;system clipboard: native tool, then OSC 52&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1140" y="680" width="200" height="60" as="geometry" /></mxCell><mxCell id="e55" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="clipboard"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e56" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="clipboard"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="lsp" value="&lt;b&gt;internal/lsp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;language-server client: definition, references, hover, symbols, diagnostics, rename&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1160" y="600" width="220" height="60" as="geometry" /></mxCell><mxCell id="lspdev" value="&lt;b&gt;go.lsp.dev/protocol + jsonrpc2&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;LSP types and JSON-RPC 2.0 over stdio&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1"><mxGeometry x="1160" y="700" width="220" height="60" as="geometry" /></mxCell><mxCell id="e57" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="lsp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e58" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="lsp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e59" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="lsp" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e60" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="lsp" target="lspdev"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="legend" value="&lt;b&gt;mm — package dependencies&lt;/b&gt;&lt;br/&gt;Arrow: &quot;imports&quot;. Yellow: entry point. Blue: front ends. Green: shared logic. Grey: leaf packages. Dashed purple: third-party modules.&lt;br/&gt;Regenerate the edge list from: go list -f '{{.ImportPath}}: {{join .Imports &quot; &quot;}}' ./..." style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=top;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1"><mxGeometry x="900" y="40" width="440" height="90" as="geometry" /></mxCell><mxCell id="webmd" value="&lt;b&gt;internal/webmd&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;web page → Markdown: fetch (robots.txt, charset → UTF-8), clean, convert&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1400" y="460" width="220" height="60" as="geometry" /></mxCell><mxCell id="xnet" value="&lt;b&gt;golang.org/x/net/html (+ x/text)&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;HTML5 parser, charset lookup&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="1400" y="760" width="220" height="60" as="geometry" /></mxCell><mxCell id="e_main_webmd" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="webmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_webmd" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="webmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_webmd_xnet" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="webmd" target="xnet"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="ask" value="&lt;b&gt;internal/ask&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;/ask another mm agent: child mm -acp, ACP client side&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="640" width="200" height="60" as="geometry" /></mxCell><mxCell id="e_main_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_agent_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_acp_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tui_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_command" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_compact" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_ui" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_acpsdk" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="acpsdk"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_genkit" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_yaml" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="yaml"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="consent" value="&lt;b&gt;internal/consent&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;yolo switch, the four answers, per-session memory, the line mode prompt hook&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="700" y="500" width="200" height="60" as="geometry" /></mxCell><mxCell id="mcp" value="&lt;b&gt;internal/mcp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;MCP clients (stdio, HTTP), their tools wrapped as mm tools&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1400" y="560" width="200" height="60" as="geometry" /></mxCell><mxCell id="e62" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="consent" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e63" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="consent" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e64" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e65" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e66" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e67" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e68" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e69" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e70" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e71" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e72" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e73" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="mcp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e74" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="mcp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="structured" value="&lt;b&gt;internal/structured&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;structuredOutput: Go declarations → JSON Schema (go/parser)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="260" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e75" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="config" target="structured"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="agentsmd" value="&lt;b&gt;internal/agentsmd&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the project's AGENTS.md, appended to the system prompt per conversation&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="520.0" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e76" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e77" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e78" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e79" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e80" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agentsmd" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="elicit" value="&lt;b&gt;internal/elicit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;ask_user's questions and answers: normalize, line answers, elicitation form schema&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="780.0" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e81" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ui" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e82" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e83" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e84" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e85" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e86" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="hooks" value="&lt;b&gt;internal/hooks&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the hooks: block — runs each hook (sh -c, JSON on stdin/stdout), chain, onError&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="940" y="400" width="200" height="60" as="geometry" /></mxCell><mxCell id="e_engine_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_main_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_agent_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tui_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_acp_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_hooks_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="hooks" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_session" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_compact" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_engine" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell></root></mxGraphModel></diagram></mxfile>
\ No newline at end of file
3+ <mxCell id="e1" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="acp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e2" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e3" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e4" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e5" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="skills"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e6" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e7" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="tools"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e8" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e9" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e10" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e11" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e12" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="acp" target="acpsdk"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e13" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="acp" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e14" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e15" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e16" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e17" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e18" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e19" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e20" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="agent" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e21" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="compact" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e22" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="compact" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e23" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="config" target="yaml"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e24" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e25" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e26" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e27" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="engine" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e28" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="engine" target="openai"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e29" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e30" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e31" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="fileedit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e32" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="skills"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e33" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e34" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e35" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="tools" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e36" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="session" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="mention" value="&lt;b&gt;internal/mention&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the @path notation of a question&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="400" width="200" height="60" as="geometry" /></mxCell><mxCell id="e37" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e38" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="store" value="&lt;b&gt;internal/store&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;per-project session files (.mm/sessions/&lt;id&gt;.json), the questions ↑ recalls, /memory and search_memory&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="480" width="200" height="60" as="geometry" /></mxCell><mxCell id="e39" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e40" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="tui" value="&lt;b&gt;internal/tui&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;window front end: one screen on tcell (mm -tui)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="430" y="160" width="200" height="60" as="geometry" /></mxCell><mxCell id="command" value="&lt;b&gt;internal/command&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the one slash-command table, per front end&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="560" width="200" height="60" as="geometry" /></mxCell><mxCell id="tcell" value="&lt;b&gt;github.com/gdamore/tcell/v2&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal screen, keys, mouse&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="920" y="840" width="200" height="60" as="geometry" /></mxCell><mxCell id="e41" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="tui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e42" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e43" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e44" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e45" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e46" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e47" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e48" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e49" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e50" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e51" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="tcell"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e52" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e53" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e54" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="command" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="saved" value="&lt;b&gt;internal/saved&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;an answer to a new file: /save, save_answer&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="920" y="680" width="200" height="60" as="geometry" /></mxCell><mxCell id="e87" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e88" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e89" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="clipboard" value="&lt;b&gt;internal/clipboard&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;system clipboard: native tool, then OSC 52&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1140" y="680" width="200" height="60" as="geometry" /></mxCell><mxCell id="e55" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="clipboard"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e56" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="clipboard"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="lsp" value="&lt;b&gt;internal/lsp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;language-server client: definition, references, hover, symbols, diagnostics, rename&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1160" y="600" width="220" height="60" as="geometry" /></mxCell><mxCell id="lspdev" value="&lt;b&gt;go.lsp.dev/protocol + jsonrpc2&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;LSP types and JSON-RPC 2.0 over stdio&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1"><mxGeometry x="1160" y="700" width="220" height="60" as="geometry" /></mxCell><mxCell id="e57" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="lsp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e58" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="lsp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e59" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="lsp" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e60" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="lsp" target="lspdev"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="legend" value="&lt;b&gt;mm — package dependencies&lt;/b&gt;&lt;br/&gt;Arrow: &quot;imports&quot;. Yellow: entry point. Blue: front ends. Green: shared logic. Grey: leaf packages. Dashed purple: third-party modules.&lt;br/&gt;Regenerate the edge list from: go list -f '{{.ImportPath}}: {{join .Imports &quot; &quot;}}' ./..." style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=top;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1"><mxGeometry x="900" y="40" width="440" height="90" as="geometry" /></mxCell><mxCell id="webmd" value="&lt;b&gt;internal/webmd&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;web page → Markdown: fetch (robots.txt, charset → UTF-8), clean, convert&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1400" y="460" width="220" height="60" as="geometry" /></mxCell><mxCell id="xnet" value="&lt;b&gt;golang.org/x/net/html (+ x/text)&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;HTML5 parser, charset lookup&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="1400" y="760" width="220" height="60" as="geometry" /></mxCell><mxCell id="e_main_webmd" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="webmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_webmd" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="webmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_webmd_xnet" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="webmd" target="xnet"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="ask" value="&lt;b&gt;internal/ask&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;/ask another mm agent: child mm -acp, ACP client side&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="640" width="200" height="60" as="geometry" /></mxCell><mxCell id="e_main_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_agent_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_acp_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tui_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_command" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_compact" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_ui" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_acpsdk" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="acpsdk"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_genkit" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_yaml" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="yaml"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="consent" value="&lt;b&gt;internal/consent&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;yolo switch, the four answers, per-session memory, the line mode prompt hook&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="700" y="500" width="200" height="60" as="geometry" /></mxCell><mxCell id="mcp" value="&lt;b&gt;internal/mcp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;MCP clients (stdio, HTTP), their tools wrapped as mm tools&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1400" y="560" width="200" height="60" as="geometry" /></mxCell><mxCell id="e62" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="consent" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e63" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="consent" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e64" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e65" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e66" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e67" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e68" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e69" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e70" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e71" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e72" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e73" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="mcp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e74" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="mcp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="structured" value="&lt;b&gt;internal/structured&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;structuredOutput: Go declarations → JSON Schema (go/parser)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="260" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e75" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="config" target="structured"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="agentsmd" value="&lt;b&gt;internal/agentsmd&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the project's AGENTS.md, appended to the system prompt per conversation&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="520.0" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e76" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e77" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e78" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e79" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e80" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agentsmd" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="elicit" value="&lt;b&gt;internal/elicit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;ask_user's questions and answers: normalize, line answers, elicitation form schema&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="780.0" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e81" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ui" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e82" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e83" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e84" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e85" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e86" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="hooks" value="&lt;b&gt;internal/hooks&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the hooks: block — runs each hook (sh -c, JSON on stdin/stdout), chain, onError&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="940" y="400" width="200" height="60" as="geometry" /></mxCell><mxCell id="e_engine_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_main_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_agent_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tui_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_acp_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_hooks_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="hooks" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_session" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_compact" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_engine" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_store" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="store"><mxGeometry relative="1" as="geometry" /></mxCell></root></mxGraphModel></diagram></mxfile>
\ No newline at end of file
@@ -1,3 +1,3 @@
1 <mxfile host="app.diagrams.net" modified="2026-10-06T00:00:00.000Z" agent="mm docs" version="24.0.0" type="device"><diagram id="packages" name="packages"><mxGraphModel dx="1400" dy="900" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1400" pageHeight="1060"><root><mxCell id="0" /><mxCell id="1" parent="0" /><mxCell id="main" value="&lt;b&gt;main (mm)&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;wiring: config, engine, tools, then one front end&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1"><mxGeometry x="420" y="40" width="200" height="60" as="geometry" /></mxCell><mxCell id="agent" value="&lt;b&gt;internal/agent&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal REPL: /quit /abort /compact /new&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="160" y="180" width="200" height="60" as="geometry" /></mxCell><mxCell id="acp" value="&lt;b&gt;internal/acp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;editor front end: Agent Client Protocol on stdio&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="700" y="180" width="200" height="60" as="geometry" /></mxCell><mxCell id="session" value="&lt;b&gt;internal/session&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;what a conversation starts from; the /new reset&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="compact" value="&lt;b&gt;internal/compact&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;history compression into a model-written summary&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="40" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="engine" value="&lt;b&gt;internal/engine&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;LLM connection + generation, one Provider per server&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="700" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="tools" value="&lt;b&gt;internal/tools&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;built-in tools: bash, read_skill, file tools, lsp, fetch_content; declared toolsbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content&lt;/font&gt;lt;/fontbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content&lt;/font&gt;gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="460" width="200" height="60" as="geometry" /></mxCell><mxCell id="detector" value="&lt;b&gt;internal/detector&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;repeated-action (loop) detection&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="40" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="config" value="&lt;b&gt;internal/config&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;settings with YAML overrides (agent.yaml)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="260" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="spinner" value="&lt;b&gt;internal/spinner&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal spinner and styling&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="480" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="ui" value="&lt;b&gt;internal/ui&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;human output destination + shared event sink&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="700" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="fileedit" value="&lt;b&gt;internal/fileedit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;exact-replacement file editing&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="920" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="skills" value="&lt;b&gt;internal/skills&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;markdown skills catalogue (./skills)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1140" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="genkit" value="&lt;b&gt;github.com/firebase/genkit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;ai.Message, tools, model calls&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="160" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="acpsdk" value="&lt;b&gt;github.com/coder/acp-go-sdk&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;JSON-RPC transport for ACP&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="700" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="openai" value="&lt;b&gt;github.com/openai/openai-go&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;OpenAI-compatible HTTP client&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="920" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="yaml" value="&lt;b&gt;gopkg.in/yaml.v3&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;YAML parsing&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="400" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="e0" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="agent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="version" value="&lt;b&gt;internal/version&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;which mm this is: build stamp, else the commit&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1380" y="600" width="200" height="60" as="geometry" /></mxCell>1 <mxfile host="app.diagrams.net" modified="2026-10-06T00:00:00.000Z" agent="mm docs" version="24.0.0" type="device"><diagram id="packages" name="packages"><mxGraphModel dx="1400" dy="900" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1400" pageHeight="1060"><root><mxCell id="0" /><mxCell id="1" parent="0" /><mxCell id="main" value="&lt;b&gt;main (mm)&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;wiring: config, engine, tools, then one front end&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1"><mxGeometry x="420" y="40" width="200" height="60" as="geometry" /></mxCell><mxCell id="agent" value="&lt;b&gt;internal/agent&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal REPL: /quit /abort /compact /new&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="160" y="180" width="200" height="60" as="geometry" /></mxCell><mxCell id="acp" value="&lt;b&gt;internal/acp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;editor front end: Agent Client Protocol on stdio&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="700" y="180" width="200" height="60" as="geometry" /></mxCell><mxCell id="session" value="&lt;b&gt;internal/session&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;what a conversation starts from; the /new reset&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="compact" value="&lt;b&gt;internal/compact&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;history compression into a model-written summary&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="40" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="engine" value="&lt;b&gt;internal/engine&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;LLM connection + generation, one Provider per server&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="700" y="320" width="200" height="60" as="geometry" /></mxCell><mxCell id="tools" value="&lt;b&gt;internal/tools&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;built-in tools: bash, read_skill, file tools, lsp, fetch_content; declared toolsbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content&lt;/font&gt;lt;/fontbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content&lt;/font&gt;gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="460" width="200" height="60" as="geometry" /></mxCell><mxCell id="detector" value="&lt;b&gt;internal/detector&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;repeated-action (loop) detection&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="40" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="config" value="&lt;b&gt;internal/config&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;settings with YAML overrides (agent.yaml)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="260" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="spinner" value="&lt;b&gt;internal/spinner&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal spinner and styling&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="480" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="ui" value="&lt;b&gt;internal/ui&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;human output destination + shared event sink&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="700" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="fileedit" value="&lt;b&gt;internal/fileedit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;exact-replacement file editing&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="920" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="skills" value="&lt;b&gt;internal/skills&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;markdown skills catalogue (./skills)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1140" y="600" width="200" height="60" as="geometry" /></mxCell><mxCell id="genkit" value="&lt;b&gt;github.com/firebase/genkit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;ai.Message, tools, model calls&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="160" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="acpsdk" value="&lt;b&gt;github.com/coder/acp-go-sdk&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;JSON-RPC transport for ACP&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="700" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="openai" value="&lt;b&gt;github.com/openai/openai-go&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;OpenAI-compatible HTTP client&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="920" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="yaml" value="&lt;b&gt;gopkg.in/yaml.v3&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;YAML parsing&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="400" y="760" width="200" height="60" as="geometry" /></mxCell><mxCell id="e0" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="agent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="version" value="&lt;b&gt;internal/version&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;which mm this is: build stamp, else the commit&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1380" y="600" width="200" height="60" as="geometry" /></mxCell>
2 <mxCell id="e61" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="version"><mxGeometry relative="1" as="geometry" /></mxCell>2 <mxCell id="e61" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="version"><mxGeometry relative="1" as="geometry" /></mxCell>
3- <mxCell id="e1" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="acp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e2" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e3" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e4" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e5" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="skills"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e6" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e7" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="tools"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e8" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e9" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e10" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e11" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e12" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="acp" target="acpsdk"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e13" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="acp" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e14" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e15" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e16" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e17" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e18" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e19" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e20" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="agent" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e21" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="compact" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e22" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="compact" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e23" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="config" target="yaml"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e24" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e25" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e26" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e27" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="engine" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e28" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="engine" target="openai"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e29" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e30" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e31" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="fileedit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e32" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="skills"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e33" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e34" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e35" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="tools" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e36" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="session" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="mention" value="&lt;b&gt;internal/mention&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the @path notation of a question&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="400" width="200" height="60" as="geometry" /></mxCell><mxCell id="e37" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e38" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="store" value="&lt;b&gt;internal/store&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;per-project session files (.mm/sessions/&lt;id&gt;.json), the questions ↑ recalls&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="480" width="200" height="60" as="geometry" /></mxCell><mxCell id="e39" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e40" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="tui" value="&lt;b&gt;internal/tui&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;window front end: one screen on tcell (mm -tui)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="430" y="160" width="200" height="60" as="geometry" /></mxCell><mxCell id="command" value="&lt;b&gt;internal/command&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the one slash-command table, per front end&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="560" width="200" height="60" as="geometry" /></mxCell><mxCell id="tcell" value="&lt;b&gt;github.com/gdamore/tcell/v2&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal screen, keys, mouse&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="920" y="840" width="200" height="60" as="geometry" /></mxCell><mxCell id="e41" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="tui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e42" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e43" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e44" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e45" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e46" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e47" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e48" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e49" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e50" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e51" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="tcell"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e52" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e53" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e54" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="command" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="saved" value="&lt;b&gt;internal/saved&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;an answer to a new file: /save, save_answer&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="920" y="680" width="200" height="60" as="geometry" /></mxCell><mxCell id="e87" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e88" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e89" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="clipboard" value="&lt;b&gt;internal/clipboard&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;system clipboard: native tool, then OSC 52&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1140" y="680" width="200" height="60" as="geometry" /></mxCell><mxCell id="e55" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="clipboard"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e56" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="clipboard"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="lsp" value="&lt;b&gt;internal/lsp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;language-server client: definition, references, hover, symbols, diagnostics, rename&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1160" y="600" width="220" height="60" as="geometry" /></mxCell><mxCell id="lspdev" value="&lt;b&gt;go.lsp.dev/protocol + jsonrpc2&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;LSP types and JSON-RPC 2.0 over stdio&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1"><mxGeometry x="1160" y="700" width="220" height="60" as="geometry" /></mxCell><mxCell id="e57" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="lsp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e58" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="lsp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e59" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="lsp" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e60" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="lsp" target="lspdev"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="legend" value="&lt;b&gt;mm — package dependencies&lt;/b&gt;&lt;br/&gt;Arrow: &quot;imports&quot;. Yellow: entry point. Blue: front ends. Green: shared logic. Grey: leaf packages. Dashed purple: third-party modules.&lt;br/&gt;Regenerate the edge list from: go list -f '{{.ImportPath}}: {{join .Imports &quot; &quot;}}' ./..." style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=top;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1"><mxGeometry x="900" y="40" width="440" height="90" as="geometry" /></mxCell><mxCell id="webmd" value="&lt;b&gt;internal/webmd&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;web page → Markdown: fetch (robots.txt, charset → UTF-8), clean, convert&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1400" y="460" width="220" height="60" as="geometry" /></mxCell><mxCell id="xnet" value="&lt;b&gt;golang.org/x/net/html (+ x/text)&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;HTML5 parser, charset lookup&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="1400" y="760" width="220" height="60" as="geometry" /></mxCell><mxCell id="e_main_webmd" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="webmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_webmd" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="webmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_webmd_xnet" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="webmd" target="xnet"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="ask" value="&lt;b&gt;internal/ask&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;/ask another mm agent: child mm -acp, ACP client side&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="640" width="200" height="60" as="geometry" /></mxCell><mxCell id="e_main_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_agent_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_acp_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tui_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_command" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_compact" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_ui" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_acpsdk" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="acpsdk"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_genkit" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_yaml" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="yaml"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="consent" value="&lt;b&gt;internal/consent&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;yolo switch, the four answers, per-session memory, the line mode prompt hook&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="700" y="500" width="200" height="60" as="geometry" /></mxCell><mxCell id="mcp" value="&lt;b&gt;internal/mcp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;MCP clients (stdio, HTTP), their tools wrapped as mm tools&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1400" y="560" width="200" height="60" as="geometry" /></mxCell><mxCell id="e62" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="consent" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e63" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="consent" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e64" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e65" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e66" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e67" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e68" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e69" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e70" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e71" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e72" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e73" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="mcp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e74" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="mcp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="structured" value="&lt;b&gt;internal/structured&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;structuredOutput: Go declarations → JSON Schema (go/parser)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="260" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e75" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="config" target="structured"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="agentsmd" value="&lt;b&gt;internal/agentsmd&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the project's AGENTS.md, appended to the system prompt per conversation&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="520.0" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e76" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e77" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e78" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e79" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e80" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agentsmd" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="elicit" value="&lt;b&gt;internal/elicit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;ask_user's questions and answers: normalize, line answers, elicitation form schema&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="780.0" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e81" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ui" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e82" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e83" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e84" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e85" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e86" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="hooks" value="&lt;b&gt;internal/hooks&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the hooks: block — runs each hook (sh -c, JSON on stdin/stdout), chain, onError&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="940" y="400" width="200" height="60" as="geometry" /></mxCell><mxCell id="e_engine_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_main_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_agent_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tui_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_acp_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_hooks_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="hooks" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_session" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_compact" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_engine" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell></root></mxGraphModel></diagram></mxfile>
\ No newline at end of file\ No newline at end of file
3+ <mxCell id="e1" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="acp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e2" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e3" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e4" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e5" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="skills"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e6" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e7" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="tools"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e8" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e9" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e10" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e11" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e12" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="acp" target="acpsdk"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e13" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="acp" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e14" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e15" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e16" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e17" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e18" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e19" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e20" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="agent" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e21" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="compact" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e22" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="compact" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e23" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="config" target="yaml"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e24" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e25" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e26" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e27" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="engine" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e28" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="engine" target="openai"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e29" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e30" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e31" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="fileedit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e32" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="skills"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e33" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="spinner"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e34" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e35" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="tools" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e36" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="session" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="mention" value="&lt;b&gt;internal/mention&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the @path notation of a question&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="400" width="200" height="60" as="geometry" /></mxCell><mxCell id="e37" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e38" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="store" value="&lt;b&gt;internal/store&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;per-project session files (.mm/sessions/&lt;id&gt;.json), the questions ↑ recalls, /memory and search_memory&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="480" width="200" height="60" as="geometry" /></mxCell><mxCell id="e39" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e40" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="tui" value="&lt;b&gt;internal/tui&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;window front end: one screen on tcell (mm -tui)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry x="430" y="160" width="200" height="60" as="geometry" /></mxCell><mxCell id="command" value="&lt;b&gt;internal/command&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the one slash-command table, per front end&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="560" width="200" height="60" as="geometry" /></mxCell><mxCell id="tcell" value="&lt;b&gt;github.com/gdamore/tcell/v2&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;terminal screen, keys, mouse&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="920" y="840" width="200" height="60" as="geometry" /></mxCell><mxCell id="e41" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="tui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e42" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e43" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e44" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e45" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="store"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e46" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="mention"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e47" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e48" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e49" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e50" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e51" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="tcell"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e52" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e53" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e54" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="command" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="saved" value="&lt;b&gt;internal/saved&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;an answer to a new file: /save, save_answer&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="920" y="680" width="200" height="60" as="geometry" /></mxCell><mxCell id="e87" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e88" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e89" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="saved"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="clipboard" value="&lt;b&gt;internal/clipboard&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;system clipboard: native tool, then OSC 52&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1140" y="680" width="200" height="60" as="geometry" /></mxCell><mxCell id="e55" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="clipboard"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e56" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="clipboard"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="lsp" value="&lt;b&gt;internal/lsp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;language-server client: definition, references, hover, symbols, diagnostics, rename&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1160" y="600" width="220" height="60" as="geometry" /></mxCell><mxCell id="lspdev" value="&lt;b&gt;go.lsp.dev/protocol + jsonrpc2&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;LSP types and JSON-RPC 2.0 over stdio&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1"><mxGeometry x="1160" y="700" width="220" height="60" as="geometry" /></mxCell><mxCell id="e57" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="lsp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e58" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="lsp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e59" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="lsp" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e60" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="lsp" target="lspdev"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="legend" value="&lt;b&gt;mm — package dependencies&lt;/b&gt;&lt;br/&gt;Arrow: &quot;imports&quot;. Yellow: entry point. Blue: front ends. Green: shared logic. Grey: leaf packages. Dashed purple: third-party modules.&lt;br/&gt;Regenerate the edge list from: go list -f '{{.ImportPath}}: {{join .Imports &quot; &quot;}}' ./..." style="text;html=1;whiteSpace=wrap;align=left;verticalAlign=top;fillColor=#ffffff;strokeColor=#999999;" vertex="1" parent="1"><mxGeometry x="900" y="40" width="440" height="90" as="geometry" /></mxCell><mxCell id="webmd" value="&lt;b&gt;internal/webmd&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;web page → Markdown: fetch (robots.txt, charset → UTF-8), clean, convert&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1400" y="460" width="220" height="60" as="geometry" /></mxCell><mxCell id="xnet" value="&lt;b&gt;golang.org/x/net/html (+ x/text)&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;HTML5 parser, charset lookup&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"><mxGeometry x="1400" y="760" width="220" height="60" as="geometry" /></mxCell><mxCell id="e_main_webmd" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="webmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_webmd" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="webmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_webmd_xnet" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="webmd" target="xnet"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="ask" value="&lt;b&gt;internal/ask&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;/ask another mm agent: child mm -acp, ACP client side&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="430" y="640" width="200" height="60" as="geometry" /></mxCell><mxCell id="e_main_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_agent_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_acp_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tui_ask" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="ask"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_command" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="command"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_compact" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_ui" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_acpsdk" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="acpsdk"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_genkit" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="genkit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_yaml" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;dashed=1;" edge="1" parent="1" source="ask" target="yaml"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="consent" value="&lt;b&gt;internal/consent&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;yolo switch, the four answers, per-session memory, the line mode prompt hook&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="700" y="500" width="200" height="60" as="geometry" /></mxCell><mxCell id="mcp" value="&lt;b&gt;internal/mcp&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;MCP clients (stdio, HTTP), their tools wrapped as mm tools&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="1400" y="560" width="200" height="60" as="geometry" /></mxCell><mxCell id="e62" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="consent" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e63" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="consent" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e64" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e65" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e66" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e67" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e68" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e69" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="consent"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e70" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e71" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="ui"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e72" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="mcp" target="detector"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e73" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="mcp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e74" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="mcp"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="structured" value="&lt;b&gt;internal/structured&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;structuredOutput: Go declarations → JSON Schema (go/parser)&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="260" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e75" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="config" target="structured"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="agentsmd" value="&lt;b&gt;internal/agentsmd&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the project's AGENTS.md, appended to the system prompt per conversation&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="520.0" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e76" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e77" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e78" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e79" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="agentsmd"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e80" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agentsmd" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="elicit" value="&lt;b&gt;internal/elicit&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;ask_user's questions and answers: normalize, line answers, elicitation form schema&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1"><mxGeometry x="780.0" y="940.0" width="200" height="60" as="geometry" /></mxCell><mxCell id="e81" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ui" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e82" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e83" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e84" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e85" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e86" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="elicit"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="hooks" value="&lt;b&gt;internal/hooks&lt;/b&gt;&lt;br/&gt;&lt;font style=&quot;font-size:10px&quot;&gt;the hooks: block — runs each hook (sh -c, JSON on stdin/stdout), chain, onError&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry x="940" y="400" width="200" height="60" as="geometry" /></mxCell><mxCell id="e_engine_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="engine" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_ask_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="ask" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_main_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="main" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_agent_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="agent" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tui_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tui" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_acp_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="acp" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_hooks_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="hooks" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_config" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="config"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_session" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="session"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_compact" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="compact"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_engine" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="engine"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_store_hooks" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="store" target="hooks"><mxGeometry relative="1" as="geometry" /></mxCell><mxCell id="e_tools_store" style="endArrow=block;html=1;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="tools" target="store"><mxGeometry relative="1" as="geometry" /></mxCell></root></mxGraphModel></diagram></mxfile>
\ No newline at end of file\ No newline at end of file
modified docs/en/README.md +1 -0
@@ -27,6 +27,7 @@ This documentation is organised along the four [Diátaxis](https://diataxis.fr)
2727 - [Add a skill](how-to/add-a-skill.md)
2828 - [Declare a custom tool](how-to/declare-a-custom-tool.md)
2929 - [Save an answer to a file](how-to/save-an-answer.md)
30+- [Search earlier sessions](how-to/search-earlier-sessions.md) — `/memory <words>`, the `search_memory` tool, `sessions.searchMemory` / `sessions.autoSearchMemory`
3031 - [Free a model's memory](how-to/unload-a-model.md) — `/unload [model]` in every front end, the `unload_model` tool after another agent's answer, `unloadModels`
3132 - [Measure whether the model picks the right skill](how-to/measure-skill-routing.md) — the routing eval: run it, read its table, use it as a before-and-after
3233 - [Keep a long session inside the context window](how-to/manage-the-context-window.md)
@@ -27,6 +27,7 @@ This documentation is organised along the four [Diátaxis](https://diataxis.fr)
27 - [Add a skill](how-to/add-a-skill.md)27 - [Add a skill](how-to/add-a-skill.md)
28 - [Declare a custom tool](how-to/declare-a-custom-tool.md)28 - [Declare a custom tool](how-to/declare-a-custom-tool.md)
29 - [Save an answer to a file](how-to/save-an-answer.md)29 - [Save an answer to a file](how-to/save-an-answer.md)
30+- [Search earlier sessions](how-to/search-earlier-sessions.md) — `/memory <words>`, the `search_memory` tool, `sessions.searchMemory` / `sessions.autoSearchMemory`
30 - [Free a model's memory](how-to/unload-a-model.md) — `/unload [model]` in every front end, the `unload_model` tool after another agent's answer, `unloadModels`31 - [Free a model's memory](how-to/unload-a-model.md) — `/unload [model]` in every front end, the `unload_model` tool after another agent's answer, `unloadModels`
31 - [Measure whether the model picks the right skill](how-to/measure-skill-routing.md) — the routing eval: run it, read its table, use it as a before-and-after32 - [Measure whether the model picks the right skill](how-to/measure-skill-routing.md) — the routing eval: run it, read its table, use it as a before-and-after
32 - [Keep a long session inside the context window](how-to/manage-the-context-window.md)33 - [Keep a long session inside the context window](how-to/manage-the-context-window.md)
modified docs/en/explanation/persistent-sessions.md +11 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/en/how-to/keep-sessions.md +1 -0
@@ -95,6 +95,7 @@ This guide shows how to make `mm` save every conversation of a project and get o
9595 - **Compression.** A `/compact` or an automatic compression rewrites the file with the shortened history; a resumed or reloaded session starts from the summary, like the live one did. The `errors` array is left as it is.
9696 - **Errors over ACP.** The editor shows the failure in its own way; the record still goes to the thread's file, and `/new` moves it to the archived conversation with the history it belongs to.
9797 - **Ask an earlier question again (window).** In `mm -tui`, ↑ on the box's first row recalls the questions of this session, then of the earlier ones. See [Recall an earlier question](use-the-window-mode.md#recall-an-earlier-question).
98+- **Search what was said before.** `/memory <words>` (with `sessions.searchMemory`) and the model's `search_memory` tool (with `sessions.autoSearchMemory`). See [Search earlier sessions](search-earlier-sessions.md).
9899 - **Starting fresh on purpose.** Nothing to do: every start is a new session. The old ones only come back on `/resume` or on an editor reload.
99100
100101 ## See also
@@ -95,6 +95,7 @@ This guide shows how to make `mm` save every conversation of a project and get o
95 - **Compression.** A `/compact` or an automatic compression rewrites the file with the shortened history; a resumed or reloaded session starts from the summary, like the live one did. The `errors` array is left as it is.95 - **Compression.** A `/compact` or an automatic compression rewrites the file with the shortened history; a resumed or reloaded session starts from the summary, like the live one did. The `errors` array is left as it is.
96 - **Errors over ACP.** The editor shows the failure in its own way; the record still goes to the thread's file, and `/new` moves it to the archived conversation with the history it belongs to.96 - **Errors over ACP.** The editor shows the failure in its own way; the record still goes to the thread's file, and `/new` moves it to the archived conversation with the history it belongs to.
97 - **Ask an earlier question again (window).** In `mm -tui`, ↑ on the box's first row recalls the questions of this session, then of the earlier ones. See [Recall an earlier question](use-the-window-mode.md#recall-an-earlier-question).97 - **Ask an earlier question again (window).** In `mm -tui`, ↑ on the box's first row recalls the questions of this session, then of the earlier ones. See [Recall an earlier question](use-the-window-mode.md#recall-an-earlier-question).
98+- **Search what was said before.** `/memory <words>` (with `sessions.searchMemory`) and the model's `search_memory` tool (with `sessions.autoSearchMemory`). See [Search earlier sessions](search-earlier-sessions.md).
98 - **Starting fresh on purpose.** Nothing to do: every start is a new session. The old ones only come back on `/resume` or on an editor reload.99 - **Starting fresh on purpose.** Nothing to do: every start is a new session. The old ones only come back on `/resume` or on an editor reload.
99 100
100 ## See also101 ## See also
added docs/en/how-to/search-earlier-sessions.md +59 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/en/reference/acp.md +1 -0
@@ -159,6 +159,7 @@ When mm is the **client** — an agent asking another one through `/ask`, `ask_a
159159 | `read` | `read` | `read_skill`, `read_file` |
160160 | `edit` | `edit` | `write_file`, `edit_file` |
161161 | `fetch` | `fetch` | `fetch_content` |
162+| `search` | `search` | `search_memory` |
162163 | `other` | `other` | `ask_agent`, `ask_user` |
163164
164165 ## Tool call identifiers
@@ -159,6 +159,7 @@ When mm is the **client** — an agent asking another one through `/ask`, `ask_a
159 | `read` | `read` | `read_skill`, `read_file` |159 | `read` | `read` | `read_skill`, `read_file` |
160 | `edit` | `edit` | `write_file`, `edit_file` |160 | `edit` | `edit` | `write_file`, `edit_file` |
161 | `fetch` | `fetch` | `fetch_content` |161 | `fetch` | `fetch` | `fetch_content` |
162+| `search` | `search` | `search_memory` |
162 | `other` | `other` | `ask_agent`, `ask_user` |163 | `other` | `other` | `ask_agent`, `ask_user` |
163 164
164 ## Tool call identifiers165 ## Tool call identifiers
modified docs/en/reference/configuration.md +5 -1
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/en/reference/slash-commands.md +3 -1
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/en/reference/tools.md +21 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/fr/README.md +1 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/fr/explanation/persistent-sessions.md +11 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/fr/how-to/keep-sessions.md +1 -0
Large diff collapsed to keep the page fast — load it when you need it.
added docs/fr/how-to/search-earlier-sessions.md +59 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/fr/reference/acp.md +1 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/fr/reference/configuration.md +5 -1
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/fr/reference/slash-commands.md +3 -1
Large diff collapsed to keep the page fast — load it when you need it.
modified docs/fr/reference/tools.md +21 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/acp/acp.go +17 -1
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/acp/acp_test.go +1 -0
Large diff collapsed to keep the page fast — load it when you need it.
added internal/acp/memory_test.go +61 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/acp/sink.go +2 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/agent/agent.go +47 -30
Large diff collapsed to keep the page fast — load it when you need it.
added internal/agent/input_test.go +55 -0
Large diff collapsed to keep the page fast — load it when you need it.
added internal/agent/memory_test.go +56 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/command/command.go +2 -1
Large diff collapsed to keep the page fast — load it when you need it.
added internal/command/memory.go +24 -0
Large diff collapsed to keep the page fast — load it when you need it.
added internal/command/memory_test.go +27 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/compact/compact.go +20 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/compact/compact_test.go +16 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/compact/prompt.go +4 -1
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/config/config.go +31 -0
Large diff collapsed to keep the page fast — load it when you need it.
added internal/config/memory_test.go +42 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/config/tools.go +1 -0
Large diff collapsed to keep the page fast — load it when you need it.
added internal/store/search.go +354 -0
Large diff collapsed to keep the page fast — load it when you need it.
added internal/store/search_test.go +216 -0
Large diff collapsed to keep the page fast — load it when you need it.
added internal/tools/searchmemory.go +77 -0
Large diff collapsed to keep the page fast — load it when you need it.
added internal/tools/searchmemory_test.go +66 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/tui/commands.go +2 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/tui/turn_test.go +26 -0
Large diff collapsed to keep the page fast — load it when you need it.
modified internal/ui/ui.go +1 -1
Large diff collapsed to keep the page fast — load it when you need it.
modified main.go +9 -0
Large diff collapsed to keep the page fast — load it when you need it.
added memory_assemble_test.go +43 -0
Large diff collapsed to keep the page fast — load it when you need it.