Skip to main content

Local AI setup

The “Ask AI” panel on each page sends the page’s context to a model and streams the answer back. This guide runs everything on your machine, with the model served locally by Ollama.
You need four things running: Redis, Ollama, the AI worker and the web app.

1. Ollama

  1. Install Ollama from https://ollama.com
  2. Start the server with a larger context window (keep this terminal open):
    Ollama defaults to 4096 tokens and silently drops anything past that, so a large page would be cut off with no error. 8192 fits comfortably in 16 GB alongside the 7B model. If you run the Ollama menu-bar app instead of ollama serve, set it for the app and restart it:
  3. In a second terminal, pull the models:

Check it works

2. Redis

The rate limiter keeps its counters in Redis. From the repo root:

3. The AI worker

The worker is the Python FastAPI service that builds the prompt and talks to the model (POST /chat, GET /health). Run it from services/ai-worker (also summarized in that folder’s README). First time only:
Edit .env:
INTERNAL_SECRET must match AI_WORKER_SECRET in apps/web/.env.local (see step 4). Every time you work on it (activate the virtualenv first in each new terminal):
Port 8001 is what the web app expects by default (AI_WORKER_URL). Start it from services/ai-worker so it finds .env. Check it is up:
Run its tests with python -m pytest.

4. The web app

apps/web/.env.local must already have DATABASE_URL, REDIS_URL and AUTH_SECRET (see the root README). Add:
Optional: AI_RATE_LIMIT_PER_MINUTE=20 (see below). Restart the dev server after editing .env.local, since Next only reads it at startup. Then sign in (seeded demo: workspace acme, password acme-demo-password), open any page and click the sparkle icon beside the copy button. The badge beside “Ask AI” says whether a local or hosted model answered.

Costs and limits

Local models are free, but a hosted model is billed per token and the chat is reachable by every signed-in user. These guards keep one user, or one large page, from running up cost or exhausting the model’s context window. Notes:
  • The rate limiter fails open. If Redis is unreachable, requests are allowed through and a warning is logged, so a Redis outage doesn’t take chat down. That is why the provider spend limit below matters.
  • The context budget is shared. The model’s window holds the system prompt, page data, history, question and the answer together. The route budgets them as one: a prompt may total about 21,500 characters (the 8,192-token window minus 1,024 for the answer, at a conservative 3 characters per token), and history gets whatever the page and question leave. The limits in limits.ts are derived from OLLAMA_CONTEXT_LENGTH and max_tokens, so change them together.
  • Limits apply to local and hosted alike, so behaviour doesn’t change when you switch providers.

Hosted models: set a spend cap

Before putting a hosted key in .env, set a hard ceiling in the provider’s own dashboard (for Fireworks, a monthly spend limit or a small prepaid balance). Application limits can be bypassed by a bug or an outage; the provider’s limit cannot. Use a key made only for this project so it can be revoked on its own. To use a hosted model, switch the worker’s .env to the hosted profile in .env.example and restart it. No web app change is needed.

Notes

  • The first request is slow while the model loads into memory.
  • On 16 GB machines, close memory-heavy apps or use the 3b model.
  • Never commit .env files. .env.example is the template.