What does it look like? | What can it do? | How does it work? | Quick start
Open-source proxy that sits between Claude Code and the Anthropic API. Logs every request. Enforces your rules.
Say your CLAUDE.md has this rule:
Python packages: use uv add, never pip install.
| Without Luthien | With Luthien |
|---|---|
|
Claude ignores your CLAUDE.md rule and you correct it manually. |
Luthien catches the violation and auto-corrects. No human intervention needed. |
🚨 Luthien is in active development. Star this repo to follow updates, or Watch > Releases to get notified on new versions.
Found a bug or have a question? Open an issue.
- Block dangerous operations —
rm -rf,git push --force, dropping database tables - Enforce package standards — block
pip install, suggestuv addinstead - Clean up AI writing tics — remove em dashes, curly quotes, over-bulleting
- Enforce scope boundaries — only allow changes to files mentioned in the request
Example: ToolCallJudgePolicy — an LLM judge that evaluates every tool call:
# config/policy_config.yaml
policy:
class: "luthien_proxy.policies.tool_call_judge_policy:ToolCallJudgePolicy"
config:
model: "anthropic/claude-haiku-4-5-20251001" # swap for a larger model if needed
probability_threshold: 0.6 # block when judge LLM's subjective risk score >= 0.6 (higher = more permissive)
judge_instructions: >
Block any 'pip install' commands. Suggest 'uv add' instead.
Block 'rm -rf' or any recursive delete on project directories.
Block 'git push --force' to main or master.The
class:field is a Python import path (module:ClassName). You can use any of the built-in policies or write your own.
Every request and response between Claude Code and the Anthropic API is recorded automatically.
- Live conversation view - open localhost:8000/history to see your full agent conversation in a readable format, updated in real time
- Activity monitor - open localhost:8000/activity/monitor to see raw JSON request/response pairs streaming through the proxy
- Policy action log - every policy decision (blocked, modified, or allowed) is recorded with the full context of what triggered it
This means you can answer questions like: what did Claude actually send to the API? Did the policy fire? What got blocked vs. allowed? Track false positives and monitor latency overhead - all from a browser tab, no extra tooling needed.
You <-> Claude Code <-> Luthien <-> Anthropic API
|
logs every request and response
enforces the rules you define
|
|-- did it do what I asked?
|-- did it follow CLAUDE.md?
+-- did it do something suspicious?
Luthien sits in line as a transparent proxy. Every request and response flows through it, adding roughly 5-15ms of overhead. You define rules in YAML or Python, and Luthien enforces them on every request. It can call a separate "judge" model (like Claude Haiku) to evaluate responses in parallel, so enforcement does not block your workflow.
curl -fsSL https://raw.githubusercontent.com/LuthienResearch/luthien-proxy/main/scripts/install.sh | bashNo Docker required. This installs uv (if needed) and the Luthien CLI, sets up the gateway with SQLite, walks you through configuration, and starts the proxy.
Claude Pro/Max users: You don't need an API key. Luthien passes your existing Claude subscription credentials through to the Anthropic API — no extra cost, no configuration needed.
Platform support: Linux and macOS. Windows is not currently supported.
After setup, use the CLI or Claude Code to manage the proxy:
| CLI command | Claude Code | What it does |
|---|---|---|
luthien claude |
— | Launch Claude Code through the proxy |
luthien status |
!luthien status |
Check gateway health |
luthien up |
!luthien up |
Start the gateway |
luthien down |
!luthien down |
Stop the gateway |
luthien logs |
!luthien logs |
View gateway logs |
Docker mode: If you prefer PostgreSQL + Redis, run
luthien onboard --dockerinstead. Requires Docker.
Next step: Once the gateway is running, see Configuration to set up API keys and customize policies.
- Gateway (Anthropic-compatible) at http://localhost:8000
- SQLite storage (zero setup) — or PostgreSQL + Redis with
--docker - Real-time monitoring at http://localhost:8000/activity/monitor
- Policy management UI at http://localhost:8000/policy-config
Trouble accessing the dashboard? The monitoring and policy UIs require the admin API key. On localhost, auth is bypassed by default — but if you're accessing from another host or see a login page, see Configuration below.
Copy .env.example to .env and configure your environment:
Luthien supports two ways to authenticate with the Anthropic API:
| Mode | Who pays | Setup |
|---|---|---|
| OAuth passthrough (default) | Your existing Claude Pro/Max subscription | Nothing — just run luthien claude |
| API key | Per-token billing to your Anthropic API account | Set ANTHROPIC_API_KEY in .env |
⚠️ API key mode bills per token. If you setANTHROPIC_API_KEYin your.env, all requests through the proxy are billed to that API key at Anthropic's per-token rates. This can result in significant charges. If you have a Claude Pro or Max subscription, you don't need an API key — OAuth passthrough is the default and uses your existing subscription at no extra cost.
# Gateway Authentication
PROXY_API_KEY=sk-luthien-dev-key # API key for clients to access the proxy
ADMIN_API_KEY=admin-dev-key # API key for admin/policy management UI (History, Policy tabs)Two gateway keys, two purposes:
PROXY_API_KEYis for Claude Code and other LLM clients connecting through the gateway.ADMIN_API_KEYis for the web dashboard (History, Policy Configuration, Activity Monitor). On localhost, the dashboard bypasses auth automatically.
# Only needed if NOT using Claude Pro/Max OAuth passthrough
ANTHROPIC_API_KEY=your_anthropic_api_key_here # optional — per-token billing, see warning above# Database — leave unset for SQLite (default: ~/.luthien/local.db)
# For Docker Compose / multi-user deployments, use PostgreSQL + Redis:
# DATABASE_URL=postgresql://luthien:password@db:5432/luthien_control
# REDIS_URL=redis://redis:6379
# Gateway
GATEWAY_HOST=localhost
GATEWAY_PORT=8000# Policy loading strategy
# Options: "db", "file", "db-fallback-file" (recommended), "file-fallback-db"
POLICY_SOURCE=db-fallback-file
# Path to YAML policy file (when POLICY_SOURCE includes "file")
POLICY_CONFIG=./config/policy_config.yaml# Configuration for judge-based policies (ToolCallJudgePolicy)
LLM_JUDGE_MODEL=anthropic/claude-haiku-4-5-20251001 # Model for judge
LLM_JUDGE_API_KEY=your_judge_api_key # optional — only if judge needs a different key than the client'sSee .env.example for all available options and defaults.
The gateway loads policies from POLICY_CONFIG (defaults to config/policy_config.yaml).
Example policy configuration:
policy:
class: "luthien_proxy.policies.tool_call_judge_policy:ToolCallJudgePolicy"
config:
model: "anthropic/claude-haiku-4-5-20251001" # swap for a larger model if needed
probability_threshold: 0.6 # block when judge LLM's subjective risk score >= 0.6 (higher = more permissive)
temperature: 0.0
max_tokens: 256Ready-to-use policies in src/luthien_proxy/policies/presets/ — no configuration needed:
BlockDangerousCommandsPolicy- Blocks destructive shell commands (rm -rf, chmod 777, mkfs, dd, etc.)BlockSensitiveFileWritesPolicy- Blocks writes to sensitive paths (/etc, ~/.ssh, ~/.gnupg, etc.)BlockWebRequestsPolicy- Blocks outbound network requests (curl, wget, fetch, etc.) to prevent data exfiltrationNoApologiesPolicy- Removes apologetic filler ("I apologize", "I'm sorry") from responsesNoYappingPolicy- Enforces concise responses by cutting filler, hedging, and unnecessary preamblePlainDashesPolicy- Replaces em-dashes and en-dashes with plain hyphens (useful for terminals)PreferUvPolicy- Replaces pip commands with uv equivalents in responses
Example preset config:
policy:
class: "luthien_proxy.policies.presets.no_yapping:NoYappingPolicy"
config: {}Base classes and building blocks in src/luthien_proxy/policies/ — see docs/policies.md for full reference with examples:
Quick Start Presets (zero config):
NoYappingPolicy- Remove filler and hedgingNoApologiesPolicy- Strip apologetic languagePlainDashesPolicy- Replace Unicode dashes with hyphensPreferUvPolicy- Replace pip commands with uv equivalentsBlockDangerousCommandsPolicy- Block rm -rf, chmod 777, etc.BlockWebRequestsPolicy- Block curl, wget, network requestsBlockSensitiveFileWritesPolicy- Block writes to /etc, ~/.ssh, etc.
Core Policies (configurable):
NoOpPolicy- Pass-through (default)SimpleLLMPolicy- Apply plain-English instructions via judge LLMToolCallJudgePolicy- Probability-based tool call blockingStringReplacementPolicy- Fast string find-and-replaceAllCapsPolicy- Simple transformation exampleDebugLoggingPolicy- Log requests/responses for debugging
Composition:
MultiSerialPolicy- Chain policies sequentially
Luthien collects anonymous, aggregate usage metrics to help track adoption and improve the project. No model names, API keys, IP addresses, or request/response content is collected.
Metrics collected every 5 minutes: request counts, token counts (input/output), streaming vs non-streaming breakdown, and active session count. Data is sent to telemetry.luthien.cc (a Cloudflare Worker) and stored in Grafana Cloud.
Telemetry is enabled by default and can be disabled:
# In .env or environment
USAGE_TELEMETRY=falseOr at runtime via the admin API: PUT /api/admin/telemetry with {"enabled": false}.
# Local mode (default)
luthien status # check health
luthien logs # view gateway logs
luthien down && luthien up # full restart
# Docker Compose mode
docker compose ps
docker compose logs gateway
docker compose down && ./scripts/quick_start.sh- Check gateway key: Ensure
Authorization: Bearer <PROXY_API_KEY>header is set - Check upstream credentials:
- OAuth passthrough (default): Run
claude auth loginto ensure your Claude Pro/Max session is active - API key mode: Verify
ANTHROPIC_API_KEYstarts withsk-ant-apiin.env
- OAuth passthrough (default): Run
- Check logs:
luthien logs(local mode) ordocker compose logs -f gateway(Docker mode)
Local mode uses SQLite — if the database file is corrupt, delete it and restart (rm ~/.luthien/local.db && luthien up).
For Docker Compose deployments:
docker compose ps db
docker compose restart db
docker compose run --rm migrationsLocal mode (default):
luthien down
uv tool uninstall luthien-cli
rm -rf ~/.luthien # removes all conversation logs, database, and configDocker Compose mode:
docker compose down -v # -v also removes the persistent database volume
uv tool uninstall luthien-cli
rm -rf ~/.luthien # removes all conversation logs and configClone the repo and start the gateway with SQLite — no Postgres or Redis needed:
git clone https://github.com/LuthienResearch/luthien-proxy.git
cd luthien-proxy
uv sync # Install uv first if needed: https://docs.astral.sh/uv/getting-started/installation/
./scripts/start_gateway.shTo use API key auth, edit .env (auto-created on first run) and add your ANTHROPIC_API_KEY.
The gateway starts at http://localhost:8000. For full development setup, tooling, architecture, and API details, see dev-README.md.
Apache License 2.0