# opencode-config Docker-based AI coding assistant with persistent memory — opencode configuration. ## Quick start ### Docker ```bash git clone https://github.com/slaid098/opencode-config.git cd opencode-config cp .env.example .env # fill in your keys docker compose up -d ``` Access at http://localhost:4096. ### Bare (without Docker) ```bash git clone https://github.com/slaid098/opencode-config.git cd opencode-config opencode # .opencode/ auto-discovered ``` ## Structure - `AGENTS.md` — global orchestrator rules (main agent = plan only, all via subagents) - `.opencode/` — project-local config (auto-discovered, zero env var) - `agents/` — subagent definitions (docs-reviewer, memory-syncer, reviewer) - `commands/` — slash commands (run-pipeline, spec, configure-opencode) - `skills/` — skill definitions (14 skills) - `tools/` — custom tools (commit, create-issue, create-pr, memory-setup, merge-pr, pipeline-status, post-docs-review, post-review, spec-status, tunnel) - `scripts/` — Python scripts (pipeline-status, spec-status, check-adr-refs, etc.) - `opencode.json` — main config (providers, MCP servers, permissions) - `app_data/workspaces/` — agent working directory - `app_data/ssh/` — SSH keys (not in git) - `src/` — Python RAG CLI (memory) - `docs/` — handoffs, decisions (ADRs), project map - `.github/workflows/` — CI workflows (ubuntu-latest) ## Configuration Copy `.env.example` to `.env` and fill in: | Variable | Description | |----------|-------------| | `AI_PROVIDER_BASE_URL` | AI provider API URL | | `AI_PROVIDER_API_KEY` | AI provider API key | | `OPENAI_BASE_URL` | Embeddings API URL (OpenRouter default) | | `OPENAI_API_KEY` | Embeddings API key (OpenRouter) | | `OPENAI_EMBEDDING_MODEL` | Embedding model (default: `qwen/qwen3-embedding-8b`) | | `OPENAI_EMBEDDING_BATCH_SIZE` | Embedding batch size (default: 50) | | `OPENCODE_SERVER_PASSWORD` | opencode server password | | `GITHUB_TOKEN` | GitHub personal access token | | `CONTEXT7_API_KEY` | Context7 MCP API key | | `OPENCODE_MEMORY_REMOTE` | Git remote for your opencode-memory fork (required) | | `MEMORY_CHUNK_SIZE` | Memory index chunk size (default: 512) | | `MEMORY_CHUNK_OVERLAP` | Memory index chunk overlap (default: 64) | | `ANTIDETECT_BROWSER_MCP_URL` | Antidetect browser MCP URL (optional) | ## Memory setup Memory uses `@mathew-cf/opencode-memory` plugin — hybrid search: ripgrep (keyword) + cloud embeddings (OpenRouter Qwen3 8B, 4096 dim, $0.01/M tokens). ### 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 MIT — see [LICENSE](LICENSE)