Одна память на двух агентов и склад с поиском

Append-only события каждого агента, детерминированный канон без LLM и Postgres с pgvector по 11 тысячам чанков диалогов и заметок.

vault/
  Agents/<agent>/events.md   append-only
  Canon/TODO · FACTS · DECISIONS  read-only
  _System/consolidate.py     единственный писатель
warehouse/
  migrations/*.sql           mem_documents, mem_chunks, mem_search
  tools/mem_search.py        вектор + FTS, RRF

Что внутри

Файлы остаются истиной, база только индекс. Любой сбой лечится пересборкой из Markdown.

11 175

чанков с эмбеддингами

732 диалога ChatGPT и Gemini плюс 130 файлов заметок, 126 МБ.

Агент пишет только в свою папку

events.md под флагом uappnd: перезапись отклоняет сама ОС. Канон собирает консолидатор.

ID ставит консолидатор

Прошлое не редактируется, ошибка исправляется новым событием со ссылкой.

Гибридный поиск

HNSW cosine и русский FTS, слияние RRF, фильтры по сфере, источнику и дате.

Громкие сбои

Дамп меньше 10 МБ или пустой ответ эмбеддера считаются ошибкой, ротация не трогает старое.

Как устроено

Две независимые части: общая память агентов на файлах и склад с индексом на Postgres.

flowchart LR
  subgraph vault
    A1[Agents/openclaw/events.md] --> C[consolidate.py<br/>id, дедуп, канон, chmod, git]
    A2[Agents/hermes/events.md] --> C
    C --> K[Canon/TODO · FACTS · DECISIONS]
  end
  subgraph warehouse
    C --> PG[(Postgres 17 + pgvector)]
    AR[экспорты ChatGPT, Gemini] --> IM[import_archive.py<br/>маскирование секретов] --> PG
    K --> BV[mem_backfill_vault.py] --> PG
    PG --> BA[mem_backfill_archive.py<br/>чанки + Ollama 768d] --> PG
    Q[mem_search.py<br/>вектор + FTS, RRF] --> PG
  end
  AG[агенты] --> Q
PythonPostgreSQL 17pgvectorOllama embeddinggemmaFTS russianlaunchd

Что было сложного

Два агента на разных движках портили общий файл

Каждый пишет только в свою папку дозаписью, Canon read-only, консолидатор детерминированный.

Склад молча лежал пять недель

Стартовый скрипт считал «already running» успехом. Теперь каждый ночной скрипт обязан вернуть ненулевой код при сбое.

Встроенный семантический поиск платформы отвалился

Один локальный Ollama embeddinggemma обслуживает и склад, и память агента, без облака.