Luminal Docs
Everything you need to install, configure, and use Luminal — the self-hosted LLM routing gateway.
What Luminal Is
Luminal sits between your app and the AI companies (OpenAI, Anthropic, Mistral, etc). Instead of your app calling those companies directly, it calls Luminal. Luminal then:
- Looks at how hard your question is (simple vs. complex).
- Picks the cheapest model that can actually handle it.
- Optionally pulls in extra info from documents you've uploaded (RAG).
- Optionally calls an outside tool (like a weather API) if the prompt needs one.
- Sends the final prompt to the real AI model and gets an answer back.
- Logs everything — cost, tokens used, which model answered, how long it took — so you can see it all on the dashboard.
Two parts run at the same time:
- The BACKEND (the actual gateway/API) — runs on port 8000.
- The DASHBOARD (the web UI you look at in a browser) — runs on port 3000.
How to Run It
You need TWO terminals open at the same time, both running.
Terminal 1 — start the backend (run this from the Luminal folder root):
The --reload flag matters — without it, the backend will NOT pick up any code changes automatically, and you'll have to manually stop and restart it every time something is fixed or changed.
Terminal 2 — start the dashboard:
Then open http://localhost:3000 in your browser.
Before either will work properly, you need a .env file in the Luminal root folder with at least one provider's API key in it (see section 6).
Logging In
The backend automatically creates a default admin account the first time it starts:
Use this to log into the dashboard at http://localhost:3000. You can create more accounts too — the dashboard's sign-up flow handles that.
Under the hood this login gives your browser a JWT (a signed login token). That's what the dashboard uses to talk to the backend on your behalf. You don't need to think about this — it's handled automatically once you're logged in.
Getting a Luminal API Key
The JWT from logging in only works for the dashboard itself. If you want some OTHER app (a script, a curl command, another service) to send prompts to Luminal, you need a Luminal API key instead. These always start with lum_.
How to get one:
- Log into the dashboard.
- Go to the API Keys section.
- Click "Create key", give it a name.
- Copy the key immediately — it's shown once, in full, and never again (only a masked version is shown after that).
Once you have a key, any app can use it like this:
That's it — no SDK needed, just plain HTTP with your key as a Bearer token. Works from Python, JavaScript, curl, Postman, anything that can make an HTTP request.
Sending a Prompt — The Main Endpoint
/routeRequest body (JSON):
promptrequired — the thing you're asking.session_idoptional — leave it out / null to start a fresh conversation. To CONTINUE a previous conversation (multi-turn, so the model remembers earlier messages), pass back the session_id you got in an earlier response.
Response body (JSON):
content— the actual answer text (comes back as Markdown — bold, lists, tables, etc. The dashboard renders this properly; if you're building your own UI on top of Luminal, render it as Markdown too instead of showing the raw ** and ### symbols as plain text).model / complexity— which model Luminal picked and why (based on how complex your prompt looked).cost / tokens_used / latency_ms— what that one request cost you.session_id— save this if you want to continue the conversation next time.citations— filled in only when RAG (document search) was used to help answer your question.
If your monthly budget is used up, you'll get back an HTTP 402 error instead of an answer.
Providers — Where the Actual AI Comes From
Luminal doesn't have its own AI — it calls out to real providers. It currently supports 8:
Ollama is special — it runs completely on your own computer for free (no API key, no internet, no cost), using whatever local models you've pulled with ollama pull <model>. All the others are cloud providers and need an API key from that company.
To add a provider's key:
- Dashboard → Settings.
- Paste the key into that provider's box.
- Click "Update Settings" (this applies immediately, no restart needed — as long as the backend is already running the latest code; see the TROUBLESHOOTING section if a change doesn't seem to take effect).
Choosing which provider Luminal actually uses:
- In the "Route a Prompt" playground, there's a Model Source toggle (Local/Ollama, Cloud/OpenRouter, NVIDIA, Mistral, Gemini) — clicking one switches which provider ALL your requests go through by default.
- The same choice is also in Settings under "Default Provider" — same setting, just reachable two ways.
- Whichever provider is selected, Luminal still picks a cheap/medium/expensive MODEL from that provider depending on how complex your prompt looked (three tiers: low/medium/high complexity).
Selecting a provider in the toggle does NOT save its API key for you — you still have to paste the actual key into Settings separately. The toggle only decides where requests get routed to; Settings is where you authenticate with that provider.
RAG — Asking Questions About Your Own Documents
RAG means: Luminal can read documents you upload and use them to answer your questions more accurately, with citations back to the source.
How to use it:
- Dashboard → Documents.
- Upload a PDF, Markdown, or text file.
- Luminal automatically splits it into chunks, turns those chunks into searchable embeddings, and stores them (Chroma by default; Pinecone or Weaviate are also supported if configured).
RAG doesn't run on every single prompt — it only kicks in when your prompt sounds like a knowledge/lookup question (contains words like "what is", "explain", "according to", "document", "summary of", etc.). A prompt like "hi" won't trigger it; a prompt like "what is our refund policy" will.
When RAG does trigger, the response's "citations" field will be filled in with which document chunks were used.
MCP Tools — Letting Luminal Call Your Own APIs
MCP tools are external APIs you register with Luminal so the model can call them when it needs real, live data (weather, order status, a calculator — anything you can put behind an HTTP endpoint).
How to register one:
- Dashboard → MCP Tools → Add Tool.
- Fill in the fields below.
- Save. From then on, any prompt containing one of your trigger keywords will make Luminal call that tool automatically and feed the result back into the model's answer.
Fields to fill in:
Tool Name— a short label.Endpoint URL— the full URL of your API (e.g. http://localhost:8008/tools/weather).Description— helps you remember what it does.Trigger Keywords— comma-separated words that, if they appear in a prompt, tell Luminal "this prompt probably needs this tool" (e.g. weather, temperature, forecast).Auth Type— how your endpoint expects to be authenticated.
Requires approval before execution — if checked, Luminal will PAUSE the request and wait for you to manually approve it in the dashboard before it actually calls your tool. Useful for anything risky (sending an email, charging a card, etc).
Technical note: Luminal tries POSTing your arguments as JSON first; if your endpoint replies "405 Method Not Allowed" (meaning it only accepts GET), Luminal automatically retries as a GET request with the arguments as query parameters instead. So both GET-style and POST-style tool APIs work without any extra configuration.
Budgets — Controlling Spend
Every account has a monthly budget (in dollars).
- Dashboard → Monthly Budget panel → Edit → type a number → Save.
- At 80% of your budget spent, Luminal automatically starts downgrading to a cheaper model tier for new requests.
- At 95% spent, it pins everything to the cheapest available model.
- At 100% (budget fully used), new requests are rejected outright (HTTP 402 Payment Required) until the budget resets.
- The budget automatically resets back to 0 spent at the start of each calendar month.
Local Ollama requests are always free ($0 cost) since nothing is being paid to a cloud provider — they don't count against your budget in a meaningful way, though they're still logged.
Watching a Live Trace
Every request runs through several stages: analyze → retrieve (RAG) → tool (MCP) → route → generate → critic. You can watch these happen live, step by step, instead of just waiting for the final answer.
- If you send a prompt from the dashboard's own "Route a Prompt" playground, the trace terminal on the right shows it automatically — nothing extra to do.
- If a request came from SOMEWHERE ELSE (curl, another app, using a lum_ API key), the dashboard doesn't automatically know about it. To watch it anyway: every /route response includes a "session_id" — copy that value, paste it into the "Watch another session_id…" box in the trace terminal, and click Watch. You'll see that request's trace live (or its full trace immediately, if it already finished by the time you paste it in).
The Dashboard, Panel by Panel
Quick tour of what each dashboard section does:
Top stat cards— requests/cost/tokens today, this month, and how much budget is left.Cost & Usage Trend— a chart of cost and request count per day, over the last 30 days.Monthly Budget— the circular gauge showing % of budget used, and where you edit your budget limit.RAG & Tool Usage— what % of your requests actually used document retrieval vs. tool calls, and their average cost/latency.Model Performance— cost, tokens, latency, and quality score broken down per model you've actually used.Route a Prompt— the playground where you type a prompt, pick a provider, and see the live trace + answer.Documents— upload/manage files for RAG.MCP Tools— register/manage external tool APIs.API Keys— create/revoke lum_ keys for external apps.Logs— a table of every request ever made, with full details.Settings— provider API keys, default provider, and whether to use an LLM (instead of simple keyword heuristics) to judge prompt complexity.
Quick Endpoint Reference
Auth
/auth/registercreate an account/auth/loginlog in, get a JWT (used by the dashboard)/auth/meget the logged-in user's infoAPI keys
/api-keyscreate a new lum_ key/api-keyslist your keys (masked)/api-keys/{id}revoke a keyRouting
/routesend a prompt, get an answer/route/streamsame, but streamed token-by-token/route/approveapprove/deny a tool call that's paused waiting for your OK/route/trace/{session_id}live trace of one request (SSE)Documents / RAG
/documents/uploadupload a file to be searchable/documentslist uploaded documents/documents/{id}remove oneDashboard data
/dashboard/statstoday/month totals/dashboard/budgetcurrent budget status/dashboard/cost-breakdowndaily cost/request trend/dashboard/model-performanceper-model stats/dashboard/rag-statsRAG/tool usage stats/dashboard/logsfull request historySettings
/dashboard/settingscurrent provider keys (masked) + config/dashboard/settingsupdate provider keys / default providerMCP tools
/dashboard/mcp-toolslist your registered tools/dashboard/mcp-toolsregister a new one/dashboard/mcp-tools/{id}edit one/dashboard/mcp-tools/{id}remove oneTroubleshooting
Q.I changed a setting / added an API key and nothing changed.
Make sure the backend was started WITH --reload. If it wasn't, it will never pick up code changes on its own — you have to manually stop it (Ctrl+C) and run the start command again. Settings saved to the database (API keys, default provider, budget) apply instantly without a restart; only actual CODE changes need a restart.
Q.I get a 402 error.
Your monthly budget is used up, or a cloud provider rejected the request for billing reasons (e.g. no credits on that provider's account). Check Settings → provider keys, or switch to Ollama (free/local) temporarily.
Q.I get a 405 error calling my own MCP tool.
Luminal automatically retries as GET if POST gets a 405, so this should self-resolve. If it still fails, double check your endpoint's auth header expectations match the Auth Type you picked when registering the tool.
Q.The trace panel is empty / stuck on IDLE.
It only auto-connects for prompts sent from the dashboard's own playground. For external requests, paste that request's session_id into the "Watch another session_id…" box (see section 10).
Q.Ollama error: All connection attempts failed.
Ollama isn't running locally. Run `ollama serve` in a terminal, and make sure you've pulled the model it's asking for, e.g. `ollama pull mistral`.
Ready to start?
Spin up the backend and dashboard, drop in your provider keys, and start routing.