Local LLM Observatory — See what your AI is actually doing, token by token.
9.0K
If LLMxRay helps you understand your AI better, consider giving it a star on GitHub.
Local LLM Observatory — See what your AI is actually doing, token by token, layer by layer.
No cloud. No API keys. No cost. Everything runs on your hardware.

docker run -p 5174:5174 -p 11435:11435 djovaneli/llmxray
Open http://localhost:5174 in your browser. Make sure Ollama is running on your machine.
The second port is the Live page's observe port: point any other tool (VS Code Copilot, Open WebUI, Continue, n8n, your own scripts) at http://localhost:11435 instead of Ollama and its traffic shows up on the Live page. Leave the mapping out if you do not need it. A published port is reachable from other machines on your network, so the Live page can run full-screen on a second screen while the agents work; bind it to 127.0.0.1:5174:5174 if you do not want that.
An agent that sends its calls through 11435 can also ask LLMxRay what went wrong with them: the image ships llmxray-mcp, a read-only MCP server (docker exec -i <container> node bin/mcp.mjs, or npx -y -p llmxray llmxray-mcp on the host with LLMXRAY_URL pointing at this container). See "For agents" in the main README.

| Variable | Default | Description |
|---|---|---|
OLLAMA_URL | http://host.docker.internal:11434 | Ollama instance URL |
PORT | 5174 | Port to serve on |
OBSERVE_PORT | 11435 | Port other tools point at to appear on the Live page |
OBSERVE | 1 | Set to 0 to not open the observe port |
LLMXRAY_DATA_DIR | /data | Where the Live page's turn records (and kept prompts) are written, 30 days |
OTEL_EXPORTER_OTLP_ENDPOINT | Send each turn to your trace viewer (Jaeger, Phoenix, Langfuse, Grafana) as OpenTelemetry spans, OTLP over HTTP | |
OTEL_EXPORTER_OTLP_HEADERS | Headers for that collector, name=value,name=value |
docker run -p 5174:5174 -p 11435:11435 -e OTEL_EXPORTER_OTLP_ENDPOINT=http://host.docker.internal:4318 djovaneli/llmxray
Each model call becomes a span and each run a trace. The prompt text is never sent unless you switch it on in the Live page. docker stop lets the open run's spans out before the container ends.
Each turn's record is written under /data, and LLMxRay puts the last 500 back when it starts. A container keeps nothing between runs unless that folder is a volume:
docker run -p 5174:5174 -p 11435:11435 -v llmxray-data:/data djovaneli/llmxray
docker run -p 5174:5174 -e OLLAMA_URL=http://192.168.1.50:11434 djovaneli/llmxray
docker run -p 3000:3000 -e PORT=3000 djovaneli/llmxray
services:
llmxray:
image: djovaneli/llmxray
ports:
- "5174:5174"
- "11435:11435"
environment:
- OLLAMA_URL=http://host.docker.internal:11434
volumes:
- llmxray-data:/data
volumes:
llmxray-data:
services:
ollama:
image: ollama/ollama
ports:
- "11434:11434"
volumes:
- ollama-data:/root/.ollama
llmxray:
image: djovaneli/llmxray
ports:
- "5174:5174"
- "11435:11435"
environment:
- OLLAMA_URL=http://ollama:11434
depends_on:
- ollama
volumes:
ollama-data:
On Linux, host.docker.internal may not resolve by default. Either:
--add-host=host.docker.internal:host-gateway to your docker run commandkeep_alive: 0 that unloads the model after every run, a 128K context on 4K prompts)
Apache 2.0 — Copyright 2026 Ivan Stankovic (LogneBudo)
Content type
Image
Digest
sha256:382a2193c…
Size
70 MB
Last updated
11 days ago
docker pull djovaneli/llmxray