A single-page dashboard for browsing and comparing models available on the NousResearch Inference API.
Live demo: https://ftzahao.github.io/NousResearchModelsPanel/
- Model Browser — Filterable/searchable cards with pricing, context length, modalities, and benchmarks
- Multi-select Filters — Pick multiple providers and modalities at once, plus reasoning-model and free-model toggles
- Analytics Charts — Price comparison, intelligence vs coding scatter plot, context distribution, provider pie chart
- Model Selection — Select visible models, append to the current selection, or clear it, with a modal listing the current picks
- Config Export — Preview and download the selection as any of the supported tool config formats (see below)
- Currency Toggle — Display prices in CNY or USD, with a live exchange rate (open.er-api.com) or a custom rate
- Bilingual — Chinese/English i18n toggle
- Dark/Light Theme — System-aware theme switching
- Responsive — Mobile-friendly layout
- Auto-refresh — Fetches latest data from the NousResearch API on every load
Select models, then choose a format in the export menu. Each format targets one tool's config schema and can be previewed before download:
| Format | Output file | Target |
|---|---|---|
| Codex setup | config.toml + models.json |
Codex CLI provider config + model catalog (verified against CLI 0.154.0) |
| Codex via Osaurus proxy | config.toml + models.json |
Codex CLI routed through a local Osaurus proxy (provider named nous, models addressed as nous/<model-id>) |
GitHub Copilot gcmp.compatibleModels |
gcmp-compatible-models.json |
Copilot GCMP-compatible model entries |
GitHub Copilot chatLanguageModels.json |
chatLanguageModels.json |
Copilot custom-endpoint provider (customendpoint / chat-completions) |
ZCode provider_config.json provider |
zcode-provider-config.json |
ZCode personal provider entry (schemaVersion: 1, open-sourced client) |
DeepSeek Harness settings.yaml provider |
dsh-llm-pi-ai.yaml |
DeepSeek Harness llm-pi-ai provider (YAML) |
| DeepSeek Harness desktop patch | dsh-desktop-cordis-patch.yml |
DeepSeek Harness desktop profile cordis.patch.yml (llm-pi-ai entry) |
LiteLLM config.yaml |
litellm-config.yaml |
LiteLLM proxy model_list entries for an OpenAI-compatible upstream |
CLIProxyAPI config.yaml |
cliproxyapi-config.yaml |
CLIProxyAPI openai-compatibility provider fragment |
OpenCode opencode.json |
opencode.json |
OpenCode v2 providers.nous entry (aisdk:@ai-sdk/openai-compatible) |
Crush crush.json |
crush.json |
Crush provider (type: openai) |
| Chatbox provider import | chatbox-nous-provider.json |
Chatbox one-click provider import JSON |
| Cherry Studio provider | cherry-studio-nous.json |
Cherry Studio data.providers.nous entry |
Zed language_models settings |
zed-language-models.json |
Zed language_models.openai_compatible fragment |
Xiaomi MiMo Desktop mimocode.jsonc |
mimocode.jsonc |
MiMo Desktop provider (@ai-sdk/openai-compatible) |
All conversion logic lives in src/model-export/. Every provider-scoped export writes a fixed provider id (nous) so re-importing replaces the same entry instead of duplicating it. Codex, LiteLLM, OpenCode, Crush, DeepSeek Harness (both variants), Zed and MiMo Desktop read the key from the NOUS_API_KEY environment variable — the desktop patch resolves it inside Harness, so put it in ~/.dsh/.env or in the app's Settings → Models page; Chatbox, Cherry Studio, ZCode and CLIProxyAPI ship a placeholder you replace after import. The Codex/Osaurus variant reads no key at all — Codex talks to the loopback server and Osaurus holds the Nous key in the macOS Keychain.
After downloading the export files, a single command merges them into each tool's target config — a .bak backup is written first and only the relevant fragment is rewritten, so the rest of the target file (your comments included) stays byte-for-byte identical:
bun run merge # scan ~/Downloads for export files and merge them all
bun run merge ~/Downloads/opencode.json # merge specific files (directories work too)
bun run merge -- --dry-run # preview the merge without writing
bun run merge -- --list # list supported formats and their default targets
bun run merge -- --api-key <your-key> # replace placeholders in the export with a real key
bun run merge -p codex=<model-id>,<model-id> -p opencode=<model-id> # generate and merge straight from model IDs, no download-p <program>=<model-id>[,<model-id>...] fetches the model list from the Nous API, builds each program's config from the given IDs and merges it like a downloaded file. It can be repeated to configure several programs in one run. Run --list to see the program names. Deno needs --allow-net for this option. --one is an alias of -p tailored for the dashboard's "one command" export: copy that command from the export preview and paste it into a terminal to generate and merge without downloading any files first.
For example, to set up OpenCode and Crush with Gemini 4 Argon:
$ bun run merge -p opencode=google/gemini-4-argon -p crush=google/gemini-4-argon --lang en
+ opencode.json → Created ~/.config/opencode/opencode.json
+ crush.json → Created ~/.config/crush/crush.json
Done: 0 merged · 2 created · 0 unchanged · 0 skipped · 0 failedThe merge implementation is a standalone TypeScript file, so Deno can execute it directly from GitHub without cloning the repository:
deno run --no-lock --reload=<merge.ts URL> --allow-read --allow-write --allow-env --allow-net \
https://raw.githubusercontent.com/ftzahao/NousResearchModelsPanel/main/scripts/merge.ts \
~/DownloadsDeno needs read, write and environment permissions to inspect and update local configs (--allow-net fetches the model list for -p/--one). --reload=<URL> busts Deno's module cache for this script only, so a changed merge.ts on main is always picked up — the pinned YAML/TOML parser modules keep their cache. Its first run downloads those parser modules.
Files are detected by content (the file name is only a fallback, and duplicate-download suffixes like config (1).toml are stripped); a Codex config.toml automatically picks up a sibling models.json and points model_catalog_json at its absolute path; re-running a merge that changes nothing reports "unchanged" without touching the file. Every spliced result is re-parsed and deep-compared against the expected merge before anything is written.
Bun + React 19 + Recharts + Tailwind CSS v4 (compiled locally via bun-plugin-tailwind) + Lucide Icons + BigNumber.js + YAML + smol-toml
index.ts— Bun server (port 8092, hot reload) with a cached/api/modelsproxy for the upstream APIindex.html— HTML entry: Tailwind stylesheet link, theme CSS variables, responsive overridessrc/root.tsx— React mount pointsrc/app.tsx— MainAppcomponent: state, filtering/sorting, selection, exporter registrysrc/components/—Header,StatsGrid/StatCard,FilterBar,ModelCard,ExportToolbar,ExportPreviewModal,SelectedModelsModal,Footer,charts.tsxsrc/hooks/—useModels.ts(model fetching),useCurrency.ts(currency + exchange rate state)src/model-export.ts— Model selection → each export formatsrc/model-export.test.ts— Tests for the export builders (bun test)scripts/merge.ts— Standalone Bun/Deno merge CLI and text-splicing implementationsrc/contexts.tsx,src/i18n.ts,src/types.ts,src/utils.ts— Theme/currency contexts, translations, shared types, helpersbuild.sh— Static build script (bundles the frontend intodocs/)
bun install
bun run devOpens at http://localhost:8092 with hot reload.
bun test
bun run typecheck
deno check --no-lock scripts/merge.tsbun run buildRuns build.sh, which bundles index.html, src/root.tsx, and the Tailwind CSS into static assets in docs/ via build.ts (Bun.build + bun-plugin-tailwind). The docs/ output is gitignored and built in CI, not committed.
The project includes a GitHub Actions workflow (.github/workflows/deploy.yml) that automatically builds and deploys on every push to main.
- Go to Settings → Pages in your GitHub repo
- Set Source to GitHub Actions
- Push to
main— deployment starts automatically