Enterprise LLM proxy built on LiteLLM — logging, guardrails, and unified access for AI coding tools.
Project description
Airlock
Enterprise LLM proxy built on LiteLLM — unified access, logging, and guardrails for AI coding tools.
Airlock sits between your developers and LLM providers, giving you visibility and control without slowing anyone down.
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Cursor │ │ Claude │ │ Copilot │
│ │ │ Code │ │ │
└─────┬─────┘ └─────┬────┘ └─────┬─────┘
│ │ │
└───────────┬───┘──────────────┘
│
┌─────▼──────┐
│ AIRLOCK │ ← logging, PII guard, keyword guard
│ (LiteLLM) │
└──────┬──────┘
│
┌─────────┼──────────┐
│ │ │
┌────▼───┐ ┌───▼────┐ ┌──▼──────┐
│Anthropic│ │ OpenAI │ │ Internal│
│ API │ │ API │ │ RAG │
└────────┘ └────────┘ └─────────┘
What it does
| Concern | How Airlock handles it |
|---|---|
| Unified access | Single OpenAI-compatible endpoint for all providers |
| Logging | Every request/response logged as structured JSONL |
| PII stripping | Microsoft Presidio scrubs credit cards, SSNs, emails, etc. before they leave the network |
| Keyword blocking | Custom blocklist prevents restricted project names or terms from leaking |
| Budget control | Per-user/per-team spend limits via LiteLLM virtual keys |
| Multi-tool support | Works with Cursor, Claude Code, GitHub Copilot, and any OpenAI-compatible client |
| Self-hosted models | Route to local vLLM, Ollama, or any OpenAI-compatible endpoint alongside cloud providers |
| Interactive testing | Built-in Basic Chat screen to test LLM connectivity and inspect full request/response cycles |
Getting started
Install from PyPI
pip install airlock-llm
python -m spacy download en_core_web_lg # required for PII redaction
airlock init
airlock init generates config.yaml, .env, and a logs/ directory in the
current working directory.
Install from source (quick setup)
git clone https://github.com/coreyt/airlock && cd airlock
./scripts/setup.sh
This installs Airlock and its dependencies, downloads the spaCy model for PII
redaction, and runs airlock init. Pass --pip to use pip instead of uv.
Developer setup
git clone https://github.com/coreyt/airlock && cd airlock
./scripts/setup-dev.sh
Everything in the standard setup, plus all optional extras (test, metrics,
tracing, search, s3, sql), install verification, and a test suite run. Pass
--pip to use pip instead of uv.
Add your API keys
Edit the generated .env file and fill in your provider keys:
# .env
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
You only need keys for the providers you plan to use. If you only use Anthropic models, you can leave OPENAI_API_KEY blank.
Start the proxy
# Option A: TUI dashboard with built-in proxy (recommended)
uv run airlock tui --start
# Option B: proxy only (headless)
uv run airlock start
Airlock listens on http://localhost:4000 by default. Change the port with AIRLOCK_PORT in .env.
Test it
curl http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-airlock-change-me" \
-d '{
"model": "claude-sonnet",
"messages": [{"role": "user", "content": "Hello!"}]
}'
Or use the TUI's Basic Chat screen (press 0) to interactively test any configured model and inspect the full request/response headers and body.
Alternative: Docker
docker compose up --build
Connecting AI tools
Point any OpenAI-compatible client at http://localhost:4000 (or your deployed Airlock URL).
Claude Code
# Install client-side hooks and route traffic through the proxy
airlock hooks install
eval $(airlock dogfood)
claude
Every request now flows through PII redaction, keyword blocking, and JSONL logging. Open airlock tui in another terminal to watch traffic in real time.
See dev/dogfooding.md for the full setup guide.
Cursor / Windsurf
In settings, set:
- OpenAI Base URL:
http://localhost:4000/v1 - API Key: your Airlock master key (from
.env)
GitHub Copilot
In VS Code settings.json:
{
"github.copilot.advanced": {
"debug.overrideProxyUrl": "http://localhost:4000/v1"
}
}
Configuration
config.yaml
The main configuration file defines models, callbacks, and guardrails. See the inline comments in config.yaml for details.
Key sections:
model_list— which LLM providers/models to exposelitellm_settings— callbacks, timeouts, budgetsrouter_settings— routing strategy, fallbacks, provider budgetsguardrails— PII and keyword guardsmcp_servers— MCP tool servers (Armada, ADO, etc.) accessible via the proxygeneral_settings— master key, host/port
Self-hosted / local models
Airlock supports any OpenAI-compatible endpoint (vLLM, Ollama, LocalAI, etc.) using the openai/ prefix with a custom api_base:
# config.yaml — add to model_list
- model_name: gemma-4
litellm_params:
model: openai/gemma4-31b # model ID as reported by the server
api_base: http://your-host:8000/v1
api_key: os.environ/VLLM_API_KEY # use "dummy-key" if server has no auth
# .env
VLLM_API_KEY=dummy-key
The model will appear in the TUI Basic Chat screen for interactive testing and can be used by any connected client via model: "gemma-4".
Environment variables
| Variable | Description | Default |
|---|---|---|
ANTHROPIC_API_KEY |
Anthropic API key | — |
OPENAI_API_KEY |
OpenAI API key | — |
AIRLOCK_MASTER_KEY |
Master key for admin endpoints | — |
AIRLOCK_HOST |
Bind address (set to 0.0.0.0 to expose externally) |
127.0.0.1 |
AIRLOCK_PORT |
Listen port | 4000 |
AIRLOCK_LOG_DIR |
Directory for JSONL log files | ./logs |
AIRLOCK_MAX_LOG_DAYS |
Days to retain log files before cleanup | 30 |
AIRLOCK_MAX_LOG_SIZE_MB |
Max log file size before rotation | 500 |
AIRLOCK_BLOCKED_KEYWORDS |
Comma-separated restricted phrases | — |
AIRLOCK_PII_ENTITIES |
Presidio entity types to redact | CREDIT_CARD,US_SSN,EMAIL_ADDRESS,PHONE_NUMBER |
Adding MCP servers
Airlock can proxy MCP tool servers alongside LLM providers. Add entries to mcp_servers in config.yaml. LiteLLM spawns stdio servers from the proxy's working directory, so command resolution matters.
Command resolution patterns
Module via python -m — cwd-independent, requires package installed in the proxy's venv:
mcp_servers:
ado_mcp:
command: uv
args: ["run", "python", "-m", "ado_mcp.mcp.server"]
env:
ADO_ORG_URL: os.environ/ADO_ORG_URL
ADO_PAT: os.environ/ADO_PAT
Installed script via uv run — cwd-independent, resolves from PATH/venv:
armada:
command: uv
args: ["run", "armada-mcp"]
env:
ARMADA_PROFILE: essential
Script file — must use an absolute path (relative paths resolve against the proxy's cwd, not the server's project directory):
mono_tui:
command: python3
args: ["/home/user/projects/my-mcp-server/server.py"]
Other runtimes:
# Node.js
my_node_server:
command: node
args: ["/path/to/server.js"]
# npx (installed package)
my_npx_server:
command: npx
args: ["my-mcp-server"]
# Bun
my_bun_server:
command: bun
args: ["run", "/path/to/server.ts"]
# Poetry
my_poetry_server:
command: poetry
args: ["run", "python", "-m", "my_server"]
Environment variables
Use os.environ/VAR_NAME to pass environment variables from Airlock's .env to the MCP server. Airlock validates these references at startup and gives clear error messages for missing values.
Guardrail coverage
All MCP tool calls flow through the same guardrail pipeline as LLM requests (PII redaction, keyword blocking, threat detection). MCP-specific guards add tool allowlist/blocklist and argument sanitization. No extra configuration needed — guardrails apply automatically.
Project structure
airlock/
├── proxy.py # Entry point — launches LiteLLM subprocess
├── callbacks/ # JSONL logger, S3, SQL, Prometheus, OpenTelemetry
├── guardrails/ # PII redaction, keyword blocking, semantic, adaptive
├── fast/ # Real-time: threat detection, circuit breaker, priority
├── slow/ # Offline: log analysis, trend detection, tuning
├── hooks/ # Claude Code client-side hooks (session, prompt, audit)
├── cli/ # Unified CLI: init, start, status, tui, analyze, hooks
└── tui/ # Textual terminal dashboard (10 screens, proxy control)
scripts/
├── setup.sh # Standard setup (install + init + spaCy model)
└── setup-dev.sh # Developer setup (all extras + tests)
Production deployment
See docs/operations.md for deployment guides (Docker, Kubernetes, bare metal), monitoring, security checklist, and upgrade procedures.
See docs/troubleshooting.md for common issues and debugging.
License
Apache 2.0
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 airlock_llm-0.1.1.tar.gz.
File metadata
- Download URL: airlock_llm-0.1.1.tar.gz
- Upload date:
- Size: 250.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c35db8d1657fa7de6c676fa61335d92370a50f61821074d7a0ce6d0bbadf433e
|
|
| MD5 |
dbfe3793a621c1e358a849bba2c8373b
|
|
| BLAKE2b-256 |
4f481e3c4a59851274b09afd0e0ce7e9730f592dca9a18acb4485f4f7197e271
|
File details
Details for the file airlock_llm-0.1.1-py3-none-any.whl.
File metadata
- Download URL: airlock_llm-0.1.1-py3-none-any.whl
- Upload date:
- Size: 179.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e121570165140de8c5a13efbf9ec08959d667ced5ceae32b535406205ae7daac
|
|
| MD5 |
e1ee0ea39bba2dc1c8c29a49388362aa
|
|
| BLAKE2b-256 |
8c3a56d3e69a25b9032cb7d94031713975357d311635f898666fd1ddc2ad8d90
|