Compare LLM responses side-by-side with local persistence
Project description
Tukey
Compare LLM responses side-by-side with local persistence.
pipx install tukey-llm
tukey
Open http://localhost:8000. A guided setup walks you through connecting your first provider — or bring your own API keys.
What it does
Send a prompt once, get parallel streaming responses from every model you selected. Configure each model independently — system prompt, temperature, max tokens, reasoning effort — or broadcast settings across all of them.
- Side-by-side comparison — parallel fan-out to any mix of OpenAI, Anthropic, Google, DeepSeek, or OpenAI-compatible providers
- Multiple completions — generate 1–9 completions per model per prompt to observe variance, not just a single sample
- Per-response metadata — tokens, cost, duration, tok/s for every response
- Local-first — all data stored in
~/.tukey/, nothing leaves your machine except API calls - Experiments — named test suites with batch execution, human annotation, and reproducible manifests (API/CLI — UI coming soon)
- Text annotation — select text in any response to rate and comment on specific sections; highlights persist across page reloads
- Search — full-text search across all chatrooms, chats, and messages
- Import/export — per-chatroom JSON export for backup or transfer
Install
Requires Python 3.11+.
# With pipx
pipx install tukey-llm
# Or with uv
uv tool install tukey-llm
Verify it works:
tukey
# Tukey is running at http://localhost:8000
Options
tukey --port 9000 # different port (default: 8000)
tukey --host 127.0.0.1 # bind to localhost only
tukey --data-dir ./my-data # custom data directory (default: ~/.tukey)
Configuration
On first launch, a guided setup helps you connect your first provider. The fastest path is OpenRouter — one API key gives you access to Claude, GPT, Gemini, and more (including free models).
Alternatively, click "I already have API keys" to add any provider directly:
| Provider | What to enter |
|---|---|
| OpenRouter | API key from openrouter.ai/keys (recommended — access to 100+ models) |
| OpenAI | API key from platform.openai.com |
| Anthropic | API key from console.anthropic.com |
| Google AI | API key from aistudio.google.dev |
| OpenAI-compatible | Base URL + API key (local servers, custom gateways, etc.) |
Keys are stored in ~/.tukey/config.json. They are never sent anywhere except to the provider's API. You can switch data directories at runtime via the folder path in the sidebar.
Usage
- Create a chatroom
- Add models from the sidebar — pick any combination across providers
- Configure each model's system prompt, temperature, and other settings (or use "Apply to all")
- Type a prompt and send — responses stream in side-by-side
- Toggle the metadata bar to see cost, speed, and token counts per response
Annotations
Select any text in a completed response to annotate it:
- Highlight a text range in a response card
- Rate it thumbs up or thumbs down, add an optional comment
- Annotations appear as colored highlights (green = positive, red = negative)
- Click a highlight to review, edit, or delete the annotation
Annotations are stored per-response and survive page refresh.
Experiments
For systematic evaluation beyond ad-hoc chat:
- Define a named experiment with test cases and evaluation criteria
- Run the test suite — Tukey executes all cases across all models with concurrency
- Have domain experts annotate results with pass/fail judgments and notes
- Export the full manifest for reproducibility
REST API
Drive Tukey programmatically via its REST API. Use any HTTP client:
import httpx
BASE = "http://localhost:8000"
with httpx.Client(timeout=120) as client:
# List chatrooms
chatrooms = client.get(f"{BASE}/api/chat/chatrooms").json()
chatroom_id = chatrooms[0]["id"]
# Create a chat session
chat = client.post(f"{BASE}/api/chat/chatrooms/{chatroom_id}/chats").json()
# Send a message — fans out to all configured models concurrently
turn = client.post(
f"{BASE}/api/chat/chatrooms/{chatroom_id}/chats/{chat['id']}/messages",
json={"content": "Your prompt here"},
).json()
for response in turn["responses"]:
print(response["model_id"], response["content"])
See GET /api/health for a quick sanity check. Full endpoint reference: start the server and visit http://localhost:8000/docs.
Contributing
git clone https://github.com/zhao-weijie/tukey.git
cd tukey
uv sync --extra dev
cd ui && npm ci && npm run build && cd ..
uv run tukey
Tests: uv run pytest
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tukey_llm-0.4.0.tar.gz.
File metadata
- Download URL: tukey_llm-0.4.0.tar.gz
- Upload date:
- Size: 413.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71b7e984d80f88ede6a179588d8e7e0be7708bdc86b3e1d35070245091eb6d76
|
|
| MD5 |
8f7cedde7cc62264fbb10d11aaf9b0b4
|
|
| BLAKE2b-256 |
084a266b2cae4100a62c9ca53b284a8aea97c5a144a7de37f2f5b1a81311739f
|
Provenance
The following attestation bundles were made for tukey_llm-0.4.0.tar.gz:
Publisher:
release.yml on zhao-weijie/tukey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tukey_llm-0.4.0.tar.gz -
Subject digest:
71b7e984d80f88ede6a179588d8e7e0be7708bdc86b3e1d35070245091eb6d76 - Sigstore transparency entry: 1167706573
- Sigstore integration time:
-
Permalink:
zhao-weijie/tukey@3ef5a248a2199a2af7a3c026cbc1242cbeeb960e -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/zhao-weijie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3ef5a248a2199a2af7a3c026cbc1242cbeeb960e -
Trigger Event:
push
-
Statement type:
File details
Details for the file tukey_llm-0.4.0-py3-none-any.whl.
File metadata
- Download URL: tukey_llm-0.4.0-py3-none-any.whl
- Upload date:
- Size: 415.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1ffc286db94b084120ea44b9e4cab59d7e95326cccb194438e4048f20fff63c
|
|
| MD5 |
b7a0d4ea055e95cc27e9021a5af2a11a
|
|
| BLAKE2b-256 |
b5503202358cdd197100be60c089a66dfd6005326892fdaa6aa3717404ad7dc9
|
Provenance
The following attestation bundles were made for tukey_llm-0.4.0-py3-none-any.whl:
Publisher:
release.yml on zhao-weijie/tukey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tukey_llm-0.4.0-py3-none-any.whl -
Subject digest:
f1ffc286db94b084120ea44b9e4cab59d7e95326cccb194438e4048f20fff63c - Sigstore transparency entry: 1167706646
- Sigstore integration time:
-
Permalink:
zhao-weijie/tukey@3ef5a248a2199a2af7a3c026cbc1242cbeeb960e -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/zhao-weijie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3ef5a248a2199a2af7a3c026cbc1242cbeeb960e -
Trigger Event:
push
-
Statement type: