Introduction
Getting Started: Self-Host in 5 Minutes
Getting Started: Self-Host in 5 Minutes
This guide gets a LADR stack running on your machine in under five minutes using Docker Compose. You will start the services, open Foundry in your browser, create your first ladder, and call it via curl.
Prerequisites
- Docker and Docker Compose (v2+). Both are included in Docker Desktop.
- An LLM provider API key (OpenAI, Anthropic, or any OpenAI-compatible provider).
- Git to clone the repository.
No Go, Node.js, or other language toolchain is required. Everything runs inside containers.
Step 1: Clone and configure
git clone https://github.com/redeolabs/ladr.git
cd ladr
cp .env.example .envEdit .env and set your provider keys:
# At minimum, set one provider key:
OPENAI_API_KEY=sk-...
# ANTHROPIC_API_KEY=sk-ant-...
# Database (defaults work for Docker Compose):
DATABASE_URL=postgres://ladr:ladr@db:5432/ladr
REDIS_URL=redis://redis:6379Step 2: Start the stack
docker compose up -dThis starts seven services:
| Service | Port | Purpose |
|---|---|---|
| gateway | 8788 | OpenAI-compatible API. Entry point for all ladder calls. |
| api | 3001 | REST API for ladder CRUD, provider management. |
| engine | 3004 | Execution engine. Runs ladder steps. |
| worker | 3005 | Asynq worker. Processes engine jobs from the queue. |
| foundry | 3006 | Visual ladder editor. Browser-based. |
| postgres | 5432 | PostgreSQL database. Stores ladder configs, users, providers. |
| redis | 6379 | Redis. Pipeline state, event streams, job queue. |
Verify all services are healthy:
docker compose psEvery service should show Up or healthy.
Step 3: Open Foundry and configure a provider
Open your browser to:
http://localhost:3006Foundry is the visual editor where you author ladders. On first launch, you will create an account (stored locally in your PostgreSQL instance).
Configure a provider
Before you can run ladders, Foundry needs at least one LLM provider configured. Navigate to Settings, Providers where you have two options:
-
Add a Custom Provider. Enter your own API key and (optionally) a custom base URL for any OpenAI-compatible provider (OpenAI, Anthropic, DeepInfra, Together, etc.). The key is stored encrypted in your local PostgreSQL database and used by the engine when dispatching LLM calls.
-
Sign in with Redeo. If you have a Redeo account, signing in loads your connected providers from the Redeo platform. When connected:
- Ladder execution routes through Redeo's servers (no local processing).
- Your provider keys are used on the server side.
- Only public ladders from the Redeo directory are visible. Private and closed ladders remain invisible — the self-hosted instance cannot access them.
For local-only operation, use Add a Custom Provider. The ladder engine runs entirely on your infrastructure using your own provider keys.
Generate an API key
Navigate to Settings, API Keys and create a key. Save it — you will use it in curl calls.
export LADR_API_KEY="lk_..."Step 4: Create and call your first ladder
In Foundry, click New Ladder. Paste this minimal config:
name: Echo
allowedTargets: { strategy: universal }
exit: answer
knobs: {}
steps:
- id: answer
name: Answer
fields:
- { name: Question, type: text, from: input.context }
systemPrompt: "Answer the question concisely."Click Save. The ladder is stored as local/echo (the local author namespace is used for self-hosted ladders).
Call it via curl
curl http://localhost:8788/v1/local/echo/chat/completions \\
-H "Authorization: Bearer $LADR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "What is 2+2?"}]
}'The URL path encodes the ladder identity: /v1/{author}/{ladder-name}/. For self-hosted ladders, the author is local. The model field is the actual LLM model you want to use.
You will receive a standard OpenAI chat completion response:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"model": "gpt-4o",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "4"
},
"finish_reason": "stop"
}],
"usage": { ... }
}Step 5: Use any OpenAI client
Because the gateway is OpenAI-compatible, any existing OpenAI client works with a one-line base URL change:
Python (openai library):
from openai import OpenAI
client = OpenAI(
api_key="lk_...",
base_url="http://localhost:8788/v1/local/echo"
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "What is 2+2?"}]
)
print(response.choices[0].message.content)JavaScript (openai npm):
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "lk-...",
baseURL: "http://localhost:8788/v1/local/echo",
});
const response = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "What is 2+2?" }],
});
console.log(response.choices[0].message.content);Passing knobs:
Knobs are caller-tunable parameters declared in the ladder config. Pass them in the request body to control fan-out, recursion depth, and other strategy parameters at call time:
curl http://localhost:8788/v1/local/draft-refine/chat/completions \\
-H "Authorization: Bearer $LADR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Design a REST API for a todo app."}],
"knobs": { "branches": 5, "verifiers": 3 },
"maxLoops": 3
}'Architecture overview
The request flow through the seven services:
Caller Gateway(:8788) Redis(Job Queue)
│ │ │
│ POST /v1/author/ │ │
│ ladder/chat │ │
├──────────────────────▶│ │
│ │ enqueue job │
│ ├────────────────────────▶│
│ │ │
│ │ Worker(:3005)
│ │ │
│ │ │ dequeue
│ │ ▼
│ │ Engine(:3004)
│ │ │
│ │ ┌─────┼─────────┐
│ │ │ │ │
│ │ ▼ ▼ ▼
│ │ Redis PostgreSQL LLM Provider
│ │ (state) (configs)
│ │
│ ◀─────────────┘ (exit step output → chat completion response)- Caller sends
POST /v1/{author}/{ladder}/chat/completionswithmodel: "gpt-4o"and amessagesarray. - Gateway authenticates via API key, resolves the ladder config from PostgreSQL, validates it, and creates a pipeline instance in Redis.
- Gateway enqueues an engine job.
- Worker picks up the job and calls the engine.
- Engine walks the steps, dispatches LLM calls via the configured provider, stores outputs in Redis, and publishes lifecycle events.
- On completion, the exit step's output is returned as the chat completion response.
Local execution (default). When you add a custom provider (your own API key), the engine runs on your infrastructure. The gateway receives the request, enqueues a job, the worker picks it up, and the engine dispatches LLM calls using your provider key. All processing is local.
Redeo-routed execution. When you sign in with Redeo, the platform can route execution through Redeo's servers instead of processing locally. Your provider keys (loaded from Redeo) are used server-side.
Troubleshooting
Services won't start. Check docker compose logs gateway for errors. The most common issue is a missing or invalid .env file.
404 on ladder call. Make sure you saved the ladder in Foundry and the URL path matches local/<ladder-name>. The name in the URL path must match the name: field in the ladder YAML, not the Foundry display name. The model field in the request body should be a valid LLM model name (e.g., gpt-4o), not the ladder name.
No LLM provider configured. Add a provider in Foundry under Settings, Providers. The engine needs at least one provider with a valid API key to dispatch LLM calls.
Port already in use. If ports 8788, 3001, 3004, 3005, or 3006 are already in use, edit docker-compose.yml to remap them.
Database not initialized. Run docker compose exec api /app/api --migrate to run database migrations manually.