Files

367 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Как пользоваться 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`, — расходник.**