Panda Router MCP
Routes tasks to local Ollama library models and returns an Ollama model name that can be run with ollama run; includes Ollama model cards, though local models may need to be pulled first.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Panda Router
A small local router that picks which LLM should handle a task.
A 31 MB ONNX task profiler (Ettin-32M, distilled from a 150M teacher) reads the task text and outputs a
category, a difficulty from 1 to 10, the skill levels it needs, and a few flags. A learned success head turns that
profile into a calibrated P(success) for each model it was trained on; the other cards use a conservative prior.
A deterministic policy then scores about 65 model cards (Claude, Codex/GPT, Grok, GLM, Kimi, top OpenRouter models,
Ollama library models) by P(success), expected cost (failures included) and latency, and picks one under the mode you
choose. It also returns an escalation_ladder: the models to try, in order, if you verify the result and it fails.
A route takes roughly 10-25 ms on a CPU. Nothing leaves your machine.
task text + optional context
|
v
+-------------------------------+
| profiler (ONNX int8, 31 MB) | category, difficulty 1-10,
| Ettin-32M encoder + heads | skill levels, flags, token estimate
+---------------+---------------+
| TaskProfile
v
+-------------------------------+ cards/*.json + success head
| matcher (deterministic) | <-- per-model skills, price,
| calibrated P(success), cost | context, latency
+---------------+---------------+
| mode: max_utility (default) | max_quality | cheapest_above_threshold
v
choice + ranking + escalation_ladder + trace_id
-> you run it and verify -> /outcome (on failure: /escalate -> next model)Features: pool name aliases (your exact string is echoed back, card_id shows the match), newer versions
supersede older ones when they are not pricier, an escalation ladder that /escalate follows after a failure, SQLite
outcome logging, an HTTP server, a CLI, a Python API and an MCP server.
The router returns a model name. It does not call the model or check its answer. See docs/INTEGRATIONS.md for how to turn the pick into
claude --model,codex -m,ollama runor an OpenRouter slug, and docs/BEST_RESULTS.md for the route, verify, escalate loop that gets the best results.
Quickstart
Requires Python 3.12+.
git clone https://github.com/AICodeKing/PandaOrchestrator.git
cd PandaOrchestrator
python3.12 -m venv .venv && . .venv/bin/activate
pip install -e . # core: serving only (onnxruntime, transformers tokenizer, numpy, scipy, jsonschema; no torch)
pip install -e ".[train]" # optional: torch and friends, only needed to retrain or export (see docs below)The trained profiler and success head ship in the repo at artifacts/panda-router-v4/ (31 MB int8 ONNX
model.int8.onnx, heads.json, success_head.json, tokenizer files). The CLI, the HTTP server and the MCP server
all default to that directory in a source checkout (or $PANDA_ROUTER_ARTIFACTS); outside one they fall back to a
keyword heuristic profiler, which works but is clearly weaker. An explicitly given --artifacts directory that fails
to load is an error, not a silent fallback.
Route one task (CLI)
panda-router route --artifacts artifacts/panda-router-v4 --no-log \
--task 'Rename a variable in utils.py' \
--pool claude/sonnet-5-5,claude-haiku-5.5,gpt-oss:20b --mode max_utility --top-k 3panda-router route prints a RouteResponse as JSON. Add --profile to include the full TaskProfile,
--context '{"repo_languages":["python"],"files_in_scope":2}' for hints, --local-only, --max-cost USD,
--min-p 0.5. All flags are listed in docs/API.md. The CLI loads the model on every call; for
loops use the server.
Start the HTTP server
panda-router-serve --port 8765 --artifacts artifacts/panda-router-v4
# [panda-router] listening on http://127.0.0.1:8765 (profiler=OnnxProfiler(panda-router-v4/model.int8.onnx), ...)
curl -s localhost:8765/healthStart the MCP server (stdio)
panda-router-mcp --artifacts artifacts/panda-router-v4It speaks newline-delimited JSON-RPC on stdin/stdout and exposes route_task, escalate_task,
record_outcome and list_models. Clients normally launch it for you; see
docs/INTEGRATIONS.md. In a source checkout, --artifacts defaults to
artifacts/panda-router-v4 when that directory exists.
Related MCP server: OpenMayhem MCP
Example
curl -s -X POST localhost:8765/route -H 'content-type: application/json' -d '{
"task": {"text": "Migrate our Express auth middleware to use JWT refresh tokens and update all call sites",
"context": {"repo_languages": ["typescript"], "files_in_scope": 12}},
"pool": ["claude-sonnet-5.5", "claude-haiku-5.5", "codex-gpt-6-luna", "ollama-qwen3-coder-30b"],
"preferences": {"mode": "cheapest_above_threshold", "min_p_success": 0.5},
"return_top_k": 2
}'Real output, trimmed to the main fields (full field list in docs/API.md):
{
"choice": {"model_id": "claude-sonnet-5.5", "confidence": 0.6227, "confidence_lower": 0.5427,
"decided_by": "policy:cheapest_above_threshold", "propensity": 1.0, "explored": false},
"ranking": [
{"model_id": "claude-sonnet-5.5", "card_id": "claude-sonnet-5.5", "p_success": 0.6227, "p_success_lower": 0.5427,
"p_source": "success_head", "est_cost_usd": 0.018252, "expected_cost_usd": 0.027815, "est_latency_ms": 21146.7},
{"model_id": "claude-haiku-5.5", "card_id": "claude-haiku-5.5", "p_success": 0.5042, "p_success_lower": 0.4565,
"p_source": "success_head", "est_cost_usd": 0.000913, "expected_cost_usd": 0.021702, "est_latency_ms": 11923.1}
],
"difficulty": {"level": 5, "expected": 4.89, "decision_level": 5.382, "vagueness": 0.0},
"category": {"label": "implementation", "p": 0.7906},
"escalation_ladder": [
{"model_id": "claude-haiku-5.5", "p_success": 0.5042, "p_success_lower": 0.4565, "est_cost_usd": 0.000913},
{"model_id": "claude-sonnet-5.5", "p_success": 0.6227, "p_success_lower": 0.5427, "est_cost_usd": 0.018252},
{"model_id": "codex-gpt-6-luna", "p_success": 0.3093, "p_success_lower": 0.2727, "est_cost_usd": 0.000913}
],
"escalation_ladder_note": "try in order, escalate on failure; independent-failure estimate of success within 2 attempts >= 0.75",
"router": {"policy": "v4", "success_head": "success_head_v4(panda-router-v4)", "latency_ms": 10.228},
"trace_id": "r_dc1daf912043483d80cdd510"
}p_success is a calibrated, strict-grading pass rate, and decisions use p_success_lower. The cheapest model whose
lower bound clears min_p_success (0.5) is claude-sonnet-5.5; haiku is cheaper but its bound is 0.46. If you verify
the result and it fails, POST /escalate returns the next model on the ladder. Report each attempt with
POST /outcome. Details: docs/API.md.
Getting the best results
A single pick scores 74-82 per 100 tasks; a verified retry scores 89-92. Full guide: docs/BEST_RESULTS.md.
Close the loop. Route, run
escalation_ladder[0], verify (tests, lint, a reviewer or a cheap LLM check), on a failurePOST /escalate, and stop after 2 retries.Pick the mode for your risk.
max_utility(default);max_qualitywhen a failure is expensive and you cannot verify;cheapest_above_thresholdfor bulk easy work.Keep
min_p_successnear 0.5. Calibrated P rarely exceeds about 0.65, so 0.75 usually falls back to the safest model (decided_byends:relaxed).Pass only models you can run. The default pool is all 65 cards, including OpenRouter and Ollama ones you may not have.
Give context and write real tasks.
repo_languages,files_in_scope,estimated_input_tokens,has_images,requires_tools; scope and acceptance criteria. Vague requests are rated harder on purpose.Always send
/outcome, failures too, with cost and latency; it is the data any later refit needs.Cap spend with
max_cost_usd,local_onlyandexclude, and readest_cost_usd.
Results
Real routed success (v4.2)
150 held-out real tasks, each actually attempted by nine models (claude-haiku/sonnet/opus-5.5, codex-gpt-6-luna, gpt-6.1-sol, gemini-3.8-flash, deepseek-v4.1-flash, minimax-m3.1-flash, qwen3.8-flash) and graded pass/fail by an LLM judge (DeepSeek, then GPT-5.6-Terra; agreement with a Kimi K3.1 Pro reference kappa 0.70-0.85). Nothing was tuned on these tasks. Reports: eval_reports/v4/REPORT.md, data/outcomes/REPORT_v4_attempts.md.
strategy | success / 100 | $ / 100 tasks |
v4.2, single pick, | 77.3 | 0.99 |
v4.2, single pick, | 82.0 | 1.20 |
v4.2, single pick, | 74.0 | 0.74 |
v4, follow | 88.7 [83.3, 93.3] | 0.88 |
v4, escalate from | 90.7 | 1.68 |
v4.2, up to 3 attempts | 92.0 | 1.23 |
always best single model (gpt-6.1-sol) | 79.3 [72.7, 85.3] | 1.11 |
always strongest-priced (claude-opus-5.5) | 76.7 | 4.03 |
oracle (cheapest model that passed) | 94.0 | 0.56 |
Costs are estimates from card prices and logged token counts. Single-pick 95% intervals are about +-7 points, so
max_utility vs always-sol is within noise; max_quality (82.0 [75.3, 88.0]) is the best single pick.
85+ needs one retry. Following the response's
escalation_ladder(cheap-but-safe first, stronger next) when your orchestrator can tell a failure (tests, review, a verifier) gets 88.7/100 for less than always-sol. In this simulation the judge's label was the failure signal. How to build the loop: docs/BEST_RESULTS.md.The three modes differ.
max_qualityis the safest single pick,cheapest_above_thresholdtrades about 3 points for 25% lower cost,max_utilitysits between.$0 models no longer win by default. Expected cost includes the cost of failing and retrying; free and weak-evidence cards get a conservative prior. $0 picks on the full pool in cheapest mode: 88% (v3) -> 0%.
Errs on the safe side. Decisions use
p_success_lower(a lower confidence bound); the profiler is trained to over- rather than under-estimate difficulty. Under-powered picks fell from 27% (v3) to 14% (max_quality: 9%).p_successis an honest, strict-grading pass rate (calibrated per model on train/val, ECE 0.015). It looks low for trivial questions (~0.5) because the outcome data has few trivial, well-specified tasks (known limitation).Vague requests ("a model trainer") are rated ~5 instead of 1.5 and go to a paid model.
Profiler quality (v1-v3 history; v4 = v3 data + Modal-trained 150M teacher, distilled 32M, vague-task fine-tune)
Evaluated on 359 real tasks (the gold set) that were never trained on, labelled by Codex + DeepSeek V4.1 Flash. Full tables: eval_reports/compare_v3.md; release notes: RESULTS.md (v4 first).
profiler | gold category acc | gold difficulty MAE / rho | gold flags AUROC | attempt-IRT rho | SWE held-out rho | hard-task pass |
v1 | 0.624 | 0.900 / 0.675 | 0.885 | 0.178 | 0.025 | 0.80 |
v2 | 0.641 | 0.897 / 0.705 | 0.886 | 0.115 | 0.119 | 0.85 |
v3 | 0.688 | 0.825 / 0.747 | 0.901 | 0.212 | 0.081 | 0.85 |
v4 keeps the 32M architecture and trades some difficulty rank correlation for a deliberate over-estimate: on gold, the v4 candidates' difficulty bias moved from -0.14 (v3) to +0.05..+0.12 and gold rho to 0.71-0.73 (v3: 0.747); hard-task pass 0.85 -> 0.90-0.95 (eval_reports/v4_profiler/REPORT.md; the shipped weights are a WiSE 0.7/0.3 blend of the fine-tune and the soup and were not re-tabulated there).
v3 was a direct Ettin-32M trained on 8,247 tasks (every row labelled by at least two teachers, DeepSeek V4.1 Flash on all of them) with real-outcome difficulty from SWE-bench and from the attempt-and-grade runs as an auxiliary target (weight 0.3). 31 MB int8.
attempt-IRT rho: rank correlation between predicted difficulty and difficulty fitted from the real attempts above. SWE held-out rho: the same against SWE-bench item difficulty on repos never trained on; v3 is lower here than v2 (0.08 vs 0.12, both weak).
Latency: v1-v4 share one 32M architecture; on an idle host the profiler runs at about 10 ms p50 / 19 ms p95 (batch 1, CPU, int8).
Model cards
Each routable model is one JSON file in cards/, validated by
schemas/model_card.schema.json. To add a model, copy the closest card, set
id (same as the file name), provider, model, cost, limits, skills and latency, and run
pytest tests/test_matcher.py. The router reloads changed cards without a restart.
Aliases:
poolentries may be card ids, the card'smodelstring (gpt-oss:20b,deepseek/deepseek-v4-flash), or a loose spelling (claude/sonnet-5-5). The response echoes your string asmodel_idand setscard_id. Ambiguous or unknown names come back infiltered_outasunknown_model.Supersedes: a card can list older versions in
supersedes. The older one is dropped only if the newer one costs the same or less for the task.Free OpenRouter tiers live in
cards/optional/and are not in the default pool.
Full guide: cards/README.md (also docs/CARDS.md).
Repo layout
panda_router/ serve/ (Router, HTTP server, CLI), mcp/ (stdio MCP server), matcher/, router_v4/ (success head,
policy, ladder), model/ (net, ONNX profiler), train/, datagen/, outcomes/, eval/, heuristic.py
cards/ one JSON per model (+ optional/ for free tiers)
schemas/ JSON Schemas for requests, responses, outcomes, cards; CONTRACTS.md; taxonomy.json
scripts/ datagen/, train/, eval/, outcomes/ (success head, card fits), modal/ (GPU training) entry points
data/ training data, gold set, outcome fits (STATS.md, gold/README.md, outcomes/REPORT.md)
eval_reports/ comparison tables and per-model reports
docs/ API.md, BEST_RESULTS.md, INTEGRATIONS.md, CARDS.md
tests/ pytest suite
RESULTS.md v4 release notes (then v3, v2)
PLAN.md design planTraining and reproduction
Install the [train] extra, then follow panda_router/train/README.md (teacher,
distillation, soup, calibration, ONNX export, latency bench, outcome anchors, the v4 Modal jobs and the success head).
Data construction and statistics: data/STATS.md; gold set: data/gold/README.md;
outcome calibration: data/outcomes/REPORT.md. Run the tests with pip install -e ".[dev]"
and pytest.
Data, licences and attribution
Code and the released model weights are MIT (LICENSE). Training data, evaluation data and base model:
source | used for | licence |
SWE-rebench (Nebius) | task text ( | CC-BY-4.0 |
task text | MIT | |
WildChat-1M (AI2) | first user turns of English chats | ODC-BY |
SWE-bench (and Verified, Lite, Multilingual) | issue text for outcome-difficulty tasks | MIT |
per-instance resolved lists, used as facts for the IRT fit; raw files are not redistributed | no licence file | |
Ettin encoders (JHU CLSP) | backbone | MIT |
Teacher labels were produced by LLMs (Codex, DeepSeek V4.1 Flash and others; see data/STATS.md), so they carry those models' biases. Repo code inside SWE-rebench keeps its own licence. More detail per source: data/gold/README.md and data/outcomes/REPORT.md.
This server cannot be deployed
Maintenance
Related MCP Connectors
A paid remote MCP for OpenAI Codex agent coordination MCP, built to return verdicts, receipts, usage
Chat, image, video, and audio models from many vendors behind one remote MCP server and one key.
Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.
LLM cost optimization gateway, repo token-waste auditor & model arbitrage MCP server.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables AI tools to uniformly discover, inspect, and call tools, prompts, and resources from multiple upstream MCP servers through a small set of fixed MCP tools, over stdio or HTTP.2MIT
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to access hosted models and services via a local stdio bridge, with live model discovery, pricing, balance checks, and paid execution requiring cost estimates.MIT
- AlicenseNot gradedqualityBmaintenanceEnables coding agents to make small, bounded decisions around tasks via stdio MCP, supporting source-bound context, durable budgets, bulk jobs, and measured outcomes while leaving planning and reasoning with the main model.MIT
- AlicenseNot gradedqualityAmaintenanceEnables MCP-speaking hosts to ask typed questions (yes/no, choice, score) and receive calibrated probabilities instead of prose, over a stdio transport. Runs offline by default with an explicitly disclosed, opt-in egress contract for live providers.66 npmApache 2.0