# Как пользоваться memo Инструкция для человека. Без внутренностей — только что делать руками. Смысл одной фразой: **вы пишете обычные markdown-файлы, а `memo` рядом с ними отвечает на вопросы по смыслу** — не по словам, а по содержанию, и не отправляя ничего в интернет. --- ## 1. Что это и зачем У вас есть папка с заметками. Обычные `.md`-файлы, обычные подпапки-темы. `memo` строит рядом с каждой папкой-темой маленький индекс (`SQLite`) и умеет искать по нему: - **по смыслу** — «как чинят карточку в jellyfin» найдёт заметку, где написано «удаление элемента из медиатеки», хотя слова «карточка» там нет; - **по точному значению** — `76.117`, номер тикета, версия — найдёт точную строку; - **сразу и то, и другое** (по умолчанию) — режим называется гибридный. Что важно понять сразу: | | | |---|---| | **Ваши файлы — главные** | `memo` только читает `.md`. Он никогда ничего в них не пишет и не переименовывает. | | **Индекс — расходник** | `.memo/index.db` внутри папки можно удалить в любой момент. Он пересоберётся. Это не ваши данные. | | **Всё локально** | Никаких облаков и API. Модель лежит файлом на диске, считает на процессоре. | | **Никакого «формата memo»** | Никаких спец-тегов, баз данных для правки, экспортов. Только markdown. | --- ## 2. Структура вашей библиотеки `memo` не навязывает вам схему — он просто следует за вашими папками. **Коллекция** = папка, в которой лежат `.md` **напрямую**. Одна папка = одна тема = одна независимая база. Папки друг о друге не знают. Пример нормальной библиотеки: ``` ~/notes/ <- корень библиотеки (не коллекция: тут нет .md напрямую) ├── infra/ <- КОЛЛЕКЦИЯ (тут *.md) │ ├── servers.md │ ├── hosts.md │ └── .memo/index.db <- индекс, создастся сам ├── work/ │ └── jira/ <- КОЛЛЕКЦИЯ (тут *.md) │ ├── access.md │ └── ci.md └── life/ └── books/ <- КОЛЛЕКЦИЯ (тут *.md) ├── history.md └── notes.md ``` Тут три коллекции: `infra`, `work/jira`, `life/books`. Папки `work` и `life` — просто группировка, коллекциями они не считаются (в них нет `.md` напрямую), и это правильно: иначе одни и те же заметки индексировались бы по нескольку раз. **Правило простое:** завёл папку, положил туда `.md` — это новая коллекция. Ничего регистрировать не надо. --- ## 3. Установка (один раз) Нужен JDK 21. ```bash cd /root/WORK/memo ./gradlew installDist ``` **Больше ничего делать не надо.** Модель (287 МБ) скачается сама при первом использовании — при первом `index`, `search` или `status`. Выглядит это так: ``` модель не найдена в /root/WORK/memo/models/siglip2, скачиваю с http://static.binom.pw/models/siglip2 (≈287 МБ, один раз) скачиваю text_model_int8.onnx: 45% (128 МБ / 283 МБ) скачано text_model_int8.onnx: 283 МБ скачано tokenizer.model: 4 МБ ``` Качается один раз: если файлы на месте, в сеть никто не ходит — поиск и индексация работают офлайн. ### Скачать заранее (необязательно) Если хотите подготовить модель до первого запуска: ```bash CLI=/root/WORK/memo/memo-cli/build/install/memo/bin/memo $CLI model #> скачано: text_model_int8.onnx, tokenizer.model (287679278 байт) $CLI model # повторный запуск: ничего не качает #> модель уже на месте в /root/WORK/memo/models/siglip2: text_model_int8.onnx, tokenizer.model $CLI model --force # перекачать принудительно $CLI model --dir /другой/путь ``` Скачивание можно прервать и продолжить: файл пишется как `<имя>.part`, а при следующем запуске закачка **дописывается с места обрыва** (сервер поддерживает докачку). Целевой файл появляется только после того, как размер сошёлся, — «битого, но выглядящего рабочим» файла не будет. ### Где живёт модель и как это менять По умолчанию — `/root/WORK/memo/models/siglip2`. Одна копия на все три программы, поэтому в дистрибутивы она не кладётся (иначе было бы 287 МБ × 3). | Переменная | Смысл | |---|---| | `MEMO_MODEL_DIR` | где лежит модель (иначе `/root/WORK/memo/models/siglip2`) | | `MEMO_MODEL_AUTO_DOWNLOAD=0` | запретить автоматическое скачивание. Тогда при отсутствии модели будет ошибка `модель не найдена в <путь>; запустите: memo model` | ```bash export MEMO_MODEL_DIR=/root/WORK/memo/models/siglip2 # добавьте в ~/.bashrc, чтобы не повторять ``` После сборки появятся три программы: ``` memo-cli/build/install/memo/bin/memo <- для человека и для скриптов memo-mcp/build/install/memo-mcp/bin/memo-mcp <- для агента (MCP) memo-watch/build/install/memo-watch/bin/memo-watch <- демон слежения (необязателен) ``` --- ## 4. Первый запуск: проиндексировать и найти ```bash CLI=/root/WORK/memo/memo-cli/build/install/memo/bin/memo # Проиндексировать всю библиотеку (коллекции найдутся сами) $CLI index ~/notes #> индексировано: 4 обновлено, 4 файлов всего #> индексировано: 4 обновлено, 4 файлов всего #> индексировано: 4 обновлено, 4 файлов всего #> итого: 12 обновлено в 3 коллекциях # Спросить по смыслу $CLI search ~/notes/infra "где публикуются релизы" #> 0.016 /root/notes/infra/hosts.md:6 Прокси #> Корпоративные домены проксируются кади на 76.132. #> 0.016 /root/notes/infra/hosts.md:3 Nexus #> Нексус доступен на 76.117, публикация — только через CI. ``` Первая строка в каждой паре — `похожесть`, адрес `файл:строка` и заголовок раздела; ниже — сам текст куска. Обратите внимание: первая команда была `index`, но она **не обязательна**. `search` сам до-индексирует то, что изменилось, прямо перед поиском. Можно просто писать заметки и сразу спрашивать. ### Команды целиком ```bash $CLI index <путь> # проиндексировать (повторный прогон — быстрый) $CLI model # скачать модель (обычно не нужно — сама скачается) $CLI search <путь> "<вопрос>" # искать: и смысл, и точные слова $CLI search <путь> "<вопрос>" --k 5 # вернуть 5 результатов (по умолчанию 8) $CLI search <путь> "<вопрос>" --json # машинный вывод (для скриптов и агента) $CLI search <путь> "<вопрос>" --mode lex # только точные слова (BM25) $CLI search <путь> "<вопрос>" --mode vec # только по смыслу (вектор) $CLI status <путь> # что проиндексировано и когда ``` Что писать в `<путь>`: - **корень библиотеки** (`~/notes`) — поиск по всем коллекциям сразу, ответы перемешиваются и сортируются по релевантности; - **одну папку-коллекцию** (`~/notes/infra`) — поиск только внутри неё. Область видно по адресам в результатах: `.../infra/hosts.md` — значит, нашли в `infra`. --- ## 5. Подключить к агенту (Hermes) Здесь `memo` и живёт по-настоящему: агент получает **инструмент поиска** и перестаёт перечитывать всю библиотеку целиком. Добавьте в конфиг Hermes (`~/.hermes/config.yaml`, секция `mcp_servers`): ```yaml mcp_servers: memo: command: /root/WORK/memo/memo-mcp/build/install/memo-mcp/bin/memo-mcp env: MEMO_MODEL_DIR: /root/WORK/memo/models/siglip2 enabled: true ``` **Инструменты подхватятся только в новой сессии Hermes** — как и любой MCP-сервер, они читаются при старте процесса. В текущей беседе их не будет; начните новую и проверьте, что появились `memo_search`, `memo_status`, `memo_reindex`. Агенту после этого можно говорить просто: «поищи в заметках, чем мы чинили карточку в jellyfin». Он вызовет `memo_search` и получит пути, строки и текст найденных кусков. ### Три инструмента | Инструмент | Что делает | |---|---| | `memo_search(path, query, k, mode)` | Гибридный поиск. **Если индекса нет — создаёт его сам.** | | `memo_status(path)` | Что проиндексировано, сколько файлов и чанков, когда обновлялось. | | `memo_reindex(path)` | Полная переиндексация (нужна редко — обычный поиск и так до-индексирует). | ### Проверить без агента Тот же код инструмента, но из командной строки — удобно, когда что-то не работает: ```bash $CLI mcp-probe --tool memo_search --args '{"path":"/root/notes/infra","query":"домены","k":3}' $CLI mcp-probe --tool memo_status --args '{"path":"/root/notes"}' ``` Ответ печатается ровно в той форме, которую получил бы агент. --- ## 6. Демон слежения — нужен ли он вам **Короткий ответ: для работы с агентом — не нужен.** Поиск сам замечает изменения: перед каждым запросом он сверяет дату и размер файлов и до-индексирует то, что поменялось. Написали заметку — сразу нашли её. Демон `memo-watch` нужен ровно в одном случае: **заметки правят мимо агента** — вы сами в редакторе, через `git pull`, синхронизацию, чужой скрипт, — и вы хотите, чтобы индекс был свежим *заранее*, а не в момент вопроса. ```bash memo-watch/build/install/memo-watch/bin/memo-watch ~/notes #> индексирую: /root/notes/infra -> обновлено 4 #> индексирую: /root/notes/life/books -> обновлено 4 #> индексирую: /root/notes/work/jira -> обновлено 4 #> наблюдаю: /root/notes/infra #> наблюдаю: /root/notes/life/books #> наблюдаю: /root/notes/work/jira ``` При старте он **сразу проходит по всем коллекциям** — индекс полный с первой секунды, ждать изменений не надо. Дальше печатает `наблюдаю:` по каждой и доиндексирует по факту правок: ``` #> индексирую: /root/notes/infra -> обновлено 1 ``` ### Какие папки он мониторит Ровно те, что вы передали аргументом, — по тому же правилу, что и остальные команды: - передали **корень** (`~/notes`) — следит за всеми коллекциями внутри него (в примере — `infra`, `work/jira`, `life/books`) и держит индекс по каждой; - передали **одну папку** (`~/notes/infra`) — следит только за ней. Внутрь служебных папок (`.memo`, `.git`, любые `.`-папки) он не заглядывает. Список наблюдаемых папок печатается при старте строками `наблюдаю: <путь>` — это и есть ответ на вопрос «что он мониторит». Демон переживает правки так: ловит изменения (с задержкой 0.5 с, чтобы не дёргаться на каждое нажатие), раз в 10 минут делает полный сверочный проход — это страховка для случаев, когда система о событиях файлов не сообщила (сетевые диски, sshfs). Пока это ручной запуск: автостарта (systemd) нет, сам он нигде в системе не прописан и **сейчас не работает** — его надо запускать руками, когда понадобится. --- ## 7. Порядок работы: как это выглядит в жизни ```bash # 1. Завести тему — просто папка с markdown mkdir -p ~/notes/infra cat > ~/notes/infra/hosts.md <<'EOF' # Хосты ## Nexus Нексус доступен на 76.117, публикация — только через CI. ## Прокси Корпоративные домены проксируются кади на 76.132. EOF # 2. Спросить $CLI search ~/notes/infra "где публикуются релизы" #> 0.031 /root/notes/infra/hosts.md:10 Nexus #> Нексус доступен на 76.117, публикация — только через CI. # 3. Дописать заметку — и сразу спросить про неё, без переиндексации printf '\n## Свежий раздел\nуникальное_слово_дзынь_47\n' >> ~/notes/infra/hosts.md $CLI search ~/notes/infra "уникальное слово дзынь" #> 0.016 /root/notes/infra/hosts.md:10 Свежий раздел #> уникальное_слово_дзынь_47 #> 0.016 /root/notes/infra/hosts.md:6 Прокси #> Корпоративные домены проксируются кади на 76.132. # 4. Периодически освежать всё скопом (обычно не нужно — бывает после git pull) $CLI index ~/notes ``` Записывать заметки можно **любым способом**: редактором, `>>`, агентом, `git pull`. `memo` не требует, чтобы записи шли через него. --- ## 8. Если что-то не так **Поиск ничего не находит, хотя файлы на месте.** Проверьте, что папка — коллекция, то есть `.md` лежат в ней напрямую: ```bash $CLI status ~/notes # должны быть видны коллекции и число файлов find ~/notes -name '*.md' | head # файлы на месте? $CLI status ~/notes/emptygroup #> коллекции не найдены ``` Если `status` пишет `коллекции не найдены` — вы указали папку, в которой нет `.md` напрямую (например, общую группировку вроде `work`, где лежат только подпапки). Укажите корень библиотеки или папку-коллекцию. **Свежая правка не находится.** Проверьте, что ищете в той же папке, где файл: поиск по `~/notes/infra` не увидит заметку из `~/notes/work`. Поиск по корню видит всё. **Хочу начать с чистого листа.** Удалите индексы — данные не пострадают: ```bash find ~/notes -name .memo -type d -prune -exec rm -rf {} + $CLI index ~/notes ``` **`database is locked`.** Значит, одновременно пишут два процесса. Подождите минуту и повторите; если повторяется — пришлите текст ошибки, это повод для отдельного разбирательства. **Инструменты `memo_*` не появились у агента.** MCP-серверы читаются при старте Hermes: начните новую сессию. Проверьте, что путь к `memo-mcp` в конфиге верный и файл исполняемый. **Агент долго не отвечает на первый запрос.** Скорее всего, скачивается модель (287 МБ) — в stderr `memo-mcp` идёт строка `модель не найдена ..., скачиваю ...`. Это разовое: скачайте заранее командой `$CLI model` или подложите файлы в `MEMO_MODEL_DIR`. **Где посмотреть, что вообще происходит.** ```bash $CLI status ~/notes # по каждой коллекции: файлов, чанков, когда индексировали find ~/notes -name index.db # где лежат индексы ``` --- ## 9. Что можно удалять без страха | Путь | Что это | Удалять? | |---|---|---| | `~/notes/**/*.md` | **ваши заметки** | Нет — это ваши данные | | `~/notes/**/.memo/` | индексы | **Да**, пересоберутся командой `index` | | `models/siglip2/` | модель | Да, но придётся скачать заново | | `build/` | сборка | Да, но придётся пересобрать | Правило: **всё, что не `.md`, — расходник.**