From 4cb50a4824924ce668f91e8691414b9468cf7ea4 Mon Sep 17 00:00:00 2001 From: Sergey <93754860+slaid098@users.noreply.github.com> Date: Sun, 26 Jul 2026 20:25:21 +0300 Subject: [PATCH] docs(readme): add memory setup instructions with troubleshooting (#86) * docs(readme): add memory setup instructions with troubleshooting * docs(handoff): add handoff + ADR-038 for PR #86 --------- Co-authored-by: opencode-agent --- README.md | 112 +++++++++++++++++- ...-pr-86-readme-memory-setup-instructions.md | 29 +++++ .../pr-86-readme-memory-setup-instructions.md | 29 +++++ 3 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 docs/decisions/038-pr-86-readme-memory-setup-instructions.md create mode 100644 docs/handoff/pr-86-readme-memory-setup-instructions.md diff --git a/README.md b/README.md index dee2fac..7d74571 100644 --- a/README.md +++ b/README.md @@ -61,11 +61,115 @@ Copy `.env.example` to `.env` and fill in: ## Memory setup -Memory uses `@mathew-cf/opencode-memory` plugin (hybrid search: ripgrep + cloud embeddings (OpenRouter Qwen3 8B)). +Memory uses `@mathew-cf/opencode-memory` plugin — hybrid search: ripgrep (keyword) + cloud embeddings (OpenRouter Qwen3 8B, 4096 dim, $0.01/M tokens). -- `OPENCODE_MEMORY_DIR` env var points to memory directory (default: `/root/.local/share/opencode/opencode-memory`) -- `OPENCODE_MEMORY_REMOTE` must point at your git remote — fork the upstream [`slaid098/opencode-memory`](https://github.com/slaid098/opencode-memory) repo and set the URL in `.env` -- Run `.opencode/scripts/setup-memory.sh` to initialize memory repo +### How it works + +``` +opencode (plugin) → rag.js wrapper → python3 -m src.memory → OpenRouter API + ↘ ripgrep (keyword search, parallel) +``` + +- `memory_search` runs both paths in parallel, merges results by score +- `memory_save` commits to memory repo, post-commit hook auto-pushes, then incremental reindex (only changed file, ~1 sec) +- First full reindex: ~4 min for 78 files / 2379 chunks via OpenRouter +- Index format: `.rag/index.json` (embeddings) + `.rag/meta.json` (SHA256 + version) + `.rag/.lock` (flock) + +### Prerequisites + +1. **Fork the memory repo**: fork [`slaid098/opencode-memory`](https://github.com/slaid098/opencode-memory) to your GitHub account +2. **Get OpenRouter API key**: sign up at [openrouter.ai](https://openrouter.ai), create API key (Qwen3 8B = $0.01/M tokens; $9 balance ≈ 700K incremental saves) +3. **Fill `.env`** (see [Configuration](#configuration) table above): + ``` + OPENAI_BASE_URL=https://openrouter.ai/api/v1 + OPENAI_API_KEY=sk-or-v1-... + OPENAI_EMBEDDING_MODEL=qwen/qwen3-embedding-8b + OPENAI_EMBEDDING_BATCH_SIZE=50 + OPENCODE_MEMORY_REMOTE=https://github.com//opencode-memory.git + OPENCODE_MEMORY_DIR=/root/.local/share/opencode/opencode-memory + GITHUB_TOKEN=ghp_... + ``` + +### Initialize + +#### In Docker (recommended) + +```bash +git clone https://github.com/slaid098/opencode-config.git +cd opencode-config +cp .env.example .env # fill in keys (see Prerequisites) +docker compose up -d +``` + +Memory initializes automatically on first container start (via `memory-setup` tool). To re-run manually: + +```bash +docker exec opencode bash -c "cd /root/workspace/opencode-config && .opencode/scripts/setup-memory.sh" +``` + +#### Bare metal + +```bash +git clone https://github.com/slaid098/opencode-config.git +cd opencode-config +uv sync # install Python deps +cp .env.example .env # fill in keys +.opencode/scripts/setup-memory.sh +``` + +### setup-memory.sh steps + +The script is idempotent — safe to re-run: + +1. Create `OPENCODE_MEMORY_DIR` if missing +2. Clone memory repo (or `pull --ff-only` if exists) +3. Verify remote origin matches `OPENCODE_MEMORY_REMOTE` +4. Install post-commit hook (auto-push on `memory_save`) +5. Build RAG index if `.rag/index.json` missing (full reindex via OpenRouter, ~4 min) +6. Generate JS wrapper at `node_modules/@mathew-cf/rag-cli/bin/rag.js` (delegates to Python CLI; original backed up to `.orig`) + +### Verify it works + +```bash +# Wrapper should be Python shim (~10 lines), not Rust binary (71 lines) +cat node_modules/@mathew-cf/rag-cli/bin/rag.js + +# Meta should show our format (version + sha256), not Rust (model_id + hidden_size) +cat $OPENCODE_MEMORY_DIR/.rag/meta.json | python3 -m json.tool | head -5 + +# .rag/ should contain index.json + meta.json + .lock (no index.bin) +ls -la $OPENCODE_MEMORY_DIR/.rag/ + +# Search end-to-end (through wrapper, as plugin does) +node node_modules/@mathew-cf/rag-cli/bin/rag.js search "docker compose bind mount" \ + -i $OPENCODE_MEMORY_DIR/.rag -k 3 --json +``` + +### Troubleshooting + +| Symptom | Cause | Fix | +|---------|-------|-----| +| `Semantic search is unavailable` in opencode | Wrapper not generated or rag-cli not installed | Re-run `setup-memory.sh` | +| Search returns results but no scores | Using Rust rag-cli (old wrapper) | Check `rag.js` is Python shim (10 lines); re-run `setup-memory.sh` | +| `Index version mismatch, full reindex` on every run | meta.json missing or stale | Delete `.rag/` and re-run `setup-memory.sh` | +| `OPENAI_BASE_URL env var not set` | .env not loaded | For Docker: `docker compose up -d --force-recreate`; for bare: ensure `.env` in CWD | +| 429 rate limit from OpenRouter | Batch too large or too fast | Reduce `OPENAI_EMBEDDING_BATCH_SIZE` (default 50, max 100 for OpenRouter) | +| Stale Rust artifacts (`index.bin` in `.rag/`) | Migrating from old rag-cli | `rm -rf $OPENCODE_MEMORY_DIR/.rag/` then re-run `setup-memory.sh` | + +### Environment variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `OPENCODE_MEMORY_DIR` | `/root/.local/share/opencode/opencode-memory` | Memory repo location | +| `OPENCODE_MEMORY_REMOTE` | — (required) | Git remote for your opencode-memory fork | +| `OPENAI_BASE_URL` | — (required) | Embeddings API URL (OpenRouter: `https://openrouter.ai/api/v1`) | +| `OPENAI_API_KEY` | — (required) | OpenRouter API key | +| `OPENAI_EMBEDDING_MODEL` | `qwen/qwen3-embedding-8b` | Embedding model (4096 dim) | +| `OPENAI_EMBEDDING_BATCH_SIZE` | `50` | Chunks per API call (OpenRouter max 100) | +| `MEMORY_CHUNK_SIZE` | `512` | Chunk size in characters | +| `MEMORY_CHUNK_OVERLAP` | `64` | Overlap between chunks | +| `MEMORY_WRAPPER_PATH` | (auto-detected) | Override rag.js wrapper path (for tests) | +| `MEMORY_WRAPPER_PYTHON` | (auto-detected) | Override Python binary for wrapper (for tests) | ## License diff --git a/docs/decisions/038-pr-86-readme-memory-setup-instructions.md b/docs/decisions/038-pr-86-readme-memory-setup-instructions.md new file mode 100644 index 0000000..83d5617 --- /dev/null +++ b/docs/decisions/038-pr-86-readme-memory-setup-instructions.md @@ -0,0 +1,29 @@ +# ADR-038: README memory setup instructions + +## Статус +Accepted (2026-07-26) + +## Контекст + +После серии PR #75 (refactor) → #77 (wrapper) → #83 (incremental index) → #85 (setup bug fix + docs align) память заработала end-to-end: plugin → Python wrapper → OpenRouter Qwen3 8B → semantic search. Однако README не содержал пошаговой инструкции развёртывания — только 3 строки с общими словами. Новый пользователь не мог развернуть память без чтения исходников setup-memory.sh и embedder.py. + +Дополнительно: после обнаружения бага в setup-memory.sh step 5 (PR #85, проверка `.rag` dir вместо `index.json`) стало ясно что нужен раздел Troubleshooting — пользователи с Rust legacy артефактами (`index.bin`) могут столкнуться с неработающей памятью. + +## Решение + +Расширить секцию `## Memory setup` в README.md до 7 подсекций: +1. How it works — диаграмма пути, краткое описание hybrid search +2. Prerequisites — fork, OpenRouter key, .env пример +3. Initialize — Docker (auto) + bare metal (manual) пути +4. setup-memory.sh steps — 6 шагов скрипта (idempotent) +5. Verify it works — 4 команды end-to-end проверки +6. Troubleshooting — таблица 6 частых проблем + fixes +7. Environment variables — полная таблица 10 vars + +Формат — таблицы и code blocks (не prose), чтобы копипастить команды напрямую. Стиль — как существующий README (English, concise). + +## Альтернативы + +- **Отдельный MEMORY.md файл** — отклонено: дробит документацию, README уже содержит Structure/Configuration секции +- **Только в wiki** — отклонено: wiki не versioned, теряется при fork +- **Оставить как было (3 строки)** — отклонено: порог входа слишком высокий, приводит к баг-репортам вида "память не работает" без контекста \ No newline at end of file diff --git a/docs/handoff/pr-86-readme-memory-setup-instructions.md b/docs/handoff/pr-86-readme-memory-setup-instructions.md new file mode 100644 index 0000000..4cc7d6b --- /dev/null +++ b/docs/handoff/pr-86-readme-memory-setup-instructions.md @@ -0,0 +1,29 @@ +--- +pr: 86 +title: docs(readme): add memory setup instructions with troubleshooting +--- + +## Что сделано + +Расширил секцию `## Memory setup` в README.md — с 3 строк до полной инструкции: +- **How it works** — ASCII-диаграмма пути plugin → wrapper → Python CLI → OpenRouter +- **Prerequisites** — fork memory repo, получить OpenRouter key, заполнить .env (с примером блока) +- **Initialize** — два пути: Docker (recommended, авто-инициализация) + bare metal (uv sync + ручной запуск) +- **setup-memory.sh steps** — 6 шагов что делает скрипт (idempotent, безопасно перезапускать) +- **Verify it works** — 4 команды для end-to-end проверки (wrapper content, meta format, .rag/ listing, search через wrapper) +- **Troubleshooting** — таблица из 6 частых проблем + fixes (semantic unavailable, no scores, version mismatch, env not set, 429 rate limit, stale Rust artifacts) +- **Environment variables** — полная таблица из 10 vars с defaults и описанием + +## Почему + +После PR #75/#77/#83 память заработала end-to-end, но README не объяснял как её развернуть с нуля. Пользователь (и будущие контрибьюторы) не знали: какие ключи нужны, как проверить что wrapper перезаписан, что делать со stale Rust артефактами. Теперь README содержит полный flow от clone до verify — снижает порог входа и количество вопросов. + +## Pending + +— + +## Watch out + +- Troubleshooting таблица ссылается на `index.bin` (Rust артефакт) — если через 2-3 месяца все мигрируют на Python CLI, строку можно убрать +- Environment variables таблица дублирует часть Configuration таблицы выше — намеренно (Memory vars сгруппированы отдельно для контекста) +- Verify commands используют `$OPENCODE_MEMORY_DIR` — в Docker это `/root/.local/share/opencode/opencode-memory` (задаётся в docker-compose.yml), на bare metal — env var \ No newline at end of file