Client Configurations
Pre-built configurations for popular coding CLIs. Every config here assumes:
- Endpoint:
https://ellm.nrp-nautilus.io/v1, Anthropic-compatible at/anthropic - Token: the value from the LLM token page, passed in
Authorization: Bearer …or whatever the client’s API-key field expects
API Access covers getting a token, and cache_salt for tenants whose prompts should not be cached across users.
VS Code
VS Code reaches NRP models through Chat: Manage Language Models, which adds them to the Copilot Chat model picker.
- Command Palette (
Ctrl+Shift+P/Cmd+Shift+P) → Chat: Manage Language Models - Add Models → Custom Endpoint
- Endpoint URL:
https://ellm.nrp-nautilus.io/v1/chat/completions
The apiKey below uses VS Code’s ${input:...} substitution, so VS Code asks for your token the first time you use a model and stores it securely from then on.
Paste into the Add Models prompt 3 models
{ "name": "NRP", "vendor": "customendpoint", "apiKey": "${input:chat.lm.secret.2630e22e}", "apiType": "chat-completions", "models": [ { "id": "glm-5", "name": "glm-5", "url": "https://ellm.nrp-nautilus.io/v1/chat/completions", "toolCalling": true, "vision": false, "maxInputTokens": 1048576, "maxOutputTokens": 100000 }, { "id": "qwen3", "name": "qwen3", "url": "https://ellm.nrp-nautilus.io/v1/chat/completions", "toolCalling": true, "vision": true, "maxInputTokens": 1000000, "maxOutputTokens": 100000 }, { "id": "kimi", "name": "kimi", "url": "https://ellm.nrp-nautilus.io/v1/chat/completions", "toolCalling": true, "vision": true, "maxInputTokens": 131072, "maxOutputTokens": 100000 } ]}omp
https://omp.sh (oh-my-pi), whose custom-model reference covers the fields below.
~/.omp/agent/models.yml 2 models
providers: nrp: baseUrl: https://ellm.nrp-nautilus.io/v1 api: openai-completions apiKey: <YOUR_API_KEY> models: - id: kimi name: kimi reasoning: true supportsTools: true input: [text, image] contextWindow: 131072 omitMaxOutputTokens: true - id: qwen3-small name: qwen3-small reasoning: true thinking: mode: effort efforts: [low, medium, xhigh] defaultLevel: xhigh supportsTools: true input: [text, image] contextWindow: 1000000 omitMaxOutputTokens: trueOpenCode
https://github.com/anomalyco/opencode
Ctrl+P → Switch models finds NRP; Switch model variant picks a thinking level. Either set OPENAI_API_KEY or replace {env:OPENAI_API_KEY} with the key itself.
~/.config/opencode/opencode.jsonc qwen3 as the default model
"model" takes a provider/model id, so the default is NRP/qwen3. "small_model" is what OpenCode uses for side tasks such as session titles — qwen3-small keeps those off the largest GPUs. An editor validating against opencode.ai/config.json underlines both values, because the schema autocompletes from the models.dev catalog and cannot know about a custom provider; OpenCode resolves them from the provider block.
{ "$schema": "https://opencode.ai/config.json", "model": "NRP/qwen3", "small_model": "NRP/qwen3-small", "provider": { "NRP": { "npm": "@ai-sdk/openai-compatible", "name": "NRP", "options": { "baseURL": "https://ellm.nrp-nautilus.io/v1", "apiKey": "{env:OPENAI_API_KEY}" }, "models": { "qwen3": { "name": "qwen3", "limit": { "context": 1000000, "output": 65536 }, "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, "tool_call": true, "reasoning": true, "attachment": true }, "qwen3-small": { "name": "qwen3-small", "limit": { "context": 1000000, "output": 65536 }, "tool_call": true, "reasoning": true } } } }}"limit.output" caps a single response, not the context window. Never set it close to or above "context".
~/.config/opencode/opencode.jsonc every model in the catalog
Nine models, each with its context window, modalities, and thinking controls. qwen3-embedding is an embedding model rather than a chat model, so it is not listed.
Thinking is selected per model with Ctrl+P → Switch model variant, and the key differs by model: qwen3 and qwen3-small take a top-level reasoning_effort (low, medium, or xhigh, the default) and turn thinking off through chat_template_kwargs.enable_thinking; glm-5 and deepseek-v4-flash take reasoning_effort inside chat_template_kwargs (low, high, or max, the default), and only deepseek-v4-flash can turn thinking off, with thinking: false. Staying on a model’s default variant leaves the server-side default in place. gemma-small is served without a reasoning parser, so its thinking arrives inline in the answer rather than as a separate reasoning block.
{ "$schema": "https://opencode.ai/config.json", "model": "NRP/qwen3", "small_model": "NRP/qwen3-small", "provider": { "NRP": { "npm": "@ai-sdk/openai-compatible", "name": "NRP", "options": { "baseURL": "https://ellm.nrp-nautilus.io/v1", "apiKey": "{env:OPENAI_API_KEY}" }, "models": { "qwen3": { "name": "qwen3", "limit": { "context": 1000000, "output": 65536 }, "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, "tool_call": true, "reasoning": true, "attachment": true, "variants": { "low": { "reasoning_effort": "low" }, "medium": { "reasoning_effort": "medium" }, "instruct": { "chat_template_kwargs": { "enable_thinking": false } } } }, "qwen3-small": { "name": "qwen3-small", "limit": { "context": 1000000, "output": 65536 }, "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, "tool_call": true, "reasoning": true, "attachment": true, "variants": { "low": { "reasoning_effort": "low" }, "medium": { "reasoning_effort": "medium" }, "instruct": { "chat_template_kwargs": { "enable_thinking": false } } } }, "glm-5": { "name": "glm-5", "limit": { "context": 1048576, "output": 65536 }, "modalities": { "input": ["text"], "output": ["text"] }, "tool_call": true, "reasoning": true, "variants": { "low": { "chat_template_kwargs": { "reasoning_effort": "low" } }, "high": { "chat_template_kwargs": { "reasoning_effort": "high" } } } }, "deepseek-v4-flash": { "name": "deepseek-v4-flash", "limit": { "context": 1048576, "output": 65536 }, "modalities": { "input": ["text", "image"], "output": ["text"] }, "tool_call": true, "reasoning": true, "attachment": true, "variants": { "low": { "chat_template_kwargs": { "reasoning_effort": "low" } }, "high": { "chat_template_kwargs": { "reasoning_effort": "high" } }, "instruct": { "chat_template_kwargs": { "thinking": false } } } }, "kimi": { "name": "kimi", "limit": { "context": 131072, "output": 32768 }, "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, "tool_call": true, "reasoning": true, "attachment": true }, "minimax-m2": { "name": "minimax-m2", "limit": { "context": 204800, "output": 32768 }, "modalities": { "input": ["text"], "output": ["text"] }, "tool_call": true, "reasoning": true }, "gpt-oss": { "name": "gpt-oss", "limit": { "context": 131072, "output": 32768 }, "modalities": { "input": ["text"], "output": ["text"] }, "tool_call": true, "reasoning": true }, "gemma": { "name": "gemma", "limit": { "context": 262144, "output": 32768 }, "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, "tool_call": true, "reasoning": true, "attachment": true, "variants": { "instruct": { "chat_template_kwargs": { "enable_thinking": false } } } }, "gemma-small": { "name": "gemma-small", "limit": { "context": 262144, "output": 32768 }, "modalities": { "input": ["text", "image", "video"], "output": ["text"] }, "tool_call": true, "reasoning": true, "attachment": true, "variants": { "instruct": { "chat_template_kwargs": { "enable_thinking": false } } } } } } }}To pin options that should apply on every request to a model — cache_salt, preserve_thinking, or a fixed effort — add an "options" block alongside "name". Anything in "options" is sent with each request; anything in "variants" only while that variant is selected:
"deepseek-v4-flash": { "name": "deepseek-v4-flash", "options": { "chat_template_kwargs": { "thinking": true, "preserve_thinking": true } }, // ... },Crush
https://github.com/charmbracelet/crush
Search for NRP in the model list once the config is in place. See also Andrea Zonca’s writeup, Configure NRP LLM with OpenCode and Crush.
~/.config/crush/crush.json 1 model — repeat the block per model
Adjust "default_max_tokens" as needed; never push it close to or above "context_window". Use "enable_thinking" or "thinking" as the model requires.
{ "$schema": "https://charm.land/crush.json", "options": { "disable_metrics": true, "disable_provider_auto_update": false, "debug": false, "debug_lsp": false, "attribution": { "trailer_style": "none", "generated_with": false } }, "mcp": {}, "providers": { "nrp": { "name": "NRP", "type": "openai-compat", "base_url": "https://ellm.nrp-nautilus.io/v1", "api_key": "<LLM_API_KEY>", "models": [ { "id": "kimi", "name": "kimi", "context_window": 131072, "default_max_tokens": 32768, "modalities": { "input": ["text", "image", "video"], "output": ["text"] } } ] } }}For "chat_template_kwargs" or other "extra_body" parameters, add this within each model, at the same level as "models":
"extra_body": { "chat_template_kwargs": { "thinking": true, "preserve_thinking": true } },pi
Ctrl-L switches models — search for NRP, or type /model modelname.
~/.pi/agent/models.json 2 models
apiKey accepts the literal key, an environment variable name (OPENAI_API_KEY), or a shell command (!decrypt_key NRP).
{ "providers": { "nrp": { "baseUrl": "https://ellm.nrp-nautilus.io/v1", "api": "openai-completions", "apiKey": "<YOUR_API_KEY>", "models": [ { "id": "kimi", "name": "kimi", "input": ["text", "image"], "contextWindow": 131072, "reasoning": true }, { "id": "qwen3-small", "name": "qwen3-small", "input": ["text", "image"], "contextWindow": 1000000, "reasoning": true, "compat": { "thinkingFormat": "qwen-chat-template", "supportsDeveloperRole": false } } ] } }}Kimi CLI
https://github.com/MoonshotAI/kimi-cli
~/.kimi/config.toml 1 model
default_model = "kimi"default_thinking = truedefault_yolo = falsedefault_plan_mode = falseshow_thinking_stream = truemerge_all_available_skills = truetelemetry = false
[providers.nrp]type = "openai_legacy"base_url = "https://ellm.nrp-nautilus.io/v1"api_key = "<YOUR_API_KEY>"
[models.kimi]provider = "nrp"model = "kimi"max_context_size = 131072capabilities = ["thinking", "image_in", "video_in"]
[background]max_running_tasks = 4keep_alive_on_exit = falseagent_task_timeout_s = 3600Claude Code
https://github.com/anthropics/claude-code
Claude Code talks to NRP through the Anthropic-compatible endpoint at /anthropic.
~/.claude/settings.json any model, by name
{ "env": { "ANTHROPIC_BASE_URL": "https://ellm.nrp-nautilus.io/anthropic", "ANTHROPIC_AUTH_TOKEN": "<llm-token>", "ANTHROPIC_MODEL": "<name-of-nrp-model>", "ANTHROPIC_DEFAULT_OPUS_MODEL": "<name-of-nrp-model>", "ANTHROPIC_DEFAULT_SONNET_MODEL": "<name-of-nrp-model>", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "<name-of-nrp-model>", "ANTHROPIC_DEFAULT_FABLE_MODEL": "<name-of-nrp-model>", "CLAUDE_CODE_SUBAGENT_MODEL": "<name-of-nrp-model>", "ENABLE_TOOL_SEARCH": "false", "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "<context-size-of-model>", "CLAUDE_CODE_EFFORT_LEVEL": "max", "CLAUDE_STREAM_IDLE_TIMEOUT_MS": "3000000", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", "CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY": "1", "CLAUDE_CODE_ENABLE_TELEMETRY": "0", "DISABLE_TELEMETRY": "1", "API_TIMEOUT_MS": "3000000", "CLAUDE_CODE_MAX_RETRIES": "10" }}Copilot CLI
https://github.com/github/copilot-cli
Environment variables any model, by name
Set COPILOT_PROVIDER_MAX_PROMPT_TOKENS to the model’s context length and COPILOT_PROVIDER_MAX_OUTPUT_TOKENS to a smaller value — roughly 1/16 to 1/4 of the context, depending on the task.
COPILOT_PROVIDER_BASE_URL="https://ellm.nrp-nautilus.io/v1"COPILOT_PROVIDER_KEY="<llm-token>"COPILOT_MODEL="<name-of-nrp-model>"COPILOT_PROVIDER_MAX_PROMPT_TOKENS="<context-length>"COPILOT_PROVIDER_MAX_OUTPUT_TOKENS="<max-output>"
This work was supported in part by National Science Foundation (NSF) awards CNS-1730158, ACI-1540112, ACI-1541349, OAC-1826967, OAC-2112167, CNS-2100237, CNS-2120019.