Skip to main content
Glama
theippenguin

Open Mind

by theippenguin
README.md
# Open Mind

Self-hosted personal knowledge infrastructure for AI agents. Inspired by [OB1 (Open Brain)](https://github.com/NateBJones-Projects/OB1), built to run on Unraid with Docker.

Store thoughts, ideas, and knowledge in PostgreSQL with pgvector for semantic search. Any MCP-compatible AI tool (OpenClaw, Claude, ChatGPT, Cursor) can read and write to your knowledge base.

## Features

- **Semantic search** via pgvector embeddings — find thoughts by meaning, not keywords
- **Configurable embeddings** — Ollama (local/free), OpenAI (OAuth or API key), or OpenRouter
- **4 core MCP tools** — capture, search, browse, and stats
- **6 extensions** — Household Knowledge, Home Maintenance, Family Calendar, Meal Planning, Professional CRM, Job Hunt Pipeline
- **Capture integrations** — Slack, Discord, and REST API
- **Multi-user support** with Row-Level Security
- **OpenAI OAuth PKCE** — authenticate without raw API keys

## Architecture

```
OpenClaw ◄──MCP──► Express:3100 ◄──► PostgreSQL+pgvector
                        │
                   Ollama / OpenAI / OpenRouter
```

## Quick Start (Standard Docker Compose)

```bash
# 1. Clone and configure
git clone https://github.com/theippenguin/open-mind.git
cd open-mind
cp .env.example .env

# 2. Generate an API key
openssl rand -hex 32
# Paste the output into .env as the API_KEY value

# 3. Edit .env with your settings
nano .env

# 4. Start services
docker compose up -d

# 5. Update the default user's API key in the database
docker exec openmind-postgres psql -U openmind -d openmind -c \
  "UPDATE users SET api_key = 'YOUR_API_KEY_HERE' WHERE name = 'default';"

# 6. Test
curl -X POST http://localhost:3100/api/capture \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY_HERE" \
  -d '{"content": "Hello Open Mind!", "source": "api"}'
```

## Unraid Installation Guide

Unraid uses the **Docker Compose Manager** plugin, which stores compose files in its own directory and doesn't allow pointing to external compose files. Follow these Unraid-specific steps:

### Prerequisites

- Unraid with the **Docker Compose Manager** plugin installed (available in Community Apps)
- An Ollama server accessible from your Unraid box (can be the same machine or a separate server)
- Ollama models pulled: `nomic-embed-text` (embeddings) and a chat model like `llama3.2`, `qwen3`, or `mistral` (metadata extraction)

### Step 1: Generate your API key

From any terminal:

```bash
openssl rand -hex 32
```

Save this key — you'll need it in multiple steps.

### Step 2: Clone the repo on Unraid

SSH into your Unraid server:

```bash
cd /mnt/user/appdata
git clone https://github.com/theippenguin/open-mind.git
cd open-mind
```

If git isn't available on your Unraid box:

```bash
cd /mnt/user/appdata
wget https://github.com/theippenguin/open-mind/archive/refs/heads/main.zip
unzip main.zip
mv open-mind-main open-mind
cd open-mind
```

### Step 3: Create your `.env` file

```bash
cp .env.example .env
nano .env
```

Fill in these values:

```env
POSTGRES_PASSWORD=pick-a-strong-password-here
API_KEY=paste-your-generated-key-from-step-1

# Your Ollama server IP and port
OLLAMA_BASE_URL=http://YOUR_OLLAMA_IP:11434

# Embedding (must be an embedding model — chat models won't work)
EMBEDDING_PROVIDER=ollama
OLLAMA_EMBEDDING_MODEL=nomic-embed-text

# Metadata extraction (any chat/instruct model works)
METADATA_LLM_PROVIDER=ollama
METADATA_LLM_MODEL=llama3.2
```

### Step 4: Create the PostgreSQL data directory

```bash
mkdir -p /mnt/user/appdata/open-mind/postgres
```

### Step 5: Verify Ollama is reachable

From your Unraid terminal, confirm Ollama responds:

```bash
curl http://YOUR_OLLAMA_IP:11434/api/tags
```

You should see a JSON list of models. If you get "connection refused", make sure Ollama is configured with `OLLAMA_HOST=0.0.0.0` so it listens on all interfaces.

Ensure the required models are pulled on your Ollama server:

```bash
ollama pull nomic-embed-text
ollama pull llama3.2  # or qwen3, mistral, etc.
```

### Step 6: Set up the Docker Compose stack in Unraid

The Unraid Docker Compose Manager stores compose files at its own path, so you **cannot** point it to the repo's `docker-compose.yml`. Instead:

1. In the Unraid web UI, go to **Docker → Compose**
2. Click **Add New Stack**, name it **OpenMind**
3. **Set the .env file path** to: `/mnt/user/appdata/open-mind/.env`
4. **Paste the following** into the compose editor:

```yaml
services:
  postgres:
    image: pgvector/pgvector:pg16
    container_name: openmind-postgres
    environment:
      POSTGRES_DB: openmind
      POSTGRES_USER: openmind
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme}
    ports:
      - "5433:5432"
    volumes:
      - /mnt/user/appdata/open-mind/postgres:/var/lib/postgresql/data
      - /mnt/user/appdata/open-mind/drizzle/0000_initial_schema.sql:/docker-entrypoint-initdb.d/01-schema.sql
      - /mnt/user/appdata/open-mind/drizzle/0001_extensions.sql:/docker-entrypoint-initdb.d/02-extensions.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U openmind"]
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  mcp-server:
    build:
      context: /mnt/user/appdata/open-mind
      dockerfile: Dockerfile
    container_name: openmind-mcp
    ports:
      - "3100:3100"
    environment:
      PORT: 3100
      DATABASE_URL: postgresql://openmind:${POSTGRES_PASSWORD:-changeme}@postgres:5432/openmind
      API_KEY: ${API_KEY:-changeme-generate-with-openssl-rand-hex-32}
      EMBEDDING_PROVIDER: ${EMBEDDING_PROVIDER:-ollama}
      OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://192.168.1.100:11434}
      OLLAMA_EMBEDDING_MODEL: ${OLLAMA_EMBEDDING_MODEL:-nomic-embed-text}
      OPENAI_API_KEY: ${OPENAI_API_KEY:-}
      OPENAI_CLIENT_ID: ${OPENAI_CLIENT_ID:-}
      OPENAI_CLIENT_SECRET: ${OPENAI_CLIENT_SECRET:-}
      OPENAI_REDIRECT_URI: ${OPENAI_REDIRECT_URI:-http://localhost:3100/auth/openai/callback}
      OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
      METADATA_LLM_PROVIDER: ${METADATA_LLM_PROVIDER:-ollama}
      METADATA_LLM_MODEL: ${METADATA_LLM_MODEL:-llama3.2}
      ENABLED_EXTENSIONS: ${ENABLED_EXTENSIONS:-household-knowledge,home-maintenance,family-calendar,meal-planning,professional-crm,job-hunt-pipeline}
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped
```

> **Important:** All paths are absolute (`/mnt/user/appdata/open-mind/...`) because the compose file is stored at the plugin's own location, not inside the repo directory. Do **not** include `version: '3.8'` — it's deprecated and will generate a warning.

5. Click **Compose Up**

### Step 7: Update the default user's API key

The database seeds a default user with a placeholder API key. You must update it to match your real key:

```bash
docker exec openmind-postgres psql -U openmind -d openmind -c \
  "UPDATE users SET api_key = '$(grep API_KEY /mnt/user/appdata/open-mind/.env | cut -d= -f2)' WHERE name = 'default';"
```

Verify it took:

```bash
docker exec openmind-postgres psql -U openmind -d openmind -c \
  "SELECT name, LEFT(api_key, 8) || '...' AS key_preview FROM users;"
```

### Step 8: Verify everything works

```bash
# Health check
curl http://localhost:3100/health

# Capture a test thought
curl -X POST http://localhost:3100/api/capture \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"content": "This is my first thought in Open Mind!", "source": "api"}'

# Verify in the database
docker exec openmind-postgres psql -U openmind -d openmind -c \
  "SELECT id, LEFT(content, 50), embedding_model, source FROM thoughts;"
```

### Updating Open Mind on Unraid

When updates are available:

```bash
cd /mnt/user/appdata/open-mind
git pull
```

Then in the Unraid UI: **Compose Down** → **Update Stack** (or Compose Up). This rebuilds the MCP server image with the latest code. The PostgreSQL data persists across updates.

### Troubleshooting

| Problem | Fix |
|---------|-----|
| `extension "pgvector" is not available` | Verify the image is `pgvector/pgvector:pg16`: `docker inspect openmind-postgres \| grep Image` |
| `Invalid API key` | Run the Step 7 command to sync the DB user's key with your `.env` key |
| `Failed to capture thought` | Check `docker logs openmind-mcp --tail 30` for the real error |
| Ollama connection refused | Ensure Ollama has `OLLAMA_HOST=0.0.0.0` and test with `curl http://OLLAMA_IP:11434/api/tags` from Unraid |
| Compose Up reuses old image | Use **Update Stack** button, or manually: `docker rmi` the old image then Compose Up |
| `version` warning in compose | Safe to ignore, or remove the `version: '3.8'` line |
| PostgreSQL skips init on restart | Data dir has stale data. `rm -rf /mnt/user/appdata/open-mind/postgres/*` then Compose Up |

## Connecting to AI Tools

### OpenClaw

Add to your OpenClaw MCP config (`~/.openclaw/config.json` or equivalent):

```json
{
  "mcpServers": {
    "open-mind": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://YOUR_UNRAID_IP:3100/mcp"],
      "env": {
        "MCP_AUTH_TOKEN": "your-api-key"
      }
    }
  }
}
```

### Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "open-mind": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://YOUR_UNRAID_IP:3100/mcp"],
      "env": {
        "MCP_AUTH_TOKEN": "your-api-key"
      }
    }
  }
}
```

### Any MCP Client

The MCP endpoint is `http://YOUR_UNRAID_IP:3100/mcp`. Authenticate with `Authorization: Bearer YOUR_API_KEY` header or `?key=YOUR_API_KEY` query parameter.

## Ollama Model Requirements

Open Mind uses **two models** for different purposes:

| Purpose | Config Variable | Model Type | Example |
|---------|----------------|-----------|---------|
| Embeddings (vector search) | `OLLAMA_EMBEDDING_MODEL` | **Embedding model** (required) | `nomic-embed-text` (~274MB) |
| Metadata extraction (tags, categories) | `METADATA_LLM_MODEL` | **Chat/instruct model** (any) | `llama3.2`, `qwen3`, `mistral` |

You **cannot** use a chat model for embeddings — it must be a dedicated embedding model like `nomic-embed-text`.

## Configuration Reference

See `.env.example` for all options. Key settings:

| Variable | Description | Default |
|----------|-------------|---------|
| `EMBEDDING_PROVIDER` | `ollama`, `openai`, or `openrouter` | `ollama` |
| `OLLAMA_BASE_URL` | Your Ollama server URL | `http://192.168.1.100:11434` |
| `OLLAMA_EMBEDDING_MODEL` | Ollama embedding model name | `nomic-embed-text` |
| `API_KEY` | Bearer token for authentication | — |
| `METADATA_LLM_PROVIDER` | `ollama`, `openai`, or `openrouter` | `ollama` |
| `METADATA_LLM_MODEL` | Chat model for metadata extraction | `llama3.2` |
| `ENABLED_EXTENSIONS` | Comma-separated list of extensions | all 6 enabled |

## License

MIT