Skip to main content
Glama

firm-memory

Слой памяти, который позволяет нашим ИИ-агентам для написания кода помнить, как эта фирма разрабатывает ПО, чтобы им не приходилось переучивать одно и то же при каждом вызове.

CodeGraph отвечает: «что делает код?» Firm Memory отвечает: «почему мы делаем это именно так?»

CodeGraph остаётся источником истины для текущего поведения кода. Память хранит контекстные инженерные знания и может устареть — поэтому когда память и текущий код расходятся, побеждает код.


Как это устроено

  OpenCode        On-call        Future agent
      └───────────────┼───────────────┘
                      │  MCP
             ┌────────▼─────────┐
             │  Firm Memory MCP │   thin transport adapter
             └────────┬─────────┘
                      │
             ┌────────▼─────────┐
             │   Firm Memory    │   taxonomy · scope · provenance · lifecycle
             └────────┬─────────┘
                      │  MemoryProvider
             ┌────────▼─────────┐
             │      mem0        │   embeddings · vector search · ranking
             └──────────────────┘

Платформа владеет смыслом понятия «память фирмы». Провайдер владеет способом её хранения и извлечения. MCP владеет тем, как агенты получают к ней доступ. В этом разделении вся суть: второго провайдера можно подключить, не меняя OpenCode и не трогая контракт MCP.


Related MCP server: Agent Memory Control Plane

Быстрый старт

pip install -e '.[mem0,pgvector,rerank,mcp,dev]'
export FIRM_MEM0_PG_DSN='postgresql://mem0:pw@db.internal:5432/mem0'
export FIRM_MEMORY_DOMAINS='execution,mcx'      # this repo's domains
export FIRM_MEMORY_CANDIDATES_PATH='.firm-memory/candidates.json'
from firm_memory import FirmMemory, MemoryScope, MemoryType

memory = FirmMemory.from_env()          # scoped to this checkout + its domains + the firm

for hit in memory.search("why does OMS reject orders after 15:20"):
    print(hit.id, hit.content, hit.provenance.reference)

proposal = memory.propose(
    "Cash strategies stop sending at 15:20 because the exchange rejects after that.",
    type=MemoryType.BUSINESS_RULE,
    scope=MemoryScope(domains=("execution",), repos=("oms", "gateway")),
    reference="mr-4821",
)
# Not stored as knowledge yet — it is queued for a human:
print(proposal.accepted, proposal.candidate_id, proposal.decision.reason)

memory.approvals.approve(proposal.candidate_id, approver="ashish")

Запустите MCP-сервер для агентов:

firm-memory-mcp        # stdio; exposes memory_search / memory_get / memory_propose / memory_correct

Пять обязательств этого пакета

1. Таксономия

Штатное извлечение провайдера заточено под потребительских ассистентов (еда, хобби, музыка). Наше — под торговые системы. Тринадцать типов, и у каждого есть описание, которое управляет извлечением:

ARCHITECTURE_DECISION · REJECTED_APPROACH · CONVENTION · REVIEW_PATTERN · BUG_FIX · TASK_LEARNING · TOOLING_SETUP · DEPENDENCY_DECISION · PERFORMANCE_FINDING · BUSINESS_RULE · PRODUCTION_ISSUE · OWNERSHIP · TERMINOLOGY

Проверяется до того, как что-либо дойдёт до провайдера. Обе записи распознаются — имя члена (BUSINESS_RULE) и стабильный сетевой slug (business_rules).

Не менее важно то, что исключено: никакого исходного кода, диффов и stack trace; никаких секретов; никаких данных об отдельных инженерах; никакого временного состояния.

2. Область применения

Независимые атрибуты, а не иерархия — потому что знания фирмы не укладываются в дерево:

{"firm": true, "domains": ["execution"], "repos": ["oms", "gateway"]}

Память, охватывающая три репозитория, хранится один раз и доступна из каждого из них. Здесь намеренно нет области уровня инженера и уровня команды: один и тот же вопрос должен возвращать одни и те же фирменные знания, кто бы ни спрашивал, а ось идентичности разрезала бы один факт на копии, которые расходятся.

3. Уровни

Ось жизненного цикла, ортогональная статусу подтверждения:

Уровень

Что содержит

Привязан к задаче?

EPISODIC

Рабочая память по каждому MR — выводы и их решения

Да, обязательно

DURABLE

Очищенное знание, прошедшее шлюз подтверждения

Никогда

INDEX

Одна дословная карточка на каждый закрытый issue/MR, документной формы

Никогда

По умолчанию поиск исключает EPISODIC. Этот дефолт несёт важную нагрузку: для векторного хранилища отсутствие фильтра задачи означает «не важно», а не «не задано», поэтому без него черновая память каждого MR попадала бы в обычный поиск. На это поведение есть контрактный тест.

4. Происхождение и жизненный цикл

Каждая запись памяти несёт свой источник, поэтому инженер может проследить, откуда она взялась — из MR, issue или интервью — и исправить её.

Candidate ─► taxonomy / scope / provenance checks ─► human approval ─► provider.insert()

V1 целиком подтверждена человеком; степень уверенности фиксируется с самого начала, чтобы автоматику можно было включить позже, без миграции. Бизнес-правила, архитектурные решения, фирменные соглашения и критичные для продакшена знания всегда требуют человека, какой бы ни была уверенность.

Ничего не удаляется. Исправление называется преемником и помечает запись; протокол содержит и то, что решение было принято, и то, что его отменили.

5. Надёжность

Память работает по принципу best effort. Чтения никогда не бросают исключений: сбой провайдера выход за пределы таймаута даёт пустой результат и записанную метрику, так что неудачное вспоминание не может провалить review кода. Записи же бросают исключения: молча потерять память, которую инженер только что подтвердил, было бы хуже, чем ошибка.


Параметры конфигурации

Настройки платформы не зависят от провайдера; настройки провайдера читаются самим провайдером. Именно разделение превращает смену провайдера в изменение конфигурации.

Переменная

По умолчанию

Значение

FIRM_MEMORY_PROVIDER

mem0

Какой провайдер использовать

FIRM_MEMORY_LIMIT

5

Результатов на один поиск

FIRM_MEMORY_MIN_SCORE

0.3

Минимальная релевантность

FIRM_MEMORY_TIMEOUT_SECONDS

2.0

Лимит ожидания

FIRM_MEMORY_DOMENS

—

Домены, к которым относится эта рабочая копия

FIRM_MEMORY_REPO

(git remote)

Переопределить slug репозитория

FIRM_MEMORY_CANDIDATES_PATH

(в процессе)

Где кандидаты ждут человека

FIRM_MEMORY_AUTO_APPROVE

off

Автоматизация на основе уверенности

FIRM_MEM0_PG_DSN

обязательно

Строка подключения к pgvector

FIRM_MEM0_COLLECTION

mem0_firm

Имя коллекции

FIRM_MEM0_POOL_OWNER

firm

user_id, задающий имя пула

FIRM_MEM0_RERANK

on

Локальный кросс-энкодер reranking

FIRM_MEM0_REPO, FIRM_MEM0_TOP_K, FIRM_MEM0_THRESHOLD и FIRM_MEM0_FIRM_OWNER всё ещё используются, чтобы существующее развертывание не менялось при обновлении.

Развёртывание самодостаточно и не имеет внешнего трафика. Бизнес-правила, например «MCX orders always route through Risk Engine A», ближе к стратегической интеллектуальной собственности, чем к комментариям в коде, а пул получает объединение access control всех репозиториев, которые его питают.


Структура

src/firm_memory/
├── models.py          canonical Memory · status · tier
├── taxonomy.py        the firm's vocabulary and its exclusions
├── scope.py           firm / domains / repos
├── provenance.py      where a memory came from
├── lifecycle.py       approval policy and status transitions
├── memory.py          the API agents and applications import
├── config.py          platform settings
├── metrics.py         failure and latency counters
├── repo.py            deterministic repo identity
├── providers/
│   ├── base.py        the interface: insert · search · get · update
│   ├── registry.py    configuration-driven selection
│   ├── inmemory.py    dependency-free provider for tests and local use
│   └── mem0/          namespace · filters · mapping · settings · provider
├── ingestion/
│   ├── approval.py    the human gate
│   └── store.py       where candidates wait
└── mcp/
    ├── tools.py       the four tools (no SDK dependency)
    └── server.py      thin transport adapter

tests/
├── unit/          modules in isolation
├── integration/   the API across layers, incl. provider swap
├── contract/      against the real mem0 filter pipeline
└── mcp/           the agent-facing surface

Разработка

.venv/bin/python -m pytest -q                       # 261 tests (1 skipped without the mcp extra)
.venv/bin/python -m pytest --cov --cov-report=term   # 94% coverage
.venv/bin/python -m ruff check src tests

Контрактные тесты — вот на что стоит смотреть. Они прогоняют наши фильтры через настоящее предобработка mem0 и SQL-построитель pgvector, фиксируя ограничения, найденные при чтении исходников: плоские ветки OR, плоские ключи метаданных, списки со значением one of и ключ верхнего уровня, который требует Memory.search. Если обновление mem0 их ломает, они падают громко, а не превращают пул в тихий пустой результат.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to capture, store, and retrieve durable learnings from projects via MCP tools, providing a queryable memory of product and technical lessons across repos.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides coding agents with governed semantic memory and code-graph context via MCP, enabling code-linked recall, blast-radius impact analysis, and lifecycle-aware memory management.
    3
    Apache 2.0