Getting Started
Stand up Felix locally and send your first request. Felix is a self-hostable
managed agents harness: YAML manifests (apiVersion: felix/v1) compile into
runnable agents with governance, durable execution, and multi-protocol surfaces.
- Harness (runtime): felix-run/felix — CPython, Compose / Helm
- Web (optional): felix-run/web — chat-ui + docs on Cloudflare Workers
For the mental model, read Concepts after this. For production deploy shape, see Deploy.
Prerequisites
- Docker + Docker Compose
- uv (Python 3.14+) for local CLI / non-Compose runs
- Optional:
ANTHROPIC_API_KEYand/orOPENAI_API_KEY, or a local Ollama daemon
Bootstrap (Compose)
-
Clone and configure
Terminal window git clone https://github.com/felix-run/felix.git && cd felixcp .env.example .env# set POSTGRES_PASSWORD (and keep FELIX_DATABASE_URL in sync):openssl rand -hex 32 -
Start the lean stack
Terminal window make up# or: docker compose up --buildBrings up api (
:8080), worker, scheduler, Postgres+pgvector, and Valkey. Object store defaults tofsunder/data(no MinIO required).Small hosts:
make up-lite. MinIO + S3 extras:make up-full. -
Migrate
Terminal window make migrate# or: docker compose exec api felix migrate head -
Health check
Terminal window curl -s http://localhost:8080/health | jqmake doctor # from a uv-synced checkout, or: docker compose exec api felix doctor -
Export your local API key
make uprunsscripts/dev-key.sh, which writes an API key into.envon first run and prints it. The Compose stack is authenticated by default and publishes on127.0.0.1.Terminal window export FELIX_KEY=$(grep -o 'sk-felix-local-[a-f0-9]*' .env | head -1)
Authenticated by default
Compose sets FELIX_AUTH_MODE=api_key, so every example below sends a bearer token. If you instead
run without Compose via make dev, the harness starts with FELIX_AUTH_MODE=none bound to
loopback and you can drop the authorization header. none is refused on any non-loopback bind.
First request — Felix-native /chat
The bundled default manifest is quick.
curl -s -X POST http://localhost:8080/chat \ -H "authorization: Bearer $FELIX_KEY" \ -H 'content-type: application/json' \ -d '{ "manifest": "quick", "messages": [{ "role": "user", "content": "What is 7 * 6?" }] }' | jqPass thread_id as a suffix (no : / #); the server prefixes the tenant id:
curl -s -X POST http://localhost:8080/chat \ -H "authorization: Bearer $FELIX_KEY" \ -H 'content-type: application/json' \ -d '{ "manifest": "quick", "thread_id": "session-1", "messages": [{ "role": "user", "content": "And times 10?" }] }' | jqStreaming:
curl -N -X POST http://localhost:8080/chat/stream \ -H "authorization: Bearer $FELIX_KEY" \ -H 'content-type: application/json' \ -d '{"manifest":"quick","messages":[{"role":"user","content":"Say hi."}]}'First request — OpenAI-shaped /v1
model is a Felix manifest name (GET /v1/models):
curl -s -X POST http://localhost:8080/v1/chat/completions \ -H "authorization: Bearer $FELIX_KEY" \ -H 'content-type: application/json' \ -d '{ "model": "quick", "messages": [{ "role": "user", "content": "Say hi." }] }' | jqChat UI (optional)
From felix-run/web, with Compose Felix already on :8080:
git clone https://github.com/felix-run/web.git felix-web && cd felix-webpnpm installpnpm chat:dev # Vite :5173, proxies /api → http://127.0.0.1:8080Offline eval (CI / no API keys)
uv sync --devFELIX_DATABASE_URL=memory://local FELIX_OBJECT_STORE=memory FELIX_ALLOW_INSECURE=true \ uv run felix eval -d smoke -m quick -f fixtures/eval/smoke.json --mock