diff --git a/OLLAMA-STACK.md b/OLLAMA-STACK.md new file mode 100644 index 0000000..4774a04 --- /dev/null +++ b/OLLAMA-STACK.md @@ -0,0 +1,109 @@ +# NoteDiscovery + Ollama + Open WebUI + +A one-command local AI stack. Runs three services, downloads a small model, no cloud, no API keys. + +| Service | URL | What it is | +|---|---|---| +| NoteDiscovery | http://localhost:8000 | Markdown notes app | +| Open WebUI | http://localhost:3000 | ChatGPT-style browser UI | +| Ollama | http://localhost:11434 | Local LLM runtime (OpenAI-compatible at `/v1`) | + +Default model: `qwen2.5:1.5b` (~1 GB). Change it in `docker-compose.ollama-stack.yml` under `ollama-init`. + +## Prerequisites + +- Docker Desktop (Windows/macOS) or Docker Engine + Compose v2 (Linux) +- ~5 GB free disk, ~2 GB free RAM + +## Start + +From the repo root: + +```bash +docker compose -f docker-compose.ollama-stack.yml up -d +docker compose -f docker-compose.ollama-stack.yml logs -f ollama-init # wait for "Model ready." +``` + +First run pulls images + the model (5–10 min). After that it's seconds. + +Then open: +- http://localhost:8000 — start taking notes (saved to `./data/`) +- http://localhost:3000 — pick `qwen2.5:1.5b` and chat + +Quick sanity-check that Ollama is up: + +```bash +curl http://localhost:11434/api/tags # bash/zsh +Invoke-RestMethod http://localhost:11434/api/tags # PowerShell +``` + +## Connect Cursor + +Two independent integrations. Enable either or both. + +### Notes via MCP + +Add to `~/.cursor/mcp.json`: + +```json +{ + "mcpServers": { + "notediscovery": { + "command": "docker", + "args": [ + "run", "--rm", "-i", + "-e", "NOTEDISCOVERY_URL=http://host.docker.internal:8000", + "ghcr.io/gamosoft/notediscovery:latest", + "python", "-m", "mcp_server" + ] + } + } +} +``` + +Restart Cursor. Ask things like *"list my recent notes"* or *"create a note called scratch with today's date"*. + +> Linux: `host.docker.internal` doesn't resolve by default. Add `"--add-host=host.docker.internal:host-gateway"` to the args array. + +### Local model as Cursor's chat model + +Cursor Settings → Models → add a custom OpenAI-compatible model: +- **Base URL:** `http://localhost:11434/v1` +- **API Key:** anything (e.g. `ollama`) +- **Model:** `qwen2.5:1.5b` + +Only affects the chat model picker — Cursor Tab and background jobs still use Cursor's cloud models. If Cursor rejects the local URL (older versions validate from the cloud), expose it via `cloudflared tunnel --url http://localhost:11434` and use the tunnel URL instead. + +## Useful commands + +All commands below assume `COMPOSE_FILE=docker-compose.ollama-stack.yml` is set; otherwise prepend `-f docker-compose.ollama-stack.yml`. + +```bash +docker compose logs -f # tail logs +docker compose exec ollama ollama list # list installed models +docker compose exec ollama ollama pull qwen2.5-coder:3b # add a model +docker compose down # stop (keeps everything) +docker compose down -v # stop + wipe models & chat history (notes survive) +docker compose pull && docker compose up -d # update +``` + +Any model tag from https://ollama.com/library works. Rough RAM rule: 1B ≈ 1 GB, 3B ≈ 2 GB, 7B ≈ 5 GB. + +## Data + +- `./data/` — your notes (plain markdown, back this up) +- `ollama-models` volume — models (re-downloadable) +- `open-webui-data` volume — chat history (safe to wipe) + +## Troubleshooting + +- **Open WebUI shows "no models"** — model pull hasn't finished. Watch `docker compose logs -f ollama-init`. +- **Cursor MCP disconnected** — check `curl http://localhost:8000/health`, then restart Cursor. +- **Slow generation** — use a smaller model (`qwen2.5:0.5b`) or give Docker more CPU/RAM. +- **Port already in use** — edit the `ports:` mapping in `docker-compose.ollama-stack.yml`, then update your MCP config / URLs. + +## Links + +- NoteDiscovery: https://github.com/gamosoft/NoteDiscovery +- MCP tools reference: [`documentation/MCP.md`](documentation/MCP.md) +- Ollama library: https://ollama.com/library diff --git a/README.md b/README.md index 1d1a3b8..e9b54f4 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,8 @@ NoteDiscovery includes a built-in **Model Context Protocol (MCP)** server, letti ``` > 💡 **See [MCP.md](documentation/MCP.md)** for complete setup instructions and all available tools. +> +> 🧪 **Want a fully local setup with a bundled LLM?** [OLLAMA-STACK.md](OLLAMA-STACK.md) spins up NoteDiscovery + Ollama + Open WebUI with one command. ## 📺 Watch the tour @@ -154,6 +156,7 @@ Two docker-compose files are provided: |------|----------| | `docker-compose.ghcr.yml` | **Recommended** - Uses pre-built image from GitHub Container Registry | | `docker-compose.yml` | For development - Builds from local source | +| `docker-compose.ollama-stack.yml` | Bundled local AI stack (NoteDiscovery + Ollama + Open WebUI) — see [OLLAMA-STACK.md](OLLAMA-STACK.md) | **Option 1: Pre-built image (fastest)** diff --git a/docker-compose.ollama-stack.yml b/docker-compose.ollama-stack.yml new file mode 100644 index 0000000..0fc1d4e --- /dev/null +++ b/docker-compose.ollama-stack.yml @@ -0,0 +1,90 @@ +services: + notediscovery: + image: ghcr.io/gamosoft/notediscovery:latest + container_name: notediscovery + restart: unless-stopped + ports: + - "8000:8000" + environment: + - TZ=UTC + volumes: + - ./data:/app/data + # Uncomment to customize (files/folders must exist first): + # - ./config.yaml:/app/config.yaml + # - ./plugins:/app/plugins + # - ./themes:/app/themes + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + + ollama: + image: ollama/ollama:latest + container_name: ollama + restart: unless-stopped + ports: + - "11434:11434" + environment: + - OLLAMA_HOST=0.0.0.0:11434 + - OLLAMA_KEEP_ALIVE=30m + volumes: + - ollama-models:/root/.ollama + healthcheck: + test: ["CMD", "ollama", "--version"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 15s + + # ChatGPT-style browser UI for Ollama. + # Available at http://localhost:3000 after startup. + open-webui: + image: ghcr.io/open-webui/open-webui:main + container_name: open-webui + restart: unless-stopped + ports: + - "3000:8080" + environment: + - OLLAMA_BASE_URL=http://ollama:11434 + # Skip account creation on first launch (single-user local mode). + # Set to "true" for the login flow if you're exposing this beyond localhost. + - WEBUI_AUTH=false + # We only use Ollama, so disable the external OpenAI integration. + - ENABLE_OPENAI_API=false + volumes: + - open-webui-data:/app/backend/data + depends_on: + ollama: + condition: service_healthy + + # One-shot service: pulls the model on first startup, then exits. + # No-op on subsequent runs if the model is already present. + # To change the model, edit MODEL below (any tag from https://ollama.com/library): + # qwen2.5:0.5b ~400 MB fastest, minimal capability + # qwen2.5:1.5b ~1.0 GB balanced (default) + # qwen2.5-coder:1.5b ~1.0 GB code-focused + # qwen2.5-coder:3b ~2.0 GB better code, still small + # llama3.2:3b ~2.0 GB general-purpose + ollama-init: + image: ollama/ollama:latest + container_name: ollama-init + depends_on: + ollama: + condition: service_healthy + environment: + - OLLAMA_HOST=ollama:11434 + - MODEL=qwen2.5:1.5b + entrypoint: + - /bin/sh + - -c + - | + echo "Pulling model: $$MODEL" + ollama pull "$$MODEL" + echo "Model ready." + restart: "no" + +volumes: + ollama-models: + open-webui-data: diff --git a/documentation/MCP.md b/documentation/MCP.md index 654c205..885cbc7 100644 --- a/documentation/MCP.md +++ b/documentation/MCP.md @@ -459,3 +459,7 @@ NoteDiscovery/ │ └── tools.py # Tool definitions └── ... ``` + +## Try it with a local LLM + +For a batteries-included setup that runs NoteDiscovery alongside [Ollama](https://ollama.com) (local LLM runtime) and [Open WebUI](https://openwebui.com) (browser chat UI), see **[OLLAMA-STACK.md](../OLLAMA-STACK.md)** in the repo root. One `docker compose` command spins everything up, and you can point Cursor at both your notes (via this MCP server) and your local model.