manual: инструкция «как пользоваться»; watch: первичный проход, коллекции по правилу ядра; приёмка: контур демона

This commit is contained in:
2026-10-02 03:43:25 +03:00
parent 2c7bca0d82
commit 3054705176
6 changed files with 648 additions and 27 deletions
+327
View File
@@ -0,0 +1,327 @@
# Как пользоваться 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
# 1. Собрать всё
./gradlew installDist
# 2. Скачать модель (в артефакты не входит, 287 МБ, один раз)
mkdir -p models/siglip2
curl -fSL -o models/siglip2/text_model_int8.onnx http://static.binom.pw/models/siglip2/text_model_int8.onnx
curl -fSL -o models/siglip2/tokenizer.model http://static.binom.pw/models/siglip2/tokenizer.model
# 3. Сказать, где модель (добавьте в ~/.bashrc, чтобы не повторять)
export MEMO_MODEL_DIR=/root/WORK/memo/models/siglip2
```
Без переменной `MEMO_MODEL_DIR` программы ищут модель в `/root/WORK/memo/models/siglip2` —
если у вас этот путь, шаг 3 можно пропустить.
После сборки появятся три программы:
```
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 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`
в конфиге верный и файл исполняемый.
**Где посмотреть, что вообще происходит.**
```bash
$CLI status ~/notes # по каждой коллекции: файлов, чанков, когда индексировали
find ~/notes -name index.db # где лежат индексы
```
---
## 9. Что можно удалять без страха
| Путь | Что это | Удалять? |
|---|---|---|
| `~/notes/**/*.md` | **ваши заметки** | Нет — это ваши данные |
| `~/notes/**/.memo/` | индексы | **Да**, пересоберутся командой `index` |
| `models/siglip2/` | модель | Да, но придётся скачать заново |
| `build/` | сборка | Да, но придётся пересобрать |
Правило: **всё, что не `.md`, — расходник.**