Developer Guide - Building with OpenContext
August 18, 2026 ยท View on GitHub
This guide shows you how to integrate OpenContext into your application. We'll cover common integration patterns, backend selection, and production deployment.
Quick Integration Checklist
Before you integrate, decide:
- Storage backend: SQLite (desktop), Postgres (server), or Chroma (managed)
- Embedding provider: Local (no API key) or cloud (OpenRouter, OpenAI)
- Transport surface: Direct import, HTTP server, or MCP
- Deployment: Self-hosted or containerized
Integration Patterns
Pattern 1: Embedded in a Node.js App
The simplest integration - import directly into your code:
pnpm add @melandlabs/opencontext
// memory-service.ts
import { createMemoryStore, getRawMessageManager } from "@melandlabs/opencontext";
let store: Awaited<ReturnType<typeof createMemoryStore>>;
export async function initMemory() {
store = await createMemoryStore({
dbPath: process.env.MEMORY_DB_PATH || "./memory.db",
});
}
export async function rememberFact(userId: string, content: string) {
const messages = await getRawMessageManager();
const now = Date.now();
await messages.storeMessages([{
messageId: `msg-${now}-${userId}`,
userId,
content,
platform: "my-app",
botId: "default",
timestamp: now,
createdAt: now,
}]);
}
export async function recallFacts(userId: string, query: string, limit = 10) {
return store.search({ userId, query, limit });
}
Use it in your app:
// app.ts
import { initMemory, rememberFact, recallFacts } from "./memory-service";
async function handleUserMessage(userId: string, message: string) {
// Remember what the user said
await rememberFact(userId, message);
// Recall relevant context
const context = await recallFacts(userId, `Context for: ${message}`);
// Use context in your response
return generateResponse(message, context.results);
}
Pattern 2: HTTP Server (Microservice)
Run OpenContext as a standalone HTTP service:
# Start the server
npx @melandlabs/opencontext http \
--embedding-provider local \
--memory-backend sqlite-vec \
--host 0.0.0.0 \
--port 7421
Or use npx without installing:
npx -y @melandlabs/opencontext http \
--embedding-provider local \
--memory-backend sqlite-vec
Call from your app:
// memory-client.ts
const MEMORY_URL = process.env.MEMORY_URL || "http://127.0.0.1:7421";
async function recallFacts(userId: string, query: string) {
const response = await fetch(`${MEMORY_URL}/v1/search`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId, query, limit: 10 }),
});
return response.json();
}
async function rememberFact(userId: string, content: string) {
const now = Date.now();
const response = await fetch(`${MEMORY_URL}/v1/raw-messages`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
userId,
embedOnInsert: true,
messages: [{
messageId: `msg-${now}`,
role: "user",
content,
platform: "my-app",
botId: "default",
timestamp: now,
createdAt: now,
}],
}),
});
return response.json();
}
Pattern 3: MCP Server (for AI Agents)
Integrate with coding agent integration:
Installation (coding agent integration):
Add the OpenContext MCP server to your coding agent's configuration:
{
"mcpServers": {
"opencontext": {
"command": "npx",
"args": [
"-y",
"@melandlabs/opencontext",
"mcp",
"--embedding-provider", "local",
"--memory-backend", "sqlite-vec",
"--name", "MyMemory",
"--version", "1.0.0"
]
}
}
}
Tools exposed:
memory.health- Check if the server is runningmemory.search- Search memory (setsynthesize: truefor LLM-synthesized answers)memory.writeRawMessage- Store messagesmemory.getRawMessage- Retrieve a message
Using from an agent:
// Your agent can now call these tools via MCP
// Your coding agent will automatically expose them
Backend Selection Guide
Choose your backend based on your deployment:
Desktop App (Tauri, Electron)
import { createMemoryStore } from "@melandlabs/opencontext";
const store = await createMemoryStore({
db: {
type: "sqlite-vec",
path: "./memory.db", // Local file
},
});
Pros: No external dependencies, fast local access Cons: Single-user only
Server / Multi-user
import { createMemoryStore, registerPostgresFactory } from "@melandlabs/opencontext";
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
// Register Postgres factory
const client = postgres(process.env.DATABASE_URL!);
const db = drizzle(client);
registerPostgresFactory(async () => ({
storeMessages: async (messages) => { /* your impl */ },
getMessages: async (opts) => { /* your impl */ },
// ... implement PostgresRawMessageManagerLike
}));
const store = await createMemoryStore({
db: { getDb: () => db },
});
Pros: Multi-user, scalable, backups Cons: Requires Postgres setup
Managed Vector Store (Chroma)
const store = await createMemoryStore({
dbPath: "./raw.db",
vector: {
backend: "chroma",
chroma: {
url: process.env.CHROMA_URL || "http://127.0.0.1:8000",
rawMessagesCollection: "raw_messages",
insightsCollection: "insights",
},
},
});
Pros: Scalable vector search, separate storage Cons: Additional service to run
Configuration Examples
Full Local Setup (No API Keys)
import { createMemoryStore, LocalTransformersEmbeddingProvider } from "@melandlabs/opencontext";
const embedder = new LocalTransformersEmbeddingProvider({
modelName: "Xenova/all-MiniLM-L6-v2",
});
const store = await createMemoryStore({
dbPath: "./memory.db",
unified: {
embedQuery: async ({ query }) => {
return await embedder.embedQuery(query);
},
},
});
Cloud Embeddings (Better Quality)
const store = await createMemoryStore({
db: {
type: "sqlite-vec",
path: "./memory.db",
},
unified: {
embedQuery: async ({ query }) => {
const response = await fetch("https://openrouter.ai/api/v1/embeddings", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.OPENROUTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "text-embedding-3-small",
input: query,
}),
});
const data = await response.json();
return data.data[0].embedding;
},
},
});
Production Deployment
Docker Compose
# docker-compose.yml
version: '3.8'
services:
opencontext:
image: node:22
working_dir: /app
command: npx -y @melandlabs/opencontext http --host 0.0.0.0 --port 7421 --embedding-provider local --memory-backend sqlite-vec
volumes:
- ./data:/app/data
environment:
- MEMORY_STORE_DB_PATH=/app/data/memory.db
ports:
- "7421:7421"
restart: unless-stopped
systemd Service
# /etc/systemd/system/opencontext.service
[Unit]
Description=OpenContext Memory Service
After=network.target
[Service]
Type=simple
User=opencontext
WorkingDirectory=/opt/opencontext
ExecStart=/usr/bin/npx -y @melandlabs/opencontext http --host 0.0.0.0 --port 7421 --embedding-provider local --memory-backend sqlite-vec
Restart=always
RestartSec=10
Environment=MEMORY_STORE_DB_PATH=/var/lib/opencontext/memory.db
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable opencontext
sudo systemctl start opencontext
sudo systemctl status opencontext
Environment Variables
All CLI flags have environment variable equivalents:
| Flag | Environment Variable | Default |
|---|---|---|
--port | MEMORY_HTTP_PORT | 7421 |
--host | MEMORY_HTTP_HOST | 127.0.0.1 |
--embedding-provider | EMBEDDING_PROVIDER | none |
--embedding-model | EMBEDDING_MODEL | (provider default) |
--memory-backend | MEMORY_BACKEND | none |
--insights-backend | INSIGHTS_BACKEND | none |
--knowledge-backend | KNOWLEDGE_BACKEND | none |
--chroma-url | CHROMA_URL | (required for chroma) |
Testing Your Integration
// test/memory.test.ts
import { createMemoryStore, getRawMessageManager } from "@melandlabs/opencontext";
import { describe, it, expect, beforeAll } from "vitest";
describe("Memory Integration", () => {
let store: Awaited<ReturnType<typeof createMemoryStore>>;
beforeAll(async () => {
process.env.MEMORY_STORE_DB_PATH = ":memory:"; // In-memory SQLite
store = await createMemoryStore();
});
it("should remember and recall facts", async () => {
const messages = await getRawMessageManager();
const now = Date.now();
await messages.storeMessages([{
messageId: "test-1",
userId: "test-user",
content: "Test fact",
platform: "test",
botId: "test-bot",
timestamp: now,
createdAt: now,
}]);
const results = await store.search({
userId: "test-user",
query: "test",
limit: 5,
});
expect(results.count).toBe(1);
expect(results.results[0].content).toContain("Test");
});
});
Troubleshooting
Module not found errors
# Reinstall dependencies
rm -rf node_modules pnpm-lock.yaml
pnpm install
Native module build failures
# Install build tools (macOS)
xcode-select --install
# Install build tools (Ubuntu)
sudo apt-get install build-essential python3
# Rebuild native modules
pnpm rebuild
Database locked errors
SQLite doesn't support concurrent writes. Use:
// Connection pooling or write queue
// Or switch to Postgres for multi-writer scenarios
Next Steps
- ๐ Getting Started - Installation guide
- ๐ค User Guide - Core concepts
- ๐ Advanced Usage - Production patterns
- ๐ Best Practices - Optimization tips
Sources: