Content
# OpenBrain
Fully local AI memory for Apple Silicon. Gives any MCP client persistent semantic memory with vector search — no cloud APIs required.
Everything runs on your Mac: embeddings via MLX on Metal GPU, enrichment via a local LLM, storage in PostgreSQL with pgvector.
Built on the [OB1](https://github.com/NateBJones-Projects/OB1) architecture by [@NateBJones-Projects](https://github.com/NateBJones-Projects).
## Architecture

A Bun MCP server brokers requests from any MCP client to PostgreSQL+pgvector for storage, a local MLX embedding service for vectorization, and a local mlx-lm server for enrichment. Redis caches embeddings and search results. A separate Bun web UI reads directly from PostgreSQL. Everything runs on-device — no cloud APIs in the data path.
## Requirements
- **Apple Silicon Mac** (M1/M2/M3/M4) — required for MLX GPU inference
- **16 GB RAM minimum** for the default model (`Qwen3-8B-4bit`, ~4.5 GB); 32 GB+ lets you run larger enrichment models
- macOS 14+
- [Node.js](https://nodejs.org) 22+ (LTS v24 recommended) and [pnpm](https://pnpm.io) 11+
- [Bun](https://bun.sh) 1.1+ as the runtime (we use `pnpm` to install deps; `bun` to run them)
- Python 3.13+ with [uv](https://docs.astral.sh/uv/)
- [PostgreSQL 17](https://www.postgresql.org/) with [pgvector](https://github.com/pgvector/pgvector) extension
- [Redis](https://redis.io/) (optional but recommended)
- [Firecrawl](https://firecrawl.dev) API key — used for all web page scraping
- [yt-dlp](https://github.com/yt-dlp/yt-dlp) (optional — YouTube transcript extraction)
### Firecrawl
[Firecrawl](https://firecrawl.dev) handles all web-page scraping (markdown extraction, JS rendering, etc.). It's a cloud service; set your key in `.env`:
```
FIRECRAWL_API_KEY=fc-...
```
Without a key, `POST /api/ingest` for web URLs will return an error.
### Quick install (recommended)
```bash
bash installer/bootstrap.sh
```
This runs the full chain: prerequisites (Homebrew packages, Bun, Python venv with `mlx-lm`), database setup, schema, and launchd services. Idempotent — safe to re-run.
### Manual install
If you'd rather install the prerequisites yourself:
```bash
# Homebrew packages
brew install postgresql@17 pgvector redis uv yt-dlp pnpm
brew services start postgresql@17
brew services start redis
# Node 22+ via nvm (skip if you already have one)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
. ~/.nvm/nvm.sh && nvm install --lts && nvm alias default 'lts/*'
# Optional, for Gmail integration via the agents/ subsystem
brew install gogcli
# Bun via its official installer (no Homebrew formula). We use Bun as the
# runtime (Bun.serve, Bun.spawn) but never `bun install` — that hits a
# macOS SIP/provenance issue. pnpm handles deps.
curl -fsSL https://bun.sh/install | bash
```
After installing Bun, restart your shell (or `source ~/.zshrc`) so the `bun` binary is on your `PATH`.
## Quick Start
```bash
# 1. Clone and enter the repo
git clone https://github.com/sajennings79/apple-silicon-openbrain.git
cd apple-silicon-openbrain
# 2. Configure environment
cp .env.example .env
# Edit .env if needed (defaults work for local setup)
# 3. Run setup (creates database, installs Bun + Python deps)
bash scripts/setup.sh
# 4. Create a Python venv for the LLM enrichment server
python3 -m venv ~/.mlx-venv
~/.mlx-venv/bin/pip install mlx-lm
# 5. Start all services (installs as launchd daemons)
bash scripts/install-services.sh
# 6. Verify everything is running
bun run health
```
Or start services manually:
```bash
bun run dev # MCP server (port 6277)
cd embed-service && uv run server.py # Embedding service (port 6278)
~/.mlx-venv/bin/python -m mlx_lm.server \
--model mlx-community/Qwen3-8B-4bit \
--port 8000 --max-tokens 4096 # LLM enrichment (port 8000)
bun run ui # Web UI (port 6279)
```
## First Run: Model Downloads
Models are pulled from Hugging Face Hub the first time each service starts — there's no separate download step. Both services block on startup until the download completes, then come online.
| Model | Size | Used by | Triggered by |
|-------|------|---------|--------------|
| `mlx-community/Qwen3-Embedding-0.6B-4bit-DWQ` | ~400 MB | Embedding service (`:6278`) | FastAPI startup |
| `mlx-community/Qwen3-8B-4bit` (default) | ~4.5 GB | LLM enrichment (`:8000`) | `mlx_lm.server` startup |
The default LLM is sized for 16 GB RAM systems. To trade RAM for quality, override `LLM_MODEL` in `.env` (and the matching `--model` arg in `~/Library/LaunchAgents/com.openbrain.llm.plist`):
| RAM | Suggested model | Disk |
|-----|-----------------|------|
| 16 GB (default) | `mlx-community/Qwen3-8B-4bit` | ~4.5 GB |
| 32 GB | `mlx-community/Qwen3.6-27B-4bit` (dense) or `mlx-community/Qwen3.6-35B-A3B-4bit` (MoE) | ~17 GB |
| 64 GB+ | `mlx-community/Qwen3.5-122B-A10B-4bit` | ~60 GB |
All models are public repos — no Hugging Face token required. Files cache to `~/.cache/huggingface/hub/` and subsequent starts run fully offline.
If you installed the launchd services, the first-run download happens silently in the background. Watch progress with:
```bash
tail -f logs/embed.log # embedding model (~30s on fast connection)
tail -f logs/llm.log # ~2 min for the default 8B model on a fast connection
```
`bun run health` will report the LLM service as down until its download finishes. Interrupted downloads resume on the next start.
## MCP Client Configuration
OpenBrain exposes both HTTP and stdio MCP transports. Configure your client to point at whichever it supports.
**HTTP transport** (recommended — one shared server for all clients):
```json
{
"mcpServers": {
"openbrain": {
"type": "http",
"url": "http://localhost:6277/mcp"
}
}
}
```
**stdio transport** (for clients that spawn the server as a subprocess):
```json
{
"mcpServers": {
"openbrain": {
"type": "stdio",
"command": "bun",
"args": ["run", "/path/to/openbrain/src/stdio.ts"]
}
}
}
```
The exact config-file location depends on your client (e.g. `.mcp.json` in a project root, or a global config under your home directory).
## MCP Tools
| Tool | Description |
|------|-------------|
| **StoreMemory** | Store text with automatic embedding, LLM enrichment (summary, tags, entities), and cross-memory linking |
| **SearchMemory** | Semantic vector search with optional filters (type, source, tags, date range) |
| **RecallMemory** | Retrieve a specific memory by UUID |
| **ListMemories** | Paginated list with filters |
| **UpdateMemory** | Update content or metadata; re-embeds and re-enriches on content changes |
| **DeleteMemory** | Soft-delete a memory by UUID |
## Services
| Service | Port | Purpose |
|---------|------|---------|
| MCP Server | 6277 | MCP protocol + URL ingestion API |
| Embedding Service | 6278 | Local MLX embeddings (Qwen3-Embedding-0.6B, 1024-dim) |
| LLM Server | 8000 | Local MLX enrichment (Qwen3-8B by default) |
| Web UI | 6279 | Dashboard for browsing and searching memories |
| PostgreSQL | 5432 | Memory storage with pgvector |
| Redis | 6379 | Embedding + search result caching |
## Web UI
The web UI at `http://localhost:6279` provides:
- Memory search and browsing with tag/source/type filters
- Dashboard with statistics (total memories, per source, per type)
- Monthly histogram and 30-day sparkline
- New memory creation form
- Tag management
## URL Ingestion
Save web pages and YouTube transcripts directly to memory using the bookmarklet.
1. Open `scripts/bookmarklet.html` in your browser
2. Drag the bookmarklet link to your bookmarks bar
3. Click it on any page to save the content to OpenBrain
**Web pages** are scraped via [Firecrawl](https://firecrawl.dev) (markdown extraction, JS rendering). Set `FIRECRAWL_API_KEY` in `.env` — without it, web ingestion will error.
**YouTube URLs** are handled locally via `yt-dlp` (install: `brew install yt-dlp`). Transcripts are extracted and stored with video metadata.
## Gradual Setup
You don't need all services running to get started:
1. **Minimum**: PostgreSQL + Embedding Service + MCP Server — gives you store and search
2. **Add enrichment**: Start the mlx-lm server — memories get auto-enriched with summaries and tags
3. **Add caching**: Start Redis — faster repeated searches and embedding lookups
4. **Add UI**: Start the web UI — browse and manage memories visually
5. **Add ingestion**: Set `FIRECRAWL_API_KEY` in `.env` and install the bookmarklet — save web content from your browser.
To skip enrichment entirely (e.g., while setting up), set `DISABLE_ENRICHMENT=true` in `.env`.
## Sources (recurring ingestion)
OpenBrain pulls content into memory on a schedule. Each **source** is a row in the `sources` table with a kind (`rss`, `mail`, or `webpage`), config, and an interval.
```bash
# Create an RSS source via the REST API:
echo '{"kind":"rss","name":"HN","config":{"feedUrl":"https://news.ycombinator.com/rss"},"intervalSeconds":3600}' \
| curl -X POST http://localhost:6277/api/sources -H 'content-type: application/json' --data @-
# Sync now:
curl -X POST http://localhost:6277/api/sources/<id>/sync
# Sync everything that's due:
curl -X POST http://localhost:6277/api/sources/poll-due
```
The Mac app (Phase 3+) drives `poll-due` from an hourly timer and exposes a UI for source CRUD. Until then, talk to the REST API directly. (The timer is just a heartbeat — each source's own `intervalSeconds` decides when it's actually due.)
### Mail sources via `gog`
To pull Gmail into memory, install [gogcli](https://github.com/steipete/gogcli) and authenticate:
```bash
brew install gogcli
gog auth add you@gmail.com
```
Then create a `mail` source:
```json
{
"kind": "mail",
"name": "Personal Gmail (last day)",
"config": {
"account": "you@gmail.com",
"query": "newer_than:1d -in:promotions -in:spam -in:trash",
"maxMessages": 25
},
"intervalSeconds": 900
}
```
**Important**: launchd-managed services have no TTY for `gog`'s keyring password prompt. Set `GOG_KEYRING_PASSWORD` in `.env` (gitignored) to your gog keyring password, then restart the MCP service. Without this, mail syncs will fail with `"no TTY available for keyring file backend password prompt"`.
## Recurring agents
OpenBrain ships with a small **starter pack** of prompt-driven agents that run on a schedule, query the memory store, call the local LLM, and write the result back as a new memory. All of this happens locally — no API keys.
```bash
# Run a shipped agent once, see the output:
bun run agents/run-agent.ts agents/prompts/newsletter-digest.md
# Or via the wrapper:
agents/run-agent.sh newsletter-digest.md
```
Shipped prompts live in `agents/prompts/`. Bring your own by dropping additional `.md` files into a directory of your choice (the [Mac app](apps/mac/) defaults to `~/Developer/claude-cron/prompts/`). See `agents/prompts/README.md` for the format.
## Remote Access via Tailscale
To access OpenBrain from other devices on your network:
```bash
# Expose MCP server over Tailscale HTTPS
tailscale serve --bg --https=6443 http://localhost:6277
```
Then update your bookmarklet URL to use `https://your-machine.tail-xxxxx.ts.net:6443` and set `AUTH_TOKEN` in `.env` to protect the endpoint.
## Development
```bash
bun run dev # MCP server with auto-reload
bun run ui # Web UI
bun run health # Check all service health
bun run db:generate # Generate Drizzle migration from schema changes
bun run db:migrate # Apply pending migrations
# Re-enrich memories missing summaries
bun run scripts/enrich-backlog.ts
```
## Managing Services
```bash
# Install as launchd daemons (auto-start on boot)
bash scripts/install-services.sh
# Uninstall all services
bash scripts/uninstall-services.sh
# Restart a single service
kill $(lsof -ti :6277) # KeepAlive restarts it automatically
# View logs
tail -f logs/mcp.log
tail -f logs/embed.log
tail -f logs/llm.log
```
## License
MIT
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
markitdown
Python tool for converting files and office documents to Markdown.
Filesystem
Node.js MCP Server for filesystem operations with dynamic access control.
TrendRadar
TrendRadar: Your hotspot assistant for real news in just 30 seconds.
mempalace
The highest-scoring AI memory system ever benchmarked. And it's free.
mempalace
The highest-scoring AI memory system ever benchmarked. And it's free.