367 lines
20 KiB
Markdown
367 lines
20 KiB
Markdown
# Как пользоваться 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`, — расходник.**
|