Quick start¶
Install¶
Python 3.11 or newer is required. The runtime dependencies are fastapi, httpx, pydantic
and uvicorn[standard].
Configure¶
Configuration is entirely JEV_-prefixed environment variables — there is no config
file. Anything you do not set falls back to its default, so the gateway starts in an
empty environment. To keep them together, use the template:
The one line that matters is JEV_BACKEND_BASE_URL — the address of your OpenAI-compatible
server:
Every variable, default and valid range is in the
configuration reference. The server listens on
JEV_SERVER_HOST:JEV_SERVER_PORT (default 0.0.0.0:8000).
Run¶
The console script jev-gateway is equivalent once the variables are exported. You can also
pass them straight on the command line and skip the file entirely:
Check that it is alive:
Send a decision¶
curl -X POST http://127.0.0.1:8000/v1/systemone \
-H 'content-type: application/json' \
-d '{
"model": "jev-latest",
"state": {"error_rate": 0.42, "p99_latency_ms": 3100, "recent_deploy": true},
"questions": {
"is_healthy": {"type": "noul", "instructions": "Is the service healthy?"},
"severity": {
"type": "choice",
"instructions": "Pick the incident severity.",
"criteria": {"sev1": "a whole region is down", "sev2": "error_rate is at least 0.05", "sev3": "below 0.05 and users are unaffected"}
},
"urgency": {
"type": "score",
"instructions": "How urgent is the response?",
"criteria": ["can wait", "today", "right now"]
}
}
}'
{
"model": "Qwen3-4B-Instruct",
"answers": {
"is_healthy": {"type": "noul", "noul": 0.0314},
"severity": {
"type": "choice",
"choice": "sev2",
"probabilities": {"sev1": 0.024, "sev2": 0.921, "sev3": 0.055}
},
"urgency": {
"type": "score",
"score": 1.86,
"legend": {"0": "can wait", "1": "today", "2": "right now"},
"probabilities": {"0": 0.041, "1": 0.058, "2": 0.901}
}
}
}
One request, three decisions, three output tokens.
Docker¶
docker compose up -d # gateway alone
docker compose -f docker-compose.llamacpp.yml up -d # gateway + llama-server
Each template passes configuration through environment: and mounts no file at all. To
change the backend address, change that variable; to change the model, context length or
port, edit the command block. Put a .gguf in ./models before starting a backend
stack. Vision models also need the projector: add
--mmproj /models/mmproj.gguf to the llama-server command and check
GET /props → modalities.vision is true.
Verify end to end¶
curl -s http://127.0.0.1:8000/healthz
curl -s http://127.0.0.1:8000/readyz
curl -s http://127.0.0.1:8000/v1/systemone \
-H 'content-type: application/json' \
-d '{
"model": "jev-latest",
"state": {"error_rate": 0.31, "p99_latency_ms": 4100},
"questions": {
"severity": {
"type": "choice",
"instructions": "Pick the severity.",
"criteria": {
"sev1": "error_rate >= 0.20",
"sev2": "error_rate >= 0.05 but < 0.20",
"sev3": "error_rate < 0.05"
}
}
}
}'
/healthz proves the process is up, /readyz proves the backend is ready and reports the
model it loaded, and the last call returns the official model, answers, and usage
shape. Image requests use assets and references; see the Images guide.
vLLM and SGLang
Only the llama.cpp compose stack ships with this repository. To reach a vLLM or
SGLang server, point backend.base_url at it and set backend.model to the name
the server was started with. See Backends.
Where to go next¶
- How it works — the classification trick and the prompt layouts.
- API reference — every field, endpoint and error code.
- Backends — the
base_urltable for llama.cpp, vLLM and SGLang.