Docs

Pi

Pi is a deliberately small terminal agent: a minimal shell that adapts to how you work instead of imposing how it works. It speaks the OpenAI format, so Helmcode goes in as one more provider.

It installs with curl -fsSL https://pi.dev/install.sh | sh, or on Windows with powershell -c "irm https://pi.dev/install.ps1 | iex".

Configuration

1. Declare the provider

In ~/.pi/agent/models.json:

{
  "providers": {
    "helmcode": {
      "baseUrl": "https://api.helmcode.com/v1",
      "api": "openai-completions",
      "apiKey": "sk-your-key-here",
      "compat": { "supportsDeveloperRole": true },
      "models": [
        {
          "id": "deepseek-v4-flash",
          "name": "DeepSeek V4 Flash",
          "reasoning": true,
          "input": ["text", "image"],
          "contextWindow": 1048576,
          "maxTokens": 32768
        },
        {
          "id": "glm5.3",
          "name": "GLM 5.3",
          "reasoning": true,
          "input": ["text", "image"],
          "contextWindow": 1048576,
          "maxTokens": 32768
        },
        {
          "id": "glm5.3-flash",
          "name": "GLM 5.3 Flash",
          "reasoning": true,
          "input": ["text", "image"],
          "contextWindow": 1048576,
          "maxTokens": 32768
        },
        {
          "id": "qwen3.6",
          "name": "Qwen 3.6",
          "reasoning": true,
          "input": ["text", "image"],
          "contextWindow": 262144,
          "maxTokens": 32768
        },
        {
          "id": "gemma4",
          "name": "Gemma 4",
          "reasoning": true,
          "input": ["text", "image"],
          "contextWindow": 262144,
          "maxTokens": 32768
        }
      ]
    }
  }
}

api: "openai-completions" is what tells Pi which format to speak. maxTokens is the ceiling for one answer, not the context — the same figure the OpenCode block publishes as limit.output, because it answers the same question.

2. Make it the default

In ~/.pi/agent/settings.json:

{
  "defaultProvider": "helmcode",
  "defaultModel": "glm5.3-flash"
}

An interactive session needs a default model and says so. Without defaultModel, the first thing Pi tells you after you connect is:

Error: Saved API key for helmcode, but no default model is configured for
provider "helmcode". Use /model to select a model.

You can obey that and pick with /model every session, or write it here once. Pi does not persist your pick: the settings.json it writes on its own carries the theme and nothing else.

Headless is the exception — pi -p resolves a model without this file. And if you declare a second provider without setting defaultProvider, Pi chooses for you; in our test it took the other one and failed against it.

3. Keep the key out of the file, if you prefer

This one runs after step 1, not instead of it: /login offers the providers declared in models.json, so if helmcode is not on the list, that file has not landed. Nothing says so — the entry is simply absent.

Instead of the apiKey field above, start a session and run:

/login

Paste the key when it asks. Pi writes ~/.pi/agent/auth.json with mode 600, so your models.json carries no secret and can be synced between machines freely. Do not write that file by hand: the credential is typed ("type": "api_key") and a plausible guess at the shape is accepted in silence and then does not authenticate.

Either way, this confirms the provider is usable before you ask it anything:

pi auth check --provider helmcode

It prints ready.

4. Try it

pi

Ask it for something short. If it answers, it is going out through Helmcode. You can switch models mid-session without leaving the agent.

glm5.3-flash for coding work: a 1M window, and it counts against the same monthly quota as deepseek-v4-flash, which is the other 1M model on every plan. qwen3.6 for everything that is bounded and wants an answer now.

Known issues

  • An error about a ByteString is a broken key, not a broken model. If a request fails with Cannot convert argument to a ByteString because the character at index 7 has a value of …, the key has a non-ASCII character in it. Index 7 is the first character after Bearer , so it is naming the first character of your credential. It happens when the key is copied out of a framed terminal UI and a box-drawing character comes along: the message mentions neither the key nor the header, so there is nothing to connect it to. Keys start with sk-hke_ and are ASCII throughout, which makes it quick to confirm.
  • The key is written in the file, unless you used /login. models.json lives in your home directory, so it does not usually end up in a repository, but keep it in mind if you sync your configuration between machines.
  • maxTokens is not the context. It is the ceiling for each answer. Reasoning comes out of that same budget, so if you ask for long reasoned answers, raise it.
  • The models you declare are the ones you get. Pi does not ask the API what is available: it shows whatever is on the list.