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": "deepseek-v4-flash", "name": "deepseek-v4-flash", "url": "https://ellm.nrp-nautilus.io/v1/chat/completions", "toolCalling": true, "vision": true, "maxInputTokens": 1048576, "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: deepseek-v4-flash name: deepseek-v4-flash reasoning: true supportsTools: true input: [text, image] contextWindow: 1048576 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, whose providers guide covers the fields below.
Run /connect, pick nrp, and paste your token — or hand it to the background server with opencode service set env NRP_API_KEY <token>. /models then lists the nrp models, and Ctrl+T cycles a model’s variants. Keep the provider ID and its "name" lowercase: /connect accepts a mixed-case ID, but /models does not list its models.
~/.config/opencode/opencode.jsonc qwen3 as the default model
"model" takes a provider/model id, so the default is nrp/qwen3. agents.title.model is the model OpenCode names sessions with — qwen3-small keeps that off the largest GPUs.
{ "$schema": "https://opencode.ai/config.json", "model": "nrp/qwen3", "agents": { "title": { "model": "nrp/qwen3-small" } }, "providers": { "nrp": { "name": "nrp", "env": ["NRP_API_KEY"], "package": "@opencode/ai/providers/openai-compatible", "settings": { "baseURL": "https://ellm.nrp-nautilus.io/v1" }, "models": { "qwen3": { "name": "qwen3", "capabilities": { "tools": true, "input": ["text", "image", "video"], "output": ["text"] }, "limit": { "context": 1000000, "output": 65536 } }, "qwen3-small": { "name": "qwen3-small", "capabilities": { "tools": true, "input": ["text", "image", "video"], "output": ["text"] }, "limit": { "context": 1000000, "output": 65536 } } } } }}"limit.output" caps a single response, not the context window. Never set it close to or above "context".
~/.config/opencode/opencode.jsonc most of the catalog
Nine models, each with its context window, input types, 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+T, or with #variant on a model id such as nrp/qwen3#low; each model’s thinking parameters are on its model card. Without a variant, the server-side default stays in place.
{ "$schema": "https://opencode.ai/config.json", "model": "nrp/qwen3", "agents": { "title": { "model": "nrp/qwen3-small" } }, "providers": { "nrp": { "name": "nrp", "env": ["NRP_API_KEY"], "package": "@opencode/ai/providers/openai-compatible", "settings": { "baseURL": "https://ellm.nrp-nautilus.io/v1" }, "models": { "qwen3": { "name": "qwen3", "capabilities": { "tools": true, "input": ["text", "image", "video"], "output": ["text"] }, "limit": { "context": 1000000, "output": 65536 }, "variants": [ { "id": "low", "body": { "reasoning_effort": "low" } }, { "id": "medium", "body": { "reasoning_effort": "medium" } }, { "id": "instruct", "body": { "chat_template_kwargs": { "enable_thinking": false } } } ] }, "qwen3-small": { "name": "qwen3-small", "capabilities": { "tools": true, "input": ["text", "image", "video"], "output": ["text"] }, "limit": { "context": 1000000, "output": 65536 }, "variants": [ { "id": "low", "body": { "reasoning_effort": "low" } }, { "id": "medium", "body": { "reasoning_effort": "medium" } }, { "id": "instruct", "body": { "chat_template_kwargs": { "enable_thinking": false } } } ] }, "glm-5": { "name": "glm-5", "capabilities": { "tools": true, "input": ["text"], "output": ["text"] }, "limit": { "context": 1048576, "output": 65536 }, "variants": [ { "id": "low", "body": { "chat_template_kwargs": { "reasoning_effort": "low" } } }, { "id": "high", "body": { "chat_template_kwargs": { "reasoning_effort": "high" } } } ] }, "deepseek-v4-flash": { "name": "deepseek-v4-flash", "capabilities": { "tools": true, "input": ["text", "image"], "output": ["text"] }, "limit": { "context": 1048576, "output": 65536 }, "variants": [ { "id": "low", "body": { "chat_template_kwargs": { "reasoning_effort": "low" } } }, { "id": "high", "body": { "chat_template_kwargs": { "reasoning_effort": "high" } } }, { "id": "instruct", "body": { "chat_template_kwargs": { "thinking": false } } } ] }, "minimax": { "name": "minimax", "capabilities": { "tools": true, "input": ["text", "image", "video"], "output": ["text"] }, "limit": { "context": 1048576, "output": 32768 } }, "gpt-oss": { "name": "gpt-oss", "capabilities": { "tools": true, "input": ["text"], "output": ["text"] }, "limit": { "context": 131072, "output": 32768 } }, "gemma": { "name": "gemma", "capabilities": { "tools": true, "input": ["text", "image", "video"], "output": ["text"] }, "limit": { "context": 262144, "output": 32768 }, "variants": [ { "id": "instruct", "body": { "chat_template_kwargs": { "enable_thinking": false } } } ] }, "gemma-small": { "name": "gemma-small", "capabilities": { "tools": true, "input": ["text", "image", "video", "audio"], "output": ["text"] }, "limit": { "context": 262144, "output": 32768 }, "variants": [ { "id": "instruct", "body": { "chat_template_kwargs": { "enable_thinking": false } } } ] } } } }}To pin fields that should go with every request — cache_salt, how much earlier reasoning to keep, or a fixed effort — add a "body" block, on the provider for every model or on a model alongside "name". A selected variant’s "body" is merged over the model’s, and the model’s over the provider’s:
"deepseek-v4-flash": { "name": "deepseek-v4-flash", "body": { "chat_template_kwargs": { "thinking": true, "drop_thinking": false } }, // ... },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": "deepseek-v4-flash", "name": "deepseek-v4-flash", "context_window": 1048576, "default_max_tokens": 65536, "modalities": { "input": ["text", "image"], "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, "drop_thinking": false } },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": "deepseek-v4-flash", "name": "deepseek-v4-flash", "input": ["text", "image"], "contextWindow": 1048576, "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 = "deepseek-v4-flash"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.deepseek-v4-flash]provider = "nrp"model = "deepseek-v4-flash"max_context_size = 1048576capabilities = ["thinking", "image_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.