---
name: memory
description: Instructions for opencode-memory file-based memory system (search + save + retro). Also when user says "память", "memory", "запомни", "найди в памяти".
---

# File Memory (opencode-memory)

Графовая память (Graphiti/FalkorDB) удалена — была нестабильна и забагована.
Память работает через файловую систему с keyword + semantic search — 5 TS tools (`.opencode/tools/memory-*.ts`), вызывают `python3 -m src.memory` напрямую (без wrapper-hop, без MCP-плагина).

## Архитектура (progressive enhancement)

- **Keyword search** — всегда работает (ripgrep по `.md` файлам). Не требует env vars, не требует индекса.
- **Semantic search** — включается если set `OPENAI_BASE_URL` + `OPENAI_API_KEY`. Embeddings через OpenRouter (`qwen/qwen3-embedding-8b`, 4096-dim), индекс в `.rag/index.json` (Python формат, `meta.json` с `version` key).
- **Fallback**: OpenRouter недоступен / упал → semantic возвращает `[]` → `memory-search` деградирует к keyword-only (работает, но semantic enhancement потерян). Не блокирует работу.
- **Auto-setup**: первый `memory-save` всё создаёт — `mkdir` категорий, `git init` (или `clone` если `OPENCODE_MEMORY_REMOTE` set), `post-commit` hook (auto-push) если remote set. Zero-config: новый пользователь без remote может начать писать память сразу.
- **`memory-doctor`** — read-only диагностика: проверяет ripgrep, Python `src.memory`, env vars, индекс. Не модифицирует ничего.

## Инструменты

| Инструмент | Назначение |
|---|---|
| `memory-search({ query, category? })` | Гибридный поиск (ripgrep keyword + Python semantic) |
| `memory-list({ category? })` | Список категорий / файлов |
| `memory-save()` | Commit + reindex после записи/редактирования (auto-setup: git init/clone + hook если `OPENCODE_MEMORY_REMOTE` set) |
| `memory-access({ path })` | Отметить файл как прочитанный (bump `last_accessed`/`access_count`) |
| `memory-doctor()` | Read-only диагностика: ripgrep, Python `src.memory`, env vars, index |

## Категории

`preferences` · `repos` · `technical` · `people` · `workflows` · `snippets` · `notes`

## Как работать

1. **Перед началом работы** — `memory-search` по теме
2. **В процессе** — сохранять находки сразу (контекст свежий)
3. **В конце сессии** — retrospective: что узнал → сохранить, что было в памяти → обновить, чего не хватало → создать

## Когда сохранять

- gotcha / workaround (неочевидное поведение)
- структура репозитория, команды сборки/тестов
- quirks инструментов
- коренные причины багов (root cause)
- указатели: «для X используй Y, осторожно с Z»

## Когда НЕ сохранять

- данные, которые живой API возвращает свежими каждый раз
- текущий статус тасок / PR / спринтов
- копии вики-страниц и API-документации
- то, что находится за <1 минуты из первых принципов

## Структура файла

```
---
title: Человекочитаемый заголовок
tags: [tag1, tag2]
summary: Описание в одну строку
created: YYYY-MM-DD
updated: YYYY-MM-DD
importance: high | medium | low
source: откуда информация
source_date: YYYY-MM-DD
related: [category/file.md]
---
```

## Путь для репозиториев

Default: `/root/.local/share/opencode/opencode-memory` (переопределяется через `OPENCODE_MEMORY_DIR`).

```
{memory-dir}/repos/{host}/{org}/{repo}.md
```

Используй один путь последовательно во всех примерах — default (`/root/.local/share/opencode/opencode-memory`) или override (`OPENCODE_MEMORY_DIR`), но не оба сразу.

### Формат записей

```
- [YYYY-MM-DD, PR#N] <суть>
```

Дата и PR-номер в тексте — для RAG-поиска и верификации (какой PR принёс знание).

### Что дистиллировать (durable-only)

- gotchas / workaround (неочевидное поведение)
- паттерны, конвенции репозитория
- указатели: «для X используй Y, осторожно с Z»
- коренные причины багов (root cause)

НЕ дистиллировать: статусы, «сейчас делаем», текущие таски, ephemeral контекст.

### ADR — только указатель

```
- [date, PR#N] ADR-NN: <суть> → docs/decisions/NN-title.md
```

Не копируй содержание ADR — только указатель на файл.

### Править вместо дублирования (ОБЯЗАТЕЛЬНО)

Перед добавлением записи — прочитай существующий файл. Если факт уже записан — обнови запись (bump `updated` в frontmatter, дополни детали если нужно). **НЕ создавай дубликаты.** Дубликаты раздули файлы до 600+ KB. Каждая гоча/паттерн/root cause = одна запись, не по одной на каждый PR где упоминалась.

### Ротация файлов (50 KB)

Память репо ротируется по размеру вместо inline compaction:
- один репо → один или несколько файлов по пути `{memory-dir}/repos/{host}/{org}/{repo}*.md`
- первый файл: `{repo}.md`; последующие (когда первый заморожен): `{repo}-002.md`, `{repo}-003.md`, ... (3-значный sequential, не по дате)
- порог ротации: **50 KB** (soft). Файл с размером ≥ 50 KB считается замороженным — новые записи в него НЕ пишутся, открывается следующий файл
- замороженные файлы остаются редактируемыми для dedup (обновление существующих гоч, bump `updated` в их frontmatter); новые записи в замороженный файл — НЕ пишутся
- `memory-syncer` выбирает активный файл (первый существующий с размером < 50 KB) перед каждой записью и ищет дубликаты по всем `repo*.md` (включая замороженные) — см. `memory-syncer` agent

Inline compaction удалён: память = durable выжимка (сжимать некуда), git = бесконечный backup (без отдельных archive-файлов). Receipts остаются в файлах (audit trail). Существующие большие файлы (`youtube-soft.md` 112 KB, `opencode.md` 80 KB, `opencode-config.md` 64 KB) миграции не требуют — при следующей записи откроется `-002.md`.

### Квитанция ставится всегда

Даже если durable-записей нет, квитанция обязательна:

```
- [date, PR#N] — (нет durable-записей)
```

Это подтверждает, что memory-sync фаза выполнена (audit trail).
