Memory search #36
Merged@k33g wants to merge
feature/memory-search into mainMerged 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 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 48 |
| 3 | 3 | title: Add a builtin tool to search into the mm sessions |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-09-27T03:45:48.121Z |
| 9 | -updatedAt: 2026-10-20T05:44:21.627Z | |
| 9 | +updatedAt: 2026-10-20T18:00:00.000Z | |
| 10 | 10 | labels: [] |
| 11 | 11 | milestone: v0.8.0 |
| 12 | 12 | epic: Agent Memory |
| @@ -17,5 +17,208 @@ body: | | ||
| 17 | 17 | enabled: true |
| 18 | 18 | ``` |
| 19 | 19 | 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: 48 | 2 | id: 48 |
| 3 | title: Add a builtin tool to search into the mm sessions | 3 | title: Add a builtin tool to search into the mm sessions |
| 4 | -state: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-09-27T03:45:48.121Z | 8 | createdAt: 2026-09-27T03:45:48.121Z |
| 9 | -updatedAt: 2026-10-20T05:44:21.627Z | 9 | +updatedAt: 2026-10-20T18:00:00.000Z |
| 10 | labels: [] | 10 | labels: [] |
| 11 | milestone: v0.8.0 | 11 | milestone: v0.8.0 |
| 12 | epic: Agent Memory | 12 | epic: Agent Memory |
| @@ -17,5 +17,208 @@ body: | | |||
| 17 | enabled: true | 17 | enabled: true |
| 18 | ``` | 18 | ``` |
| 19 | use a /memory command to search information into the sessions files | 19 | 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 @@ | ||
| 1 | 1 | # Managed by IssueSpec. Hand edits are welcome; keep the schema valid. |
| 2 | 2 | id: 93 |
| 3 | 3 | title: Save an answer to a file without regenerating it (/save, save_answer) |
| 4 | -state: open | |
| 4 | +state: closed | |
| 5 | 5 | author: |
| 6 | 6 | name: k33g |
| 7 | 7 | email: ph.charriere@gmail.com |
| 8 | 8 | createdAt: 2026-10-17T16:00:00.000Z |
| 9 | -updatedAt: 2026-10-17T16:00:00.000Z | |
| 9 | +updatedAt: 2026-10-20T06:49:43.311Z | |
| 10 | 10 | labels: |
| 11 | 11 | - kind::feature |
| 12 | 12 | - builtin tool |
| 13 | +milestone: v0.7.0 | |
| 13 | 14 | epic: Builtin tools |
| 14 | 15 | body: | |
| 15 | 16 | ## Why |
| @@ -34,10 +35,9 @@ body: | | ||
| 34 | 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 | 36 | ## Measured with the mini-tutorial agent (wip2/, 2026-10-17) |
| 36 | 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 | 38 | tasks: |
| 39 | 39 | - id: 1 |
| 40 | - title: "internal/saved + /save command, with tests" | |
| 40 | + title: internal/saved + /save command, with tests | |
| 41 | 41 | state: closed |
| 42 | 42 | priority: high |
| 43 | 43 | author: |
| @@ -47,7 +47,7 @@ tasks: | ||
| 47 | 47 | updatedAt: 2026-10-17T16:00:00.000Z |
| 48 | 48 | closedAt: 2026-10-17T16:00:00.000Z |
| 49 | 49 | - id: 2 |
| 50 | - title: "save_answer tool + engine.Reply, with tests" | |
| 50 | + title: save_answer tool + engine.Reply, with tests | |
| 51 | 51 | state: closed |
| 52 | 52 | priority: high |
| 53 | 53 | author: |
| @@ -57,7 +57,7 @@ tasks: | ||
| 57 | 57 | updatedAt: 2026-10-17T16:00:00.000Z |
| 58 | 58 | closedAt: 2026-10-17T16:00:00.000Z |
| 59 | 59 | - id: 3 |
| 60 | - title: "Docs EN+FR, diagram" | |
| 60 | + title: Docs EN+FR, diagram | |
| 61 | 61 | state: closed |
| 62 | 62 | priority: medium |
| 63 | 63 | author: |
| @@ -67,7 +67,7 @@ tasks: | ||
| 67 | 67 | updatedAt: 2026-10-17T16:00:00.000Z |
| 68 | 68 | closedAt: 2026-10-17T16:00:00.000Z |
| 69 | 69 | - 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 | 71 | state: closed |
| 72 | 72 | priority: medium |
| 73 | 73 | 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: 93 | 2 | 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: open | 4 | +state: closed |
| 5 | author: | 5 | author: |
| 6 | name: k33g | 6 | name: k33g |
| 7 | email: ph.charriere@gmail.com | 7 | email: ph.charriere@gmail.com |
| 8 | createdAt: 2026-10-17T16:00:00.000Z | 8 | createdAt: 2026-10-17T16:00:00.000Z |
| 9 | -updatedAt: 2026-10-17T16:00:00.000Z | 9 | +updatedAt: 2026-10-20T06:49:43.311Z |
| 10 | labels: | 10 | labels: |
| 11 | - kind::feature | 11 | - kind::feature |
| 12 | - builtin tool | 12 | - builtin tool |
| 13 | +milestone: v0.7.0 | ||
| 13 | epic: Builtin tools | 14 | epic: Builtin tools |
| 14 | body: | | 15 | body: | |
| 15 | ## Why | 16 | ## 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: 1 | 39 | - id: 1 |
| 40 | - title: "internal/saved + /save command, with tests" | 40 | + title: internal/saved + /save command, with tests |
| 41 | state: closed | 41 | state: closed |
| 42 | priority: high | 42 | priority: high |
| 43 | author: | 43 | author: |
| @@ -47,7 +47,7 @@ tasks: | |||
| 47 | updatedAt: 2026-10-17T16:00:00.000Z | 47 | updatedAt: 2026-10-17T16:00:00.000Z |
| 48 | closedAt: 2026-10-17T16:00:00.000Z | 48 | closedAt: 2026-10-17T16:00:00.000Z |
| 49 | - id: 2 | 49 | - id: 2 |
| 50 | - title: "save_answer tool + engine.Reply, with tests" | 50 | + title: save_answer tool + engine.Reply, with tests |
| 51 | state: closed | 51 | state: closed |
| 52 | priority: high | 52 | priority: high |
| 53 | author: | 53 | author: |
| @@ -57,7 +57,7 @@ tasks: | |||
| 57 | updatedAt: 2026-10-17T16:00:00.000Z | 57 | updatedAt: 2026-10-17T16:00:00.000Z |
| 58 | closedAt: 2026-10-17T16:00:00.000Z | 58 | closedAt: 2026-10-17T16:00:00.000Z |
| 59 | - id: 3 | 59 | - id: 3 |
| 60 | - title: "Docs EN+FR, diagram" | 60 | + title: Docs EN+FR, diagram |
| 61 | state: closed | 61 | state: closed |
| 62 | priority: medium | 62 | priority: medium |
| 63 | author: | 63 | author: |
| @@ -67,7 +67,7 @@ tasks: | |||
| 67 | updatedAt: 2026-10-17T16:00:00.000Z | 67 | updatedAt: 2026-10-17T16:00:00.000Z |
| 68 | closedAt: 2026-10-17T16:00:00.000Z | 68 | closedAt: 2026-10-17T16:00:00.000Z |
| 69 | - id: 4 | 69 | - 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: closed | 71 | state: closed |
| 72 | priority: medium | 72 | 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 | ||
| 121 | 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 | 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 | 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 | 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 | 127 | ## Demos |
| @@ -154,6 +155,7 @@ The `demos/` directory holds ready-made set-ups (most with a README explaining h | ||
| 154 | 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 | 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 | 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 | 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 | 161 | ## 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 | ## Demos | 127 | ## 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 more | 161 | ## 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 @@ | ||
| 1 | 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="<b>main (mm)</b><br/><font style="font-size:10px">wiring: config, engine, tools, then one front end</font>" 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="<b>internal/agent</b><br/><font style="font-size:10px">terminal REPL: /quit /abort /compact /new</font>" 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="<b>internal/acp</b><br/><font style="font-size:10px">editor front end: Agent Client Protocol on stdio</font>" 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="<b>internal/session</b><br/><font style="font-size:10px">what a conversation starts from; the /new reset</font>" 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="<b>internal/compact</b><br/><font style="font-size:10px">history compression into a model-written summary</font>" 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="<b>internal/engine</b><br/><font style="font-size:10px">LLM connection + generation, one Provider per server</font>" 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="<b>internal/tools</b><br/><font style="font-size:10px">built-in tools: bash, read_skill, file tools, lsp, fetch_content; declared toolsbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content</font>lt;/fontbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content</font>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="<b>internal/detector</b><br/><font style="font-size:10px">repeated-action (loop) detection</font>" 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="<b>internal/config</b><br/><font style="font-size:10px">settings with YAML overrides (agent.yaml)</font>" 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="<b>internal/spinner</b><br/><font style="font-size:10px">terminal spinner and styling</font>" 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="<b>internal/ui</b><br/><font style="font-size:10px">human output destination + shared event sink</font>" 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="<b>internal/fileedit</b><br/><font style="font-size:10px">exact-replacement file editing</font>" 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="<b>internal/skills</b><br/><font style="font-size:10px">markdown skills catalogue (./skills)</font>" 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="<b>github.com/firebase/genkit</b><br/><font style="font-size:10px">ai.Message, tools, model calls</font>" 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="<b>github.com/coder/acp-go-sdk</b><br/><font style="font-size:10px">JSON-RPC transport for ACP</font>" 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="<b>github.com/openai/openai-go</b><br/><font style="font-size:10px">OpenAI-compatible HTTP client</font>" 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="<b>gopkg.in/yaml.v3</b><br/><font style="font-size:10px">YAML parsing</font>" 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="<b>internal/version</b><br/><font style="font-size:10px">which mm this is: build stamp, else the commit</font>" 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 | 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="<b>internal/mention</b><br/><font style="font-size:10px">the @path notation of a question</font>" 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="<b>internal/store</b><br/><font style="font-size:10px">per-project session files (.mm/sessions/<id>.json), the questions ↑ recalls</font>" 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="<b>internal/tui</b><br/><font style="font-size:10px">window front end: one screen on tcell (mm -tui)</font>" 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="<b>internal/command</b><br/><font style="font-size:10px">the one slash-command table, per front end</font>" 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="<b>github.com/gdamore/tcell/v2</b><br/><font style="font-size:10px">terminal screen, keys, mouse</font>" 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="<b>internal/saved</b><br/><font style="font-size:10px">an answer to a new file: /save, save_answer</font>" 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="<b>internal/clipboard</b><br/><font style="font-size:10px">system clipboard: native tool, then OSC 52</font>" 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="<b>internal/lsp</b><br/><font style="font-size:10px">language-server client: definition, references, hover, symbols, diagnostics, rename</font>" 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="<b>go.lsp.dev/protocol + jsonrpc2</b><br/><font style="font-size:10px">LSP types and JSON-RPC 2.0 over stdio</font>" 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="<b>mm — package dependencies</b><br/>Arrow: "imports". Yellow: entry point. Blue: front ends. Green: shared logic. Grey: leaf packages. Dashed purple: third-party modules.<br/>Regenerate the edge list from: go list -f '{{.ImportPath}}: {{join .Imports " "}}' ./..." 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="<b>internal/webmd</b><br/><font style="font-size:10px">web page → Markdown: fetch (robots.txt, charset → UTF-8), clean, convert</font>" 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="<b>golang.org/x/net/html (+ x/text)</b><br/><font style="font-size:10px">HTML5 parser, charset lookup</font>" 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="<b>internal/ask</b><br/><font style="font-size:10px">/ask another mm agent: child mm -acp, ACP client side</font>" 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="<b>internal/consent</b><br/><font style="font-size:10px">yolo switch, the four answers, per-session memory, the line mode prompt hook</font>" 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="<b>internal/mcp</b><br/><font style="font-size:10px">MCP clients (stdio, HTTP), their tools wrapped as mm tools</font>" 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="<b>internal/structured</b><br/><font style="font-size:10px">structuredOutput: Go declarations → JSON Schema (go/parser)</font>" 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="<b>internal/agentsmd</b><br/><font style="font-size:10px">the project's AGENTS.md, appended to the system prompt per conversation</font>" 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="<b>internal/elicit</b><br/><font style="font-size:10px">ask_user's questions and answers: normalize, line answers, elicitation form schema</font>" 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="<b>internal/hooks</b><br/><font style="font-size:10px">the hooks: block — runs each hook (sh -c, JSON on stdin/stdout), chain, onError</font>" 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="<b>internal/mention</b><br/><font style="font-size:10px">the @path notation of a question</font>" 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="<b>internal/store</b><br/><font style="font-size:10px">per-project session files (.mm/sessions/<id>.json), the questions ↑ recalls, /memory and search_memory</font>" 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="<b>internal/tui</b><br/><font style="font-size:10px">window front end: one screen on tcell (mm -tui)</font>" 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="<b>internal/command</b><br/><font style="font-size:10px">the one slash-command table, per front end</font>" 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="<b>github.com/gdamore/tcell/v2</b><br/><font style="font-size:10px">terminal screen, keys, mouse</font>" 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="<b>internal/saved</b><br/><font style="font-size:10px">an answer to a new file: /save, save_answer</font>" 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="<b>internal/clipboard</b><br/><font style="font-size:10px">system clipboard: native tool, then OSC 52</font>" 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="<b>internal/lsp</b><br/><font style="font-size:10px">language-server client: definition, references, hover, symbols, diagnostics, rename</font>" 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="<b>go.lsp.dev/protocol + jsonrpc2</b><br/><font style="font-size:10px">LSP types and JSON-RPC 2.0 over stdio</font>" 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="<b>mm — package dependencies</b><br/>Arrow: "imports". Yellow: entry point. Blue: front ends. Green: shared logic. Grey: leaf packages. Dashed purple: third-party modules.<br/>Regenerate the edge list from: go list -f '{{.ImportPath}}: {{join .Imports " "}}' ./..." 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="<b>internal/webmd</b><br/><font style="font-size:10px">web page → Markdown: fetch (robots.txt, charset → UTF-8), clean, convert</font>" 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="<b>golang.org/x/net/html (+ x/text)</b><br/><font style="font-size:10px">HTML5 parser, charset lookup</font>" 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="<b>internal/ask</b><br/><font style="font-size:10px">/ask another mm agent: child mm -acp, ACP client side</font>" 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="<b>internal/consent</b><br/><font style="font-size:10px">yolo switch, the four answers, per-session memory, the line mode prompt hook</font>" 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="<b>internal/mcp</b><br/><font style="font-size:10px">MCP clients (stdio, HTTP), their tools wrapped as mm tools</font>" 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="<b>internal/structured</b><br/><font style="font-size:10px">structuredOutput: Go declarations → JSON Schema (go/parser)</font>" 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="<b>internal/agentsmd</b><br/><font style="font-size:10px">the project's AGENTS.md, appended to the system prompt per conversation</font>" 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="<b>internal/elicit</b><br/><font style="font-size:10px">ask_user's questions and answers: normalize, line answers, elicitation form schema</font>" 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="<b>internal/hooks</b><br/><font style="font-size:10px">the hooks: block — runs each hook (sh -c, JSON on stdin/stdout), chain, onError</font>" 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="<b>main (mm)</b><br/><font style="font-size:10px">wiring: config, engine, tools, then one front end</font>" 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="<b>internal/agent</b><br/><font style="font-size:10px">terminal REPL: /quit /abort /compact /new</font>" 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="<b>internal/acp</b><br/><font style="font-size:10px">editor front end: Agent Client Protocol on stdio</font>" 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="<b>internal/session</b><br/><font style="font-size:10px">what a conversation starts from; the /new reset</font>" 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="<b>internal/compact</b><br/><font style="font-size:10px">history compression into a model-written summary</font>" 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="<b>internal/engine</b><br/><font style="font-size:10px">LLM connection + generation, one Provider per server</font>" 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="<b>internal/tools</b><br/><font style="font-size:10px">built-in tools: bash, read_skill, file tools, lsp, fetch_content; declared toolsbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content</font>lt;/fontbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content</font>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="<b>internal/detector</b><br/><font style="font-size:10px">repeated-action (loop) detection</font>" 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="<b>internal/config</b><br/><font style="font-size:10px">settings with YAML overrides (agent.yaml)</font>" 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="<b>internal/spinner</b><br/><font style="font-size:10px">terminal spinner and styling</font>" 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="<b>internal/ui</b><br/><font style="font-size:10px">human output destination + shared event sink</font>" 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="<b>internal/fileedit</b><br/><font style="font-size:10px">exact-replacement file editing</font>" 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="<b>internal/skills</b><br/><font style="font-size:10px">markdown skills catalogue (./skills)</font>" 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="<b>github.com/firebase/genkit</b><br/><font style="font-size:10px">ai.Message, tools, model calls</font>" 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="<b>github.com/coder/acp-go-sdk</b><br/><font style="font-size:10px">JSON-RPC transport for ACP</font>" 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="<b>github.com/openai/openai-go</b><br/><font style="font-size:10px">OpenAI-compatible HTTP client</font>" 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="<b>gopkg.in/yaml.v3</b><br/><font style="font-size:10px">YAML parsing</font>" 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="<b>internal/version</b><br/><font style="font-size:10px">which mm this is: build stamp, else the commit</font>" 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="<b>main (mm)</b><br/><font style="font-size:10px">wiring: config, engine, tools, then one front end</font>" 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="<b>internal/agent</b><br/><font style="font-size:10px">terminal REPL: /quit /abort /compact /new</font>" 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="<b>internal/acp</b><br/><font style="font-size:10px">editor front end: Agent Client Protocol on stdio</font>" 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="<b>internal/session</b><br/><font style="font-size:10px">what a conversation starts from; the /new reset</font>" 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="<b>internal/compact</b><br/><font style="font-size:10px">history compression into a model-written summary</font>" 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="<b>internal/engine</b><br/><font style="font-size:10px">LLM connection + generation, one Provider per server</font>" 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="<b>internal/tools</b><br/><font style="font-size:10px">built-in tools: bash, read_skill, file tools, lsp, fetch_content; declared toolsbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content</font>lt;/fontbuilt-in tools: bash, read_skill, file tools, lsp, fetch_content</font>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="<b>internal/detector</b><br/><font style="font-size:10px">repeated-action (loop) detection</font>" 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="<b>internal/config</b><br/><font style="font-size:10px">settings with YAML overrides (agent.yaml)</font>" 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="<b>internal/spinner</b><br/><font style="font-size:10px">terminal spinner and styling</font>" 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="<b>internal/ui</b><br/><font style="font-size:10px">human output destination + shared event sink</font>" 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="<b>internal/fileedit</b><br/><font style="font-size:10px">exact-replacement file editing</font>" 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="<b>internal/skills</b><br/><font style="font-size:10px">markdown skills catalogue (./skills)</font>" 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="<b>github.com/firebase/genkit</b><br/><font style="font-size:10px">ai.Message, tools, model calls</font>" 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="<b>github.com/coder/acp-go-sdk</b><br/><font style="font-size:10px">JSON-RPC transport for ACP</font>" 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="<b>github.com/openai/openai-go</b><br/><font style="font-size:10px">OpenAI-compatible HTTP client</font>" 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="<b>gopkg.in/yaml.v3</b><br/><font style="font-size:10px">YAML parsing</font>" 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="<b>internal/version</b><br/><font style="font-size:10px">which mm this is: build stamp, else the commit</font>" 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="<b>internal/mention</b><br/><font style="font-size:10px">the @path notation of a question</font>" 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="<b>internal/store</b><br/><font style="font-size:10px">per-project session files (.mm/sessions/<id>.json), the questions ↑ recalls</font>" 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="<b>internal/tui</b><br/><font style="font-size:10px">window front end: one screen on tcell (mm -tui)</font>" 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="<b>internal/command</b><br/><font style="font-size:10px">the one slash-command table, per front end</font>" 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="<b>github.com/gdamore/tcell/v2</b><br/><font style="font-size:10px">terminal screen, keys, mouse</font>" 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="<b>internal/saved</b><br/><font style="font-size:10px">an answer to a new file: /save, save_answer</font>" 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="<b>internal/clipboard</b><br/><font style="font-size:10px">system clipboard: native tool, then OSC 52</font>" 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="<b>internal/lsp</b><br/><font style="font-size:10px">language-server client: definition, references, hover, symbols, diagnostics, rename</font>" 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="<b>go.lsp.dev/protocol + jsonrpc2</b><br/><font style="font-size:10px">LSP types and JSON-RPC 2.0 over stdio</font>" 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="<b>mm — package dependencies</b><br/>Arrow: "imports". Yellow: entry point. Blue: front ends. Green: shared logic. Grey: leaf packages. Dashed purple: third-party modules.<br/>Regenerate the edge list from: go list -f '{{.ImportPath}}: {{join .Imports " "}}' ./..." 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="<b>internal/webmd</b><br/><font style="font-size:10px">web page → Markdown: fetch (robots.txt, charset → UTF-8), clean, convert</font>" 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="<b>golang.org/x/net/html (+ x/text)</b><br/><font style="font-size:10px">HTML5 parser, charset lookup</font>" 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="<b>internal/ask</b><br/><font style="font-size:10px">/ask another mm agent: child mm -acp, ACP client side</font>" 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="<b>internal/consent</b><br/><font style="font-size:10px">yolo switch, the four answers, per-session memory, the line mode prompt hook</font>" 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="<b>internal/mcp</b><br/><font style="font-size:10px">MCP clients (stdio, HTTP), their tools wrapped as mm tools</font>" 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="<b>internal/structured</b><br/><font style="font-size:10px">structuredOutput: Go declarations → JSON Schema (go/parser)</font>" 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="<b>internal/agentsmd</b><br/><font style="font-size:10px">the project's AGENTS.md, appended to the system prompt per conversation</font>" 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="<b>internal/elicit</b><br/><font style="font-size:10px">ask_user's questions and answers: normalize, line answers, elicitation form schema</font>" 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="<b>internal/hooks</b><br/><font style="font-size:10px">the hooks: block — runs each hook (sh -c, JSON on stdin/stdout), chain, onError</font>" 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="<b>internal/mention</b><br/><font style="font-size:10px">the @path notation of a question</font>" 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="<b>internal/store</b><br/><font style="font-size:10px">per-project session files (.mm/sessions/<id>.json), the questions ↑ recalls, /memory and search_memory</font>" 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="<b>internal/tui</b><br/><font style="font-size:10px">window front end: one screen on tcell (mm -tui)</font>" 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="<b>internal/command</b><br/><font style="font-size:10px">the one slash-command table, per front end</font>" 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="<b>github.com/gdamore/tcell/v2</b><br/><font style="font-size:10px">terminal screen, keys, mouse</font>" 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="<b>internal/saved</b><br/><font style="font-size:10px">an answer to a new file: /save, save_answer</font>" 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="<b>internal/clipboard</b><br/><font style="font-size:10px">system clipboard: native tool, then OSC 52</font>" 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="<b>internal/lsp</b><br/><font style="font-size:10px">language-server client: definition, references, hover, symbols, diagnostics, rename</font>" 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="<b>go.lsp.dev/protocol + jsonrpc2</b><br/><font style="font-size:10px">LSP types and JSON-RPC 2.0 over stdio</font>" 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="<b>mm — package dependencies</b><br/>Arrow: "imports". Yellow: entry point. Blue: front ends. Green: shared logic. Grey: leaf packages. Dashed purple: third-party modules.<br/>Regenerate the edge list from: go list -f '{{.ImportPath}}: {{join .Imports " "}}' ./..." 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="<b>internal/webmd</b><br/><font style="font-size:10px">web page → Markdown: fetch (robots.txt, charset → UTF-8), clean, convert</font>" 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="<b>golang.org/x/net/html (+ x/text)</b><br/><font style="font-size:10px">HTML5 parser, charset lookup</font>" 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="<b>internal/ask</b><br/><font style="font-size:10px">/ask another mm agent: child mm -acp, ACP client side</font>" 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="<b>internal/consent</b><br/><font style="font-size:10px">yolo switch, the four answers, per-session memory, the line mode prompt hook</font>" 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="<b>internal/mcp</b><br/><font style="font-size:10px">MCP clients (stdio, HTTP), their tools wrapped as mm tools</font>" 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="<b>internal/structured</b><br/><font style="font-size:10px">structuredOutput: Go declarations → JSON Schema (go/parser)</font>" 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="<b>internal/agentsmd</b><br/><font style="font-size:10px">the project's AGENTS.md, appended to the system prompt per conversation</font>" 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="<b>internal/elicit</b><br/><font style="font-size:10px">ask_user's questions and answers: normalize, line answers, elicitation form schema</font>" 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="<b>internal/hooks</b><br/><font style="font-size:10px">the hooks: block — runs each hook (sh -c, JSON on stdin/stdout), chain, onError</font>" 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) | ||
| 27 | 27 | - [Add a skill](how-to/add-a-skill.md) |
| 28 | 28 | - [Declare a custom tool](how-to/declare-a-custom-tool.md) |
| 29 | 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 | 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 | 32 | - [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 | 33 | - [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-after | 32 | - [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 | ||
| 95 | 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 | 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 | 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 | 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 | 101 | ## 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 also | 101 | ## 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 | ||
| 159 | 159 | | `read` | `read` | `read_skill`, `read_file` | |
| 160 | 160 | | `edit` | `edit` | `write_file`, `edit_file` | |
| 161 | 161 | | `fetch` | `fetch` | `fetch_content` | |
| 162 | +| `search` | `search` | `search_memory` | | |
| 162 | 163 | | `other` | `other` | `ask_agent`, `ask_user` | |
| 163 | 164 | |
| 164 | 165 | ## 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 identifiers | 165 | ## 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.