This repository provides a local embedding service (FastAPI + SentenceTransformer) and a Node.js plugin that wires OpenCode RAG tools to Qdrant using a YAML-first configuration.
- Run embeddings locally with a stable HTTP API.
- Keep RAG configuration explicit, validated, and YAML-first.
- Provide OpenCode tools for search, ingest, and reindexing.
- Preserve consistent data contracts for client integrations.
- FastAPI embedder in
app.py, loadingBAAI/bge-small-en-v1.5once at startup. - RAG plugin in
opencode-rag-local/that calls the embedder and Qdrant. - YAML config at
opencode-rag-local/config/rag.yamlwith strict validation.
app.py: FastAPI embedder service.requirements.txt: Python runtime dependencies.logging.yaml: Uvicorn logging configuration.opencode-rag-local/: OpenCode RAG plugin (Node.js).instructions/: Versioned operational notes and runbooks.
- Python 3.9+ (type-hinting uses
list[str]). - Node.js 18+ for the RAG plugin.
- Qdrant instance reachable at the
qdrant_urlconfigured inrag.yaml. - OpenCode configured to load the local RAG plugin.
- Apple Silicon or an environment that supports
torchMPS if you keepdevice="mps"inapp.py.
- Start the embedder service.
python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
uvicorn app:app --reload --log-config logging.yaml --port 8010
- Start Qdrant (example Docker command).
docker run --rm -p 6333:6333 -p 6334:6334 qdrant/qdrant:latest
- Set up the RAG plugin.
cd opencode-rag-local
npm run setup
- Update the OpenCode config at
~/.config/opencode/opencode.json.
POST /embed expects:
{
"texts": ["hello world", "another input"],
"normalize": true
}
Response shape:
{
"vectors": [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]],
"dim": 384,
"model": "BAAI/bge-small-en-v1.5"
}
Notes:
normalizedefaults totrue.- Vectors are returned as float32 lists in the input order.
dimis derived from the embedding width.
Edit opencode-rag-local/config/rag.yaml and keep it in sync with your runtime
services. There are no environment variable fallbacks.
Key settings:
embed_url: URL to the FastAPI embedder (default:http://localhost:8010/embed).qdrant_url: Qdrant endpoint (default:http://localhost:6333).collection: Qdrant collection name (default:opencode_memory).vector_size: Must match the embedder output (default:384).distance: Qdrant distance metric (default:Cosine).
Operational sections:
embed: embedding defaults (includingnormalize).search:top_kandtruncate_chars.chunking:chunk_sizeandchunk_overlapfor ingest.ingest: source/extension filters and size limits.retry: retry and backoff behavior.ids: namespace UUID and user ID policy.logging: plugin log level.
Run npm run setup after edits to validate the YAML.
OpenCode loads plugins from ~/.config/opencode/opencode.json. Ensure the local
RAG plugin is listed. If you already have a plugins array, append the path.
Example:
{
"plugins": [
"opencode-rag-local"
]
}
If your OpenCode version uses a different key or structure, follow your existing schema and ensure the plugin path is registered.
rag_search: search Qdrant withquery, optionaltop_k,collection.rag_upsert: upsert documents (id,text, optionalmetadata).rag_ingest: ingest files from disk with chunking and filtering options.rag_reindex: drop and re-ingest a collection.
- Node tests:
npm testinopencode-rag-local. - Python tests: not currently present; use
python -m compileall app.pyfor a quick syntax check.
- Uvicorn uses
logging.yamlfor the embedder. - The RAG plugin logs through
pino.
- The embedder model is loaded once at import time; avoid re-loading in request handlers.
- Batch size is set to 32 to keep throughput predictable.