memohood
Health Pass
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 23 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Dialogue memory for AI agents (hermes plugin): auto-recall of facts across sessions, LLM fact extraction with a cheap gate, SUPERSEDE versioning. Local SQLite + hybrid search. One-command install.
🧠 MemoHood
MemoHood — это плагин памяти диалогов для hermes-agent: агент сам замечает важное в разговоре, сам вспоминает его к месту в следующий раз и сам решает, когда старый факт пора заменить новым — без единой лишней команды от вас.
🌐 Русский · English
Быстрый старт · Инструменты и команды · Настройки · FAQ
flowchart TD
subgraph TURN["Каждый ход диалога"]
MSG["Сообщение пользователя"]
GATE{"gate — вспоминать?<br/>v1.1, по умолч. pass"}
PRE["гибридный поиск<br/>FTS5(RU-стемминг) + вектор BGE-M3 + RRF + Cohere rerank"]
GR["graph_rerank<br/>связи сессий, v1.1"]
POST["post_recall<br/>MMR + схлопывание дублей, v1.1"]
CTX["<memory-context> в промпте"]
ANS["Ответ модели"]
MSG --> GATE -->|"recall"| PRE --> GR --> POST --> CTX --> ANS
GATE -.->|"skip"| ANS
end
ANS --> SYNC["sync_turn<br/>фоновый поток, ответ не ждёт"]
subgraph CAPTURE["capture.py — двухступенчатая экстракция"]
SIG{"Бесплатные сигналы-ключевики"}
GEM["Gemini flash-lite<br/>только спорные случаи"]
SUP{"supersede-классификатор<br/>cosine + LLM-judge"}
SIG -->|"явный сигнал"| SUP
SIG -->|"спорно"| GEM --> SUP
end
SYNC --> SIG
SUP -->|"ADD / SUPERSEDE / NOOP"| DB[("memory.db<br/>captures + история замещений")]
DB -.->|"ночью, hermes cron"| NIGHT["Консолидация:<br/>decay Эббингауза (кроме pinned) →<br/>dedup → rollup день→неделя→месяц → FTS-rebuild"]
NIGHT -.-> DB
Что делает MemoHood?
MemoHood — это плагин памяти диалогов для hermes-agent. Представьте, что у агента появился личный дневник: он сам записывает туда важное из разговора — факты, решения, исправления, предпочтения — и сам подглядывает в него перед каждым новым ответом, без того, чтобы вы отдельно просили что-то запомнить.
Без памяти агент помнит только то, что помещается в текущий контекст: начали новую сессию — и всё, что было вчера, исчезло. MemoHood хранит важное отдельно, в локальной базе на вашей машине, и подмешивает нужные кусочки обратно в разговор ровно тогда, когда они пригодились бы. Это провайдер памяти (memory.provider) для hermes-agent — устанавливается одной командой и работает полностью автономно.
От каких проблем избавляет
- Агент забывает всё, стоит закрыть чат. → Помнит между сессиями — факты живут в локальной базе, а не в контексте одного диалога.
- Приходится каждый раз вручную напоминать контекст о себе. → Авто-recall сам подтягивает нужные факты перед каждым ответом, без просьбы «вспомни».
- Путает старое решение с новым, держится за устаревшее. → SUPERSEDE: новый факт наверх, старый помечается устаревшим и хранится с датой — видно и «как сейчас», и «как было».
- Память жила «в голове» модели и обнулялась при смене модели. → Факты лежат в отдельной локальной базе, не привязанной к модели: сменил модель — recall работает так же, ничего не теряется.
- Платишь токенами за обработку пустой болтовни. → Дешёвый офлайн-гейт (Model2Vec) отсекает трёп до дорогого вызова модели.
Что это даёт
- Авто-вспоминание перед каждым ответом. Перед тем как агент начнёт отвечать, MemoHood тихо ищет в памяти всё релевантное: гибридный поиск объединяет полнотекстовый FTS5/BM25 с русским стеммингом и векторный поиск (модель BGE-M3 через Cloudflare Workers AI), сливает оба списка взаимным ранжированием (RRF) и, если настроен ключ, дополнительно переранжирует топ-кандидатов моделью Cohere.
- Авто-захват фактов, бесплатный там, где можно. Явные сигналы — исправление, решение, предпочтение, прямое «запомни» — ловятся бесплатным сигнальным скорингом по ключевым словам, без единого вызова LLM. Только по-настоящему спорные случаи уходят на один-единственный вызов дешёвой модели Gemini flash-lite, которая решает, стоит ли это запоминать и как.
- Supersede вместо затирания истории. Когда новый факт противоречит старому (пользователь передумал, поправил себя), MemoHood не хранит оба вперемешку — новый замещает старый, а старый не пропадает: уходит в датированную историю записи, которую всегда можно поднять через
memohood_fetch. - Pinned-факты, которые никогда не забываются. Имя, дата рождения, аллергии, диагнозы, явное «запомни навсегда» — распознаются и помечаются как pinned. Такие записи полностью исключены из ночного угасания confidence, сколько бы времени ни прошло.
- Ночная консолидация с кривой забывания Эббингауза. Уверенность (confidence) каждого факта угасает экспоненциально со временем с момента последнего обращения к нему — быстрее для мимолётных событий, гораздо медленнее для устойчивых фактов и убеждений, и вообще не угасает для pinned. Вся эта тяжёлая работа (decay, дедуп, свёртка день→неделя→месяц, перестройка индекса) вынесена из горячего пути ответа в фоновую ночную задачу.
- Русская морфология из коробки. И запросы, и содержимое записей стеммингуются PyStemmer — запрос «договора» находит запись про «договор», без точного совпадения форм слова.
- Спенд-леджер с месячным потолком. Каждый внешний вызов — эмбеддинг, реранк, экстракция LLM — пишется в леджер расходов. При достижении месячного потолка по конкретному провайдеру соответствующий шаг просто аккуратно пропускается (например, поиск идёт без векторного плеча), а не падает с ошибкой.
Новое в v1.1 — умный конвейер recall
Три этапа делают вспоминание точнее и разнообразнее. Два из них включены по умолчанию, третий — opt-in.
gate— «стоит ли вообще вспоминать?» (по умолчанию выключен). Перед тем как тратиться на полный поиск, гейт может быстро оценить запрос: если это простое «спасибо» или «ок», recall пропускается. По умолчаниюgate.backend: pass— гейт всегда пропускает дальше (память проверяется каждый ход). Включить умный режим —gate.backend: model2vec: крошечная офлайн-модель статических эмбеддингов (пакетmodel2vec, без сети и без API-ключа) сравнивает запрос со встроенными наборами «похоже на вопрос к памяти» и «похоже на болтовню». Правило намеренно осторожное: пропуск recall только при явном перевесе «болтовни» — ложно вспомнить безопаснее, чем ложно промолчать.post_recall— разнообразие и без дублей (по умолчанию ВКЛ). После поиска выдача проходит два шага: схлопывание near-дублей (две почти одинаковые записи не занимают два места) и MMR (Maximal Marginal Relevance) — переупорядочивание так, чтобы верхние результаты не были все об одном и том же. Итог: агент видит более широкую и менее избыточную картину памяти.graph_rerank— связи между сессиями (по умолчанию ВКЛ). MemoHood хранит граф связей между сессиями (session_links). Если найденная запись относится к сессии, связанной с «якорными» топ-результатами, её вес немного повышается; кроме того, из связанных сессий могут подтянуться релевантные записи, которые обычный поиск не нашёл. Так по теме поднимается контекстно-связанное, а не только буквально совпавшее по словам.
Как это работает?
Каждый ход диалога проходит через prefetch, и это целый конвейер: gate решает, стоит ли вообще вспоминать → гибридный поиск (FTS5 + вектор + RRF + опц. Cohere) достаёт кандидатов → graph_rerank поднимает контекстно-связанное по графу сессий → post_recall убирает дубли и добавляет разнообразия. Итог MemoHood подмешивает в промпт отдельным блоком <memory-context>. После того как модель ответила, в фоновом потоке (не блокируя ответ) запускается sync_turn: он разбирает реплику на сигналы, при необходимости зовёт Gemini на спорные случаи и решает — добавить новую запись, заменить старую (supersede) или ничего не делать (дубль). Ночью, по расписанию hermes cron, отдельно запускается консолидация: угасание confidence, дедуп, свёртка старых записей и перестройка индекса.
MemoHood vs альтернативы
| Критерий | MemoHood | Без памяти (только system prompt) |
|---|---|---|
| Что помнит | Диалоги: факты, решения, исправления, предпочтения | Только текущий контекст сессии |
| Забывание | Плавное, по кривой Эббингауза; pinned — никогда | Полное при новой сессии или сжатии контекста |
| Противоречивые факты | Supersede: новое замещает старое, старое — в историю | Копятся в контексте, модель путается |
| Стоимость | Доли цента за ход; месячный потолок по умолчанию $5 на провайдера | Ноль |
Быстрый старт
Установка
Ставите через Telegram-бота hermes? Пришлите архив плагина в чат и попросите «распакуй и поставь по инструкции внутри» — агент выполнит установку по
AGENTS.md. Ниже — ручная установка в терминале.
1. Один командой. Установщик сам находит venv hermes-agent, ставит зависимости (sqlite-vec, PyStemmer, ftfy, requests, model2vec), копирует папку плагина в <HERMES_HOME>/plugins/memohood/ и включает memory.provider: memohood в config.yaml — руками копировать папку или редактировать конфиг не нужно:
# Windows
.\install.ps1
# Linux / macOS
./install.sh
Перезапустите hermes — память уже работает, в keyword-режиме: сигналы вроде «запомни», «решили», «на самом деле» запоминаются бесплатно, без единого внешнего вызова.
Если hermes у вас работает как systemd-сервис (gateway), ключи из .env подхватятся после hermes gateway restart — установщик уже прописал для этого системный drop-in (EnvironmentFile). В интерактивной CLI-сессии .env подхватывается сам собой: она наследует окружение процесса, из которого её запустили.
2. Ключи — по желанию, для семантики. Без них память работает только на точном совпадении слов; чтобы включить поиск по смыслу (эмбеддинги + реранк) и извлечение спорных фактов, впишите ключи в .env рядом с config.yaml (~/.hermes/.env, на Windows — %LOCALAPPDATA%\hermes\.env). Проще всего это сделать мастером настройки прямо в терминале:
hermes memohood setup
Мастер идёт по шагам, по одному вопросу за раз, и каждый можно пропустить простым Enter (память продолжит работать, просто скромнее): сначала Cloudflare (эмбеддинги — векторный поиск по смыслу), потом Cohere — и тут же простыми словами объясняет, что такое реранкер («строгий редактор», который пересортировывает найденное так, что самое нужное оказывается сверху), затем Gemini (экстракция спорных фактов и ночная консолидация), и напоследок проверяет, что нужные python-библиотеки на месте. По желанию каждый ключ можно сразу проверить одним живым запросом к провайдеру. В консоли ключ целиком никогда не показывается — только первые символы с многоточием — и в таком же замаскированном виде пишется в .env. Мастер не трогает config.yaml — это уже сделал установщик на шаге 1 (если он запускался без --no-config).
Ключи те же самые, что мастер спрашивает по одному, можно вписать и вручную:
CLOUDFLARE_ACCOUNT_ID=...
CLOUDFLARE_API_TOKEN=...
GEMINI_API_KEY=...
COHERE_API_KEY=... # опционально — включает финальный реранк
Cloudflare нужен для векторного поиска (эмбеддинги, бесплатный тир), Gemini — для экстракции спорных фактов и ночной консолидации, Cohere — необязательный реранк. Что произойдёт, если какого-то ключа нет — см. FAQ ниже. Не хотите зависеть от Cloudflare вовсе — переустановите с флагом --local/-Local: установщик поставит fastembed, скачает модель intfloat/multilingual-e5-large (~2.2 ГБ, один раз) и сам пропишет офлайн-эмбеддер в config.yaml.
3. Проверьте:
hermes memohood status
Если плагин подхватился, вы увидите статистику памяти (пока пустую) и расход за 30 дней по каждому провайдеру — 0 из настроенного потолка, а в конце — блок «Ключи»: полный путь к .env и статус каждого ключа (✓ настроен с маской / ✗ нет / ⚠ есть в .env, но процесс не видит — записан, но нужен рестарт).
Настройки
Все ключи ниже задаются в config.yaml с префиксом memory.memohood., например memory.memohood.capture_threshold: 4.0.
| Ключ | Тип | По умолчанию | Что делает |
|---|---|---|---|
gate.backend |
string | pass |
Гейт «стоит ли вспоминать» перед recall. pass — всегда вспоминать (по умолчанию); model2vec — офлайн-классификатор релевантности запроса (opt-in, подтягивает пакет model2vec) |
gate.threshold |
float | 0.5 |
Порог уверенного «не вспоминать» для backend model2vec |
gate.margin |
float | 0.05 |
Зазор в пользу recall: пропустить только при явном перевесе negative-сигналов |
gate.model2vec_model |
string | minishlab/potion-base-8M |
Статическая embedding-модель для гейта |
gate.meaningful_terms_floor |
int | 3 |
Если в запросе столько значимых слов и больше — вспоминаем сразу, без эмбеддинга |
model.provider |
string | gemini |
Провайдер LLM для спорной экстракции фактов и ночной консолидации |
model.model |
string | gemini-3.1-flash-lite |
Конкретная модель для экстракции и консолидации |
embedder.provider |
string | cloudflare |
Провайдер эмбеддингов для векторного поиска |
embedder.model |
string | @cf/baai/bge-m3 |
Модель эмбеддингов |
embedder.dims |
int | 1024 |
Размерность вектора |
rerank.provider |
string | cohere |
Провайдер финального реранка |
rerank.enabled |
bool | true |
Включить реранк Cohere поверх результата RRF (без ключа — тихая деградация в rrf-only) |
post_recall.mmr.enabled |
bool | true |
MMR-разнообразие выдачи recall — верхние результаты не про одно и то же |
post_recall.mmr.lambda |
float | 0.7 |
Баланс релевантность/разнообразие (1.0 = чистая релевантность) |
post_recall.cluster.enabled |
bool | true |
Схлопывать near-дубли в выдаче |
post_recall.cluster.threshold |
float | 0.93 |
Косинусный порог, выше которого две записи считаются дублем |
graph_rerank.enabled |
bool | true |
Переранжирование по графу связей сессий (session_links) |
graph_rerank.boost |
list | [1.5, 1.3, 1.15] |
Множители score по близости связи (тесная/средняя/слабая) |
graph_rerank.max_neighbors |
int | 3 |
Сколько связанных записей максимум подтянуть в выдачу |
graph_rerank.top_n_anchors |
int | 3 |
Сколько верхних результатов служат «якорями» для расширения по графу |
graph_rerank.weight_tiers |
list | [0.66, 0.33] |
Пороги веса связи для выбора тира boost |
auto_capture |
bool | true |
Автоматически извлекать факты из каждого хода диалога |
capture_threshold |
float | 4.0 |
Порог бесплатного сигнального скоринга, выше которого факт сохраняется гарантированно, без вызова LLM |
monthly_ceiling_usd.cloudflare |
number | 5 |
Месячный потолок расходов на эмбеддинги, $ |
monthly_ceiling_usd.cohere |
number | 5 |
Месячный потолок расходов на реранк, $ |
monthly_ceiling_usd.gemini |
number | 5 |
Месячный потолок расходов на экстракцию и консолидацию, $ |
decay.floor |
float | 0.05 |
Порог confidence, ниже которого запись архивируется при ночной консолидации |
decay.halflife_days.event |
int | 7 |
Период полураспада для событий |
decay.halflife_days.preference |
int | 90 |
Для предпочтений |
decay.halflife_days.decision |
int | 90 |
Для решений |
decay.halflife_days.correction |
int | 90 |
Для исправлений |
decay.halflife_days.fact |
int | 365 |
Для устойчивых фактов |
decay.halflife_days.persona |
int | 365 |
Для данных о личности/профиле |
decay.halflife_days.instruction |
int | 365 |
Для инструкций |
decay.halflife_days.summary |
int | 365 |
Для сводок, созданных консолидацией |
recall.k |
int | 8 |
Сколько записей памяти возвращать в prefetch перед каждым ходом |
recall.messages_k |
int | 4 |
Сколько сообщений истории возвращать в prefetch |
consolidate.enabled |
bool | true |
Включить этап свёртки (rollup) при ночной консолидации |
Инструменты и команды
Модель видит память как пять инструментов; человек — как команды hermes memohood.
Инструменты (доступны модели)
| Инструмент | Параметры | Что делает |
|---|---|---|
memohood_search |
query (обязателен), k (по умолчанию 8) |
Сырой поиск по записям памяти без форматирования под обычный recall-блок — список найденных записей с id, типом, оценкой и источником |
memohood_fetch |
capture_id (обязателен) |
Одна запись памяти по id вместе с историей замещений (supersede) |
memohood_recall |
query (обязателен), k (по умолчанию 10) |
Явно вспомнить факты и историю диалогов по запросу — то же самое, что автоматическое вспоминание перед каждым ходом, но по требованию и с произвольным k |
memohood_stats |
— | Статистика памяти: сколько записей, разбивка по типам, расход за 30 дней по каждому провайдеру, состояние индексации истории |
memohood_capture |
content (обязателен), kind (persona/event/preference/decision/correction/fact/instruction), pinned (да/нет) |
Явно сохранить факт в обход авто-извлечения — когда пользователь прямо просит что-то запомнить |
CLI-команды
| Команда | Что делает |
|---|---|
hermes memohood status / hermes memohood stats |
Статистика памяти (то же самое, что memohood_stats): число записей, разбивка по типам, расход за 30 дней по каждому провайдеру, состояние индексации истории |
hermes memohood reindex |
Переэмбеддинг всех записей в теневую таблицу — нужен после смены модели эмбеддингов |
hermes memohood seed [--dry-run] |
Догнать полнотекстовый индекс истории диалогов до текущего состояния — только индексация для recall, извлечение новых фактов из старой истории этим не выполняется; --dry-run показывает состояние индекса, ничего не меняя |
hermes memohood consolidate |
Вручную запустить ночную консолидацию (угасание confidence, дедуп, свёртка, перестройка индекса) — обычно она идёт по расписанию через hermes cron, эта команда для ручного прогона или отладки |
Пример использования
Ничего специально вызывать не нужно — память работает сама. Показательный сценарий из трёх сессий:
Понедельник, вы вскользь упоминаете важное:
— Кстати, у меня аллергия на пенициллин, запомни.
— Записал, учту.
Явные сигналы «запомни» и «аллергия» проходят бесплатный сигнальный скоринг — факт сохраняется без единого вызова LLM, kind: fact, и помечается pinned (аллергия — один из pinned-триггеров).
Через месяц, в новой сессии:
— Подбери антибиотик от ангины.
— Учитывая вашу аллергию на пенициллин, пенициллиновый ряд не подойдёт — вот альтернативы…
Перед ответом gate решил, что вспоминать стоит; гибридный поиск нашёл pinned-факт (за месяц он не угас — pinned исключены из decay), graph_rerank и post_recall привели выдачу в порядок, и факт подмешался в <memory-context>. Вы ни о чём не напоминали.
Позже вы передумали:
— На самом деле аллергии нет, врач пересмотрел диагноз.
— Понял, обновляю.
Сигнал «на самом деле» + противоречие старой записи запускают supersede: новая запись замещает старую, старая уходит в датированную историю (её всё ещё видно через memohood_fetch) и больше не всплывает в обычном поиске.
Какие есть ограничения?
hermes memohood seedнаполняет индекс истории для поиска, но не извлекает из старой истории новые факты — двухступенчатая экстракция работает только для новых ходов диалога, идущих после установки.- Явного инструмента «забыть факт» нет: неверную запись исправляют, попросив агента запомнить верную версию — она вытеснит старую через supersede, а старая останется только в датированной истории, не всплывая в обычном поиске.
- Оценки расходов по внешним вызовам — лучшее приближение по публичному прайсингу провайдеров, не гарантированно точный биллинг.
Частые вопросы
Забудет ли MemoHood что-то важное?
Обычные факты со временем плавно теряют вес по кривой Эббингауза и в конце концов архивируются (не удаляются физически, просто перестают всплывать в поиске). Но факты, помеченные как pinned — имя, дата рождения, аллергии, диагнозы, явное «запомни навсегда» — полностью исключены из этого угасания и остаются актуальными сколько угодно долго.
Что будет, если не задать GEMINI_API_KEY?
Экстракция спорных фактов и ночная консолидация просто не будут выполняться — плагин не упадёт и не уронит сессию, но пограничные (неочевидные) факты перестанут запоминаться, а угасание/свёртка не будут прогоняться автоматически. Явные сигналы (ключевые слова вроде «запомни», «решили», «на самом деле») продолжат запоминаться бесплатно, без LLM.
Сколько это стоит?
Копейки. По умолчанию месячный потолок — $5 на каждый из трёх провайдеров (Cloudflare, Gemini, Cohere) отдельно, и это именно потолок, а не типичный расход: обычная сессия использует малую его часть. При достижении потолка по конкретному провайдеру плагин не падает — соответствующий шаг (например, реранк) просто тихо пропускается. Текущий расход — в hermes memohood status.
Что делает hermes memohood setup?
Это мастер онбординга прямо в терминале: по одному вопросу за шаг собирает ключи Cloudflare, Cohere и Gemini, объясняет простыми словами, что каждый из них даёт (Cohere — это реранкер, «строгий редактор», пересортировывающий найденное так, что самое нужное оказывается сверху), по желанию проверяет каждый ключ живым запросом и сохраняет их в .env в замаскированном виде — целиком ключ в консоли не показывается никогда. Enter на любом шаге — пропустить. memory.provider и секцию memory.memohood в config.yaml мастер не трогает, это по-прежнему ручной шаг 2 из «Быстрого старта» выше.
Какой самый простой способ настроить MemoHood, если я только начинаю с hermes?
Запустите установщик (install.sh/install.ps1, см. «Быстрый старт» выше) — он сам ставит зависимости, копирует плагин и включает memory.provider: memohood в конфиге, без единой ручной правки. Ключи (если они вам нужны) собираются отдельно, терминальным мастером hermes memohood setup — см. предыдущий вопрос.
Переживёт ли память обновление hermes?
Да. MemoHood — плагин, лежит в ~/.hermes/plugins/memohood/ отдельно от кода самого hermes-agent, и обновления ядра его не затрагивают.
Поддерживает ли MemoHood русский язык?
Да, это одна из целей плагина: и запросы, и содержимое записей стеммингуются PyStemmer с учётом русской морфологии — запрос «договора» находит запись про «договор» без точного совпадения форм слова.
Замедляет ли MemoHood ответы агента?
Вспоминание (prefetch) идёт перед ответом и добавляет время на поиск; захват фактов (sync_turn) выполняется в фоновом потоке после того, как ответ уже показан пользователю, и не задерживает его. Ночная консолидация идёт по расписанию отдельно от диалога.
Тесты
Юнит- и компонентные тесты (включая отдельные наборы на gate, post_recall, graph_rerank и сквозной конвейер v1.1) прогоняются так — из нейтрального каталога, не изнутри папки плагина:
python -m pytest tests -q
На момент публикации: 247 passed, 1 skipped (2 live-теста сами пропускаются без ключей в ~/.hermes/.env, а не падают; для полностью офлайн-прогона добавьте -m "not integration").
Документация
Практический гайд по установке, диагностике и работе с захватом фактов — в GUIDE.md. Полная инженерная спецификация — в DESIGN_v1.md. Скилл для hermes — в skill/memohood/SKILL.md.
Made by
Сделано Maxim Skorohod — skorehood.com · YouTube · Telegram
Лицензия
MIT — copyright © 2026 Maxim Skorohod. Полный текст — в LICENSE.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found