calivi
Tools Transparency Features Get started GitHub
Self-hosted · MIT · Docker

You pick which model
runs where.

Calivi is a self-hosted chat interface for your own Ollama and OpenAI-compatible servers. Every message goes to the exact server and model you choose — no hidden router deciding for you.

One docker compose up · SQLite, no external services · nine languages

The interface

A chat window that shows the machinery.

Two dropdowns pick the server and model. Streaming answers with reasoning, tool calls, and per-message attribution — visible, not hidden.

calivi
local-gpu llama3.3:70b
10:24:07
Write a bash script that zips the current folder, named with a timestamp.
10:24:11llama3.3:70b · local-gpu

Here's a script that archives everything in the current directory and excludes its own output:

bashCopy
#!/usr/bin/env bash
set -euo pipefail

# timestamped archive of the current folder
stamp=$(date +"%Y-%m-%d_%H-%M-%S")
zip -r "backup_${stamp}.zip" . -x "backup_*.zip"

Run it inside the folder you want to archive; the new .zip lands right there.

~135 t/s
10:25:02
🔍 what changed in httpx 0.28
What changed in httpx v0.28?
🔧 web_search · 5 results
Type a message…

// mockup with placeholder data — not a real conversation

Tools & MCP

Give the model instruments — and keep the keys.

One toggle offers the tool layer; the model decides what to call. Bundled web search comes built in, and any remote MCP server plugs in beside it. Read-only tools run freely, state-changing ones ask you first.

Theme
Light / dark appearance. Defaults to your system preference.
LightDark
Accent color
Color of buttons, links and selected items.
Interface language
Nine languages, switched live.
English
Registration open
When off, new user sign-up is blocked (existing users unaffected).
local-gpu — 192.168.1.50:11434 · local ollama
workstation — 192.168.1.51:11434 · local ollama
openrouter — https://openrouter.ai/api/v1 · openai api
lab-box — 192.168.1.52:11434 · local ollama

A green light means the server answered and its model list arrived. Red servers are hidden from the chat picker.

New server
OpenAI-compatible
Name (e.g. local-gpu)
Base URL (https://api.openai.com/v1)
API Key (optional)
+ Add Server

Read-only tools from remote MCP servers. Streamable HTTP and the older HTTP+SSE transport.

context7 — https://mcp.context7.com/mcp2 tools
github — https://api.githubcopilot.com/mcp/readonly14 tools
Automatic 🔧 mcp__context7__query-docs
Ask first ⚠️ mcp__github__create_issue
New MCP server
Preset: context7githubexa
HTTP
Name (e.g. context7)
https://mcp.example.com/mcp
Authorization
Bearer
Token (optional)
Extra headers as JSON, e.g. {"X-MCP-Readonly": "true"}
Enabled
+ Add MCP Server

Per-model system (initial) prompts. Key = exact model name, 'default' = fallback.

# hot-reloaded — edit and the next message uses it
default: |
  You are a careful, concise assistant. Answer the
  question that was asked. Say when you are unsure.

"qwen3:32b": |
  A reasoning model. Take multi-step problems slowly
  and show the steps that matter.

Tool layer settings. enabled: master switch. max_iterations: agentic loop cap. MCP tools are switched on and off individually in the MCP tab.

# read on every request — no restart
enabled: true
max_iterations: 8
tools:
  web_search:
    enabled: true
    num_results: 5
#0001 alice (you)super admin
#0002 bobuser
bob@example.com
bob
Save
Make admin Block Delete
#0003 caroluser

Everyone sees only their own chats. The first account is the super admin and cannot be demoted or deleted.

Calivi

A self-hosted, multi-user chat app that connects to Ollama and OpenAI-compatible servers from one interface. Server and model selection is manual. Images and documents, a tool layer with web search and MCP servers, and approval before anything changes state.

FastAPI + React · self-hosted · github.com/orkun-soylu/calivi

// mockup with placeholder data — advances every 3s, click a tab to stop

Transparency

Tools don't make a model honest.
They make it checkable.

A documentation or search tool returns the passages that matched one query — never a complete reference. A model can read a partial excerpt and confidently report that the part it did not receive does not exist. Calivi does not claim to fix that. It shows you what the model actually got.

What we measured

A confident wrong answer

Asked about Pydantic v2 validator modes, a model sent one broad query to Context7, got back an excerpt in which the word wrap never appears, and reported that the mode does not exist — while closing with “this is from the current documentation”. A re-worded query returns the exact sentence it needed. The documentation was fine; one retrieval was treated as exhaustive.

The fix that failed

Measured, then dropped

We wrote a system-layer instruction telling the model to re-query when something looked uncovered, and measured it over five runs per arm. It was worse: the false claim went from 0/5 to 2/5, and one run exhausted the iteration cap without producing an answer. Telling a model to “say plainly when something is not covered” appears to invite the confident claim of absence that was the bug. It was not shipped.

What shipped instead

The receipts, kept

The failure is intermittent — 0/5 without the guard — so it is variance, not a defect a prompt can remove. The model cannot be made reliable here, but the operator can be given what it saw: every tool call is clickable and opens the raw output, stored with the message so it survives a reload.

🔧 context7: query-docs raw output ▾
Exactly what the tool returned. Check the answer against it — anything missing here may have been filled in from memory.
### model_validator with mode='after' for cross-field validation

Source: https://github.com/pydantic/pydantic/blob/main/pydantic/functional_validators.py

@model_validator(mode='after')
def verify_square(self) -> Self:
    if self.width != self.height:
        raise ValueError('width and height do not match')
    return self
// four more excerpts — none of them mentioning wrap

// the panel is real; the excerpt is trimmed for the page

What you get

Control first, everything else built in.

Routing

Manual, always

Choose the server and model from the top bar for every message. Only reachable servers appear — no auto-router second-guessing you.

Backends

One UI, any server

Native Ollama and any OpenAI-compatible API — OpenRouter, LM Studio, vLLM, llama.cpp — side by side through one interface.

Streaming

With reasoning

Answers stream as they generate; reasoning models show their thinking in a separate pane. Stop any response with Esc.

Context

Vision & documents

Paste images to vision models. Attach PDFs, docx or code — extracted as lossless text, not OCR — on any model.

Tools

Web search and MCP

A bundled SearXNG, plus any remote MCP server — Context7, GitHub, Exa. The model calls them on its own initiative, and you see which tool ran, right in the conversation.

Access

Multi-user

Cookie sessions, admin and user roles, each person scoped to their own chats. Registration you can close anytime.

Get started

Running in one command.

bash
# clone and bring it up
$ git clone https://github.com/orkun-soylu/calivi.git
$ cd calivi
$ docker compose up -d --build

 calivi running on http://localhost:8090
1

Bring up the stack

Backend, frontend and a bundled SearXNG. Needs only Docker & Compose — data lives in SQLite.

2

Create the first account

The first sign-up becomes the admin. Add your servers under Settings — Ollama by host, OpenAI-compatible by base URL.

3

Put a model to work

Pick a server and model from the top bar and start chatting. Behind HTTPS? Set COOKIE_SECURE=true.