manual: инструкция «как пользоваться»; watch: первичный проход, коллекции по правилу ядра; приёмка: контур демона
This commit is contained in:
@@ -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`, — расходник.**
|
||||
Reference in New Issue
Block a user