Skill

Register custom LLM variants in Pi agent configuration

Registers an unrecognized OpenRouter model slug (like a :nitro variant) as a custom Pi model so it stops silently falling back.

Works with openrouteranthropic

91
Spark score
out of 100
Updated 15 days ago
Version 1.0.0

Add to Favorites

Why it matters

Ensure Pi agent correctly loads and persists custom or variant model slugs (like OpenRouter routing shortcuts :nitro, :floor, :exacto) by registering them in the local model registry, preventing silent fallback to bundled defaults.

Outcomes

What it gets done

01

Add custom model metadata to ~/.pi/agent/models.json under the correct provider

02

Set defaultProvider and defaultModel in settings.json to match the registered slug exactly

03

Verify provider authentication exists in auth.json or environment variables

04

Confirm the model appears in --list-models and test with a smoke-test query

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/ag-pi-custom-model | bash

Overview

Pi custom / variant model

Registers an OpenRouter routing-shortcut variant or new model slug as a custom Pi model in models.json, fixing the silent fallback to Pi's built-in default when the slug isn't in the bundled registry. Use it whenever Pi appears to have reset your chosen model with no error shown. Confirm the slug and provider auth are real before registering it.

What it does

Fixes a Pi agent bug where a saved default model silently falls back to the built-in per-provider default (for OpenRouter, moonshotai/kimi-k2.6) instead of loading the intended one - because Pi's saved default only loads if the exact provider/id exists in its model registry, and Pi ships a static bundled list per provider that does not include OpenRouter routing-shortcut variants (:nitro for throughput, :floor for cheapest, :exacto for quality tool-use) or any brand-new model slug. The fix is registering the slug as a custom model so find(provider, id) actually matches it.

When to use - and when NOT to

The symptom to watch for is a model that appears to have reset itself with zero warning text anywhere - that silence is the diagnostic tell, since Pi never prints an error for this class of failure, it just quietly shows something else in the footer. Before registering anything, confirm two things first: that the model or variant id is spelled and typed correctly (a typo'd id fails exactly the same silent way as a genuinely missing one), and that the provider actually has a working auth key configured, since a model can be fully registered and still fall back if its provider has no credentials at all.

Inputs and outputs

Three global files are involved: ~/.pi/agent/settings.json holds defaultProvider, defaultModel, and defaultThinkingLevel; ~/.pi/agent/models.json holds custom models keyed by provider; and ~/.pi/agent/auth.json holds provider credentials. Add the model under providers.<provider>.models in models.json - for a built-in provider like OpenRouter or Anthropic, only metadata is needed, since api, baseUrl, and auth are inherited from the bundled defaults:

{
  "providers": {
    "openrouter": {
      "models": [
        {
          "id": "z-ai/glm-5.2:nitro",
          "name": "Z.ai: GLM 5.2 (nitro)",
          "reasoning": true,
          "thinkingLevelMap": { "xhigh": "xhigh" },
          "input": ["text"],
          "cost": { "input": 0.95, "output": 3, "cacheRead": 0.18, "cacheWrite": 0 },
          "contextWindow": 1048576,
          "maxTokens": 32768,
          "compat": { "supportsDeveloperRole": false, "thinkingFormat": "openrouter" }
        }
      ]
    }
  }
}

Copy cost, contextWindow, and compat from the base model rather than hardcoding a generic context or token size, since the variant shares them - the bundled entry can be found in <pi-pkg>/node_modules/@earendil-works/pi-ai/dist/providers/<provider>.models.js. Then set defaultProvider and defaultModel in settings.json to the exact id, leaving defaultThinkingLevel as the user already had it. Verify with pi --list-models | grep <id> and confirm the JSON parses, optionally smoke-testing with pi --provider <p> --model "<id>" "which model are you?".

Integrations

Several quirks matter: the saved-default lookup in find() requires an exact provider+id match, with no fuzzy matching or colon-stripping, so the slug must be byte-identical between settings.json and models.json; editing settings.json alone does nothing if the slug isn't also registered in models.json; the optional enabledModels field pins the model picker so Ctrl+P cycling can't drift back, formatted as "enabledModels": ["<provider>/<id>:<thinking>"]; a repo's local .pi/settings.json overrides the global one, so a default that only reverts inside one project should be checked there first; and Pi must be fully restarted, since the model registry loads at startup.

Who it's for

Anyone debugging why Pi's model picker won't hold the choice they just made - the fix is a config edit rather than a Pi bug report, and once the right file carries the registration, the chosen model behaves like any other bundled one from then on.

Source README

Pi custom / variant model

When to Use

Pi's saved default only loads if the exact provider/id exists in its model registry. Pi ships a static bundled list per provider - so OpenRouter routing-shortcut variants (:nitro = sort by throughput, :floor = cheapest, :exacto = quality tool-use) and any brand-new slug are NOT in it. When the default doesn't resolve, Pi silently falls through to its built-in per-provider default (for openrouter that's moonshotai/kimi-k2.6) - looking like Pi "reset" your model. Fix = register the slug as a custom model so find(provider, id) matches.

Files (global)

  • ~/.pi/agent/settings.json - defaultProvider, defaultModel, defaultThinkingLevel
  • ~/.pi/agent/models.json - custom models, keyed by provider
  • ~/.pi/agent/auth.json - provider credentials (check the provider key exists)

Steps

  1. Confirm the slug is real before adding it (e.g. check the OpenRouter model/variant exists). A typo'd id also silently falls back.
  2. Confirm auth. The provider must have a key in auth.json (or an env var like OPENROUTER_API_KEY). No auth → the model is registered but unavailable → still falls back.
  3. Add the model to models.json under providers.<provider>.models. For a built-in provider (openrouter, anthropic, etc.) you only supply metadata - api, baseUrl, and auth are inherited from the bundled defaults. Example:
    {
      "providers": {
        "openrouter": {
          "models": [
            {
              "id": "z-ai/glm-5.2:nitro",
              "name": "Z.ai: GLM 5.2 (nitro)",
              "reasoning": true,
              "thinkingLevelMap": { "xhigh": "xhigh" },
              "input": ["text"],
              "cost": { "input": 0.95, "output": 3, "cacheRead": 0.18, "cacheWrite": 0 },
              "contextWindow": 1048576,
              "maxTokens": 32768,
              "compat": { "supportsDeveloperRole": false, "thinkingFormat": "openrouter" }
            }
          ]
        }
      }
    }
    
    Copy cost/contextWindow/compat from the base model (the variant shares them) - find the bundled entry in <pi-pkg>/node_modules/@earendil-works/pi-ai/dist/providers/<provider>.models.js. Don't hardcode generic 128k/16k if the real model is bigger.
  4. Set the default in settings.json: defaultProvider + defaultModel = the exact id. Leave defaultThinkingLevel as the user has it.
  5. Verify: pi --list-models | grep <id> shows it, and JSON parses. Optionally smoke-test: pi --provider <p> --model "<id>" "which model are you?".

Quirks

  • Exact match only. find() is exact provider+id - no fuzzy/colon-stripping for the saved default path. The slug in settings.json and models.json must be byte-identical.
  • Silent fallback. Pi prints no error when the default doesn't resolve; it just shows a different model in the footer. That's the tell.
  • Don't edit settings.json alone. Setting defaultModel to an unregistered slug does nothing - models.json is the actual fix.
  • enabledModels (optional) pins the model picker so Ctrl+P cycling can't drift back: "enabledModels": ["<provider>/<id>:<thinking>"].
  • Project override. A repo's .pi/settings.json overrides global. If a default reverts only inside one project, check that file first.
  • Restart Pi fully - the registry loads at startup.

Limitations

  • Adapted from davidondrej/skills; verify local paths, tools, credentials, and agent features before acting.
  • For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.

Discussion

Questions & comments · 0

Sign In Sign in to leave a comment.