LLM Gateway with Anthropic-compatible API
Project description
TTLLM Gateway
LLM gateway exposing an Anthropic-compatible API (POST /v1/messages), routing requests through LangChain to any supported provider (Bedrock, OpenAI, etc.). Tracks tokens, costs, and maintains audit trails. Supports user management with per-user model access control.
Quick Start
Prerequisites
- Python 3.12+
- PostgreSQL 16
- Docker (optional)
Run with Docker Compose
docker-compose up
This starts PostgreSQL and the API on port 8000. Migrations run automatically on container start.
A default admin account is created by the migrations:
- Email:
admin@localhost - Password: value of
TTLLM_ADMIN_PASSWORD(defaults toadmin)
Set TTLLM_ADMIN_PASSWORD before running migrations to use a custom password. Log in via ttllm login and change the password or create a new admin user immediately.
Run from Docker Image
# From GitHub Container Registry
docker run -p 8000:8000 \
-e TTLLM_DATABASE__URL="postgresql+asyncpg://user:pass@host:5432/ttllm" \
ghcr.io/ponquersohn/ttllm-gateway:latest
Passing configuration
Option A - Mount a config file:
docker run -p 8000:8000 \
-v /path/to/config.yaml:/app/config.yaml \
-e TTLLM_CONFIG_FILE=/app/config.yaml \
-e TTLLM_CONFIG_ENV=prod \
ghcr.io/ponquersohn/ttllm-gateway:latest
Option B - Environment variables only:
docker run -p 8000:8000 \
-e TTLLM_DATABASE__URL="postgresql+asyncpg://user:pass@host:5432/ttllm" \
-e TTLLM_AUTH__JWT__SECRET_KEY="your-secret" \
-e TTLLM_ENGINE__LISTEN_PORT=8000 \
-e TTLLM_PROVIDER__DEFAULT_REGION="us-east-1" \
ghcr.io/ponquersohn/ttllm-gateway:latest
The container listens on port 8000 by default (configurable via engine.listen_port). Map it to any host port with -p <host>:<container>.
Debugging failed containers
By default the container exits on error. Set TTLLM_EXIT_ON_ERROR=false to keep the container alive after a failure, so you can exec into it for debugging:
docker run -p 8000:8000 \
-e TTLLM_EXIT_ON_ERROR=false \
-e TTLLM_DATABASE__URL="postgresql+asyncpg://user:pass@host:5432/ttllm" \
ghcr.io/ponquersohn/ttllm-gateway:latest
Install from PyPI
pip install ttllm-gateway
Run Locally
pip install -e .
alembic upgrade head
uvicorn ttllm.handlers.ecs_entrypoint:app --reload
Configuration
Settings are resolved in order: YAML config file -> environment variables -> defaults.
| Environment Variable | Description | Default |
|---|---|---|
TTLLM_CONFIG_FILE |
Path to YAML config file | (none) |
TTLLM_CONFIG_ENV |
Environment section to load | dev |
TTLLM_DATABASE__URL |
PostgreSQL connection string | postgresql+asyncpg://ttllm:dev@localhost:5432/ttllm |
TTLLM_ENGINE__LISTEN_PORT |
Server listen port | 8000 |
TTLLM_ENGINE__BASE_URL |
External-facing URL (for OAuth callbacks) | http://localhost:4000 |
TTLLM_ENGINE__CORS_ORIGINS |
Allowed CORS origins | ["*"] |
TTLLM_AUTH__JWT__SECRET_KEY |
JWT signing secret | CHANGE-ME-IN-PRODUCTION |
TTLLM_PROVIDER__DEFAULT_REGION |
AWS region for Bedrock | us-east-1 |
TTLLM_SECRETS__ENCRYPTION_KEY |
Fernet key for encrypting secrets | (none) |
Nested env vars use __ as delimiter. YAML values support env://VAR,default and secret://arn resolution patterns. Local overrides via local.config.yaml (git-ignored).
Config file example
dev:
database:
url: "postgresql+asyncpg://ttllm:dev@localhost:5432/ttllm"
pool_size: 5
engine:
base_url: "http://localhost:8000"
listen_port: 8000
cors_origins: ["*"]
log_request_bodies: false
auth:
jwt:
secret_key: "dev-secret"
algorithm: "HS256"
access_token_ttl_minutes: 15
identity_providers:
entra:
name: "Entra ID"
type: "oidc"
client_id: "..."
provider:
default_region: "us-east-1"
secrets:
encryption_key: "env://TTLLM_SECRETS_ENCRYPTION_KEY"
Secrets Management
Provider credentials (AWS keys, API keys, etc.) can be stored encrypted in the database and
referenced from model configs using secret://name. This avoids storing plaintext credentials
in config_json.
Setup
- Generate an encryption key and add it to your config:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
Add to config.yaml:
dev:
secrets:
encryption_key: "your-generated-key"
Or via environment variable: TTLLM_SECRETS__ENCRYPTION_KEY.
- Create secrets:
ttllm secrets create --name aws-bedrock-key # prompts for value (hidden)
ttllm secrets create --name aws-bedrock-secret # prompts for value (hidden)
- Reference secrets in model config:
ttllm models create \
--name claude-sonnet \
--provider bedrock \
--provider-model-id anthropic.claude-3-sonnet-20240229-v1:0 \
--config '{"aws_access_key_id":"secret://aws-bedrock-key","aws_secret_access_key":"secret://aws-bedrock-secret","region":"us-west-2"}'
At runtime, secret:// references are resolved transparently before the provider client is created. Secret values are never exposed through the API or CLI.
CLI
Admin operations via the ttllm CLI:
ttllm users list|show|create|update|delete
ttllm models list|show|create|update|delete|assign|unassign
ttllm groups list|show|create|update|delete
ttllm tokens list|show|create|delete
ttllm secrets list|show|create|update|delete
ttllm usage summary|costs [--user] [--model] [--since] [--until]
ttllm audit-logs [--user] [--model] [--limit]
Releasing
Releases are created from the main branch. The Makefile bumps the version in src/ttllm/__init__.py and shows the commands to complete the release:
make release # Patch bump (v0.0.1 -> v0.0.2)
make release-minor # Minor bump (v0.1.0 -> v0.2.0)
make release-major # Major bump (v1.0.0 -> v2.0.0)
After running make release*, follow the printed instructions to commit, tag, push, and create the GitHub release. Publishing a GitHub release triggers the CI workflow to:
- Validate that the git tag matches the
__version__in code - Publish the Python package to PyPI
- Build and push the Docker image to
ghcr.io/ponquersohn/ttllm-gateway
Development
pip install -e ".[dev]"
pytest
Project details
Release history Release notifications | RSS feed
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 ttllm_gateway-0.0.9.tar.gz.
File metadata
- Download URL: ttllm_gateway-0.0.9.tar.gz
- Upload date:
- Size: 61.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
604deaa383f9ac133b47f4d5adb05f391766b9a9ba3786a6796b64eea518a67e
|
|
| MD5 |
8daf195e8668bcd23fa1d316cb60348e
|
|
| BLAKE2b-256 |
1efaa2618e8804c04136c1ac10a173296d67c42d02a677c8a9305832f3930c66
|
Provenance
The following attestation bundles were made for ttllm_gateway-0.0.9.tar.gz:
Publisher:
release.yml on ponquersohn/ttllm-gateway
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ttllm_gateway-0.0.9.tar.gz -
Subject digest:
604deaa383f9ac133b47f4d5adb05f391766b9a9ba3786a6796b64eea518a67e - Sigstore transparency entry: 1262659389
- Sigstore integration time:
-
Permalink:
ponquersohn/ttllm-gateway@2c2ad002443ec052509c6d543853db5a9b65521a -
Branch / Tag:
refs/tags/v0.0.9 - Owner: https://github.com/ponquersohn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2c2ad002443ec052509c6d543853db5a9b65521a -
Trigger Event:
release
-
Statement type:
File details
Details for the file ttllm_gateway-0.0.9-py3-none-any.whl.
File metadata
- Download URL: ttllm_gateway-0.0.9-py3-none-any.whl
- Upload date:
- Size: 59.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d018bc819b09147e9370a4ed80bc9b8ef5dac225c474393e3e8f909eee8f9db
|
|
| MD5 |
97dced02e78540adac2dd223786a6204
|
|
| BLAKE2b-256 |
f2ca44232eec752291d04d7df04faf4e86b7ad66302da0f879a62c998754728c
|
Provenance
The following attestation bundles were made for ttllm_gateway-0.0.9-py3-none-any.whl:
Publisher:
release.yml on ponquersohn/ttllm-gateway
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ttllm_gateway-0.0.9-py3-none-any.whl -
Subject digest:
3d018bc819b09147e9370a4ed80bc9b8ef5dac225c474393e3e8f909eee8f9db - Sigstore transparency entry: 1262659398
- Sigstore integration time:
-
Permalink:
ponquersohn/ttllm-gateway@2c2ad002443ec052509c6d543853db5a9b65521a -
Branch / Tag:
refs/tags/v0.0.9 - Owner: https://github.com/ponquersohn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2c2ad002443ec052509c6d543853db5a9b65521a -
Trigger Event:
release
-
Statement type: