Support v1.0.0

Setup guide, design rationale, and troubleshooting. If something is missing, open an issue.

Prerequisites

Python 3.14+ (or Docker)
PostgreSQL 15+ (or Docker)
Redis 7+ (or Docker)
LLM API key (OpenRouter free tier or OpenAI)
uv package manager

Environment

LLM_PROVIDER            "openai" or "openrouter". Default: openrouter.
LLM_MODEL               Model ID. Default: nvidia/nemotron-3-super-120b-a12b:free.
OPENROUTER_API_KEY      Required if LLM_PROVIDER=openrouter.
OPENAI_API_KEY          Required if LLM_PROVIDER=openai.
REQUIRE_AUTH            Set to "true" to enable API key validation. Default: false.
DATABASE_URL            PostgreSQL connection string.
DATABASE_READONLY_URL   Optional. Read-only replica for queries.
REDIS_URL               Redis connection string.
CSRF_SECRET_KEY         Optional. Secret for signing CSRF cookies.
ALLOWED_ORIGINS         Optional. Comma-separated CORS origins.
MAX_PROMPT_LENGTH       Max prompt chars. Default: 2000.
QUERY_TIMEOUT_SECONDS   Query execution timeout. Default: 30.
LOG_LEVEL               Logging level. Default: INFO.
LOG_FORMAT              "json" or "text". Default: json.

Quick start

git clone https://github.com/palmshed/predicate.git
cd predicate
cp .env.example .env
# Set OPENROUTER_API_KEY or OPENAI_API_KEY in .env
docker-compose up --build

API docs at http://localhost:8000/docs

Why this exists

Most natural language to SQL tools let the AI generate raw SQL directly. This is a security risk. The AI can hallucinate table names, inject arbitrary queries, or leak data across tenants.

predicate solves this by introducing a structured intermediate layer. The AI generates a constrained JSON blueprint (Pydantic validated). The compiler translates that blueprint into parameterized SQL. The AI never touches the query string.

Design decisions

Troubleshooting

Symptom Cause Resolution
401 Unauthorized Missing or invalid API key Include X-Predicate-API-Key header. Check key in mock registry.
403 Forbidden CSRF token missing, expired, or mismatched Ensure cookies are enabled. If behind a proxy, check that the X-CSRF-Token header matches the signed cookie. Set CSRF_SECRET_KEY for persistence.
429 Too Many Requests Rate limit exceeded for your tier Wait for the window to reset. Sandbox: 60 RPM, Growth: 20 RPM, Enterprise: 100 RPM.
Empty results array Query returned no matching rows Check your data. Tenant isolation filters by tenant_id.
Compilation error AI generated invalid blueprint Check LLM API key in .env. The Pydantic schema constrains output to valid blueprints.
Query timeout Execution exceeded QUERY_TIMEOUT_SECONDS Increase timeout or optimize the query. Default is 30 seconds.
Export stuck in PROCESSING Celery worker not running Start Celery: celery -A app.worker worker --loglevel=info
Redis connection error Redis not running Start Redis via Docker Compose, or caching falls back to no-cache mode.
DB connection pool exhausted Too many concurrent queries Increase maxconn in connection.py or reduce concurrency.

Health endpoints

GET /health    → {"status": "healthy", "checks": {"db": true, "redis": true}, ...}
GET /ready     → 200 if all checks pass, 503 otherwise
GET /metrics   → Prometheus text format

Found something unexpected? Report an issue.