Build with the AI

Use with opencode, Aider, Continue & nanocoder

Point any OpenAI-compatible coding agent at Krallo. opencode can even auto-load the models from a link.

Krallo exposes an OpenAI-compatible chat completions endpoint at https://exe.krallo.com/api/v1. Any tool that speaks the OpenAI Chat Completions wire format — opencode, Aider, Continue, nanocoder, the official OpenAI SDKs, or a raw curl — can drive it with no adapter. You authenticate with a krallo_live_ bearer key, calls are token-metered on your own wallet, and tools (function calling) and streaming both work.

Before you begin

You need one thing: an API key with the ai:invoke scope.

  1. Open the console at /ops/dev and create an app.
  2. Mint a key and grant it ai:invoke (see Scopes). Copy the krallo_live_… secret — it is shown once.
  3. Export it as an environment variable so your editor never hard-codes it:
shell
export KRALLO_API_KEY=krallo_live_...
powershell
$env:KRALLO_API_KEY = "krallo_live_..."

The key is a secret. Keep it in an environment variable or your OS keychain — never commit it to a repo or paste it into client-side code. If it leaks, rotate it in the console. See Authentication.

opencode: automatic setup

Recommended

opencode reads a remote provider configuration from a .well-known/opencode document on the provider’s host, and this document sits at the top of opencode’s config hierarchy. Krallo serves one at https://exe.krallo.com/.well-known/opencode. Because Krallo publishes the full provider block — including every curated model — you do not write an opencode.json by hand: you just supply the key and opencode loads the krallo provider and all four models for you.

GET/.well-known/opencode

This endpoint is public and unauthenticated — it carries no secrets, only model ids and display names — so you can open it in a browser to see exactly what opencode will load.

Set your API key

opencode reads the key from the KRALLO_API_KEY environment variable referenced by the served config ({env:KRALLO_API_KEY}). Export it as shown above, then start opencode and select any krallo-* model. That is the entire setup.

What the link serves

The document is a standard opencode config fragment. It declares the krallo provider (backed by the @ai-sdk/openai-compatible npm package that opencode fetches automatically), the API base URL, the key reference, and each model with a friendly name:

json
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "krallo": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Krallo",
      "options": {
        "baseURL": "https://exe.krallo.com/api/v1",
        "apiKey": "{env:KRALLO_API_KEY}"
      },
      "models": {
        "krallo-chat": { "name": "Krallo Chat" },
        "krallo-code": { "name": "Krallo Code" },
        "krallo-fast": { "name": "Krallo Fast" },
        "krallo-reasoning": { "name": "Krallo Reasoning" }
      }
    }
  }
}

If your opencode version does not pick up the remote document, fall back to the manual configuration below. It is the same provider block — identical base URL, key reference, and models — written into your local opencode.json.

opencode: manual configuration

To pin the configuration locally (or if remote config is not applied), add the provider block to your opencode.json. Place the file in your project root or at ~/.config/opencode/opencode.json:

json
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "krallo": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Krallo",
      "options": {
        "baseURL": "https://exe.krallo.com/api/v1",
        "apiKey": "{env:KRALLO_API_KEY}"
      },
      "models": {
        "krallo-code": { "name": "Krallo Code" },
        "krallo-chat": { "name": "Krallo Chat" },
        "krallo-reasoning": { "name": "Krallo Reasoning" },
        "krallo-fast": { "name": "Krallo Fast" }
      }
    }
  }
}

Keep KRALLO_API_KEY exported in your shell so the {env:KRALLO_API_KEY} reference resolves. Restart opencode and pick a krallo-* model from the model selector.

Available models

All four models accept the same request shape. Reference them by these public ids — Krallo maps each to an internal route on its side, and the underlying provider names are intentionally not exposed. Omit the model field and requests default to krallo-code.

Model idDisplay nameBest for
krallo-code defaultKrallo CodeEditing, refactoring, and agentic coding tasks.
krallo-chatKrallo ChatGeneral conversation and explanation.
krallo-reasoningKrallo ReasoningDeep, multi-step problem solving.
krallo-fastKrallo FastLow-latency, low-cost quick turns.

An unknown model returns a 400 with error type model_not_found and the list of valid ids. You can also enumerate them programmatically via GET /api/v1/models. Full request/response detail lives on Chat completions.

Aider

Aider talks to any OpenAI-compatible endpoint through its OpenAI provider. Set the base URL and key, then name the model with the openai/ prefix so Aider routes it through that provider:

shell
export OPENAI_API_BASE=https://exe.krallo.com/api/v1
export OPENAI_API_KEY=$KRALLO_API_KEY

aider --model openai/krallo-code

On Windows PowerShell, set the variables with $env: first:

powershell
$env:OPENAI_API_BASE = "https://exe.krallo.com/api/v1"
$env:OPENAI_API_KEY  = $env:KRALLO_API_KEY
aider --model openai/krallo-code

Continue

In Continue, add Krallo as an OpenAI-compatible model. Using config.yaml (~/.continue/config.yaml):

yaml
models:
  - name: Krallo Code
    provider: openai
    model: krallo-code
    apiBase: https://exe.krallo.com/api/v1
    apiKey: ${{ secrets.KRALLO_API_KEY }}

The equivalent in the legacy config.json form:

json
{
  "models": [
    {
      "title": "Krallo Code",
      "provider": "openai",
      "model": "krallo-code",
      "apiBase": "https://exe.krallo.com/api/v1",
      "apiKey": "krallo_live_..."
    }
  ]
}

nanocoder

nanocoder is a community, local-first CLI coding agent whose default provider type is openai-compatible — exactly what Krallo serves. Add Krallo as a provider in agents.config.json, either in your project root or at the user level (Windows %APPDATA%\nanocoder\agents.config.json, Linux ~/.config/nanocoder/agents.config.json, macOS ~/Library/Preferences/nanocoder/agents.config.json):

json
{
  "nanocoder": {
    "providers": [
      {
        "name": "Krallo",
        "baseUrl": "https://exe.krallo.com/api/v1",
        "apiKey": "${KRALLO_API_KEY}",
        "models": ["krallo-code", "krallo-chat", "krallo-reasoning", "krallo-fast"]
      }
    ]
  }
}

nanocoder substitutes ${KRALLO_API_KEY} from your environment, so the variable you exported in Before you begin works here too. Then launch with Krallo selected — the --provider value matches the name field in your config — or switch provider/model from inside the session:

shell
nanocoder --provider Krallo --model krallo-code

Any OpenAI-compatible SDK

Because the endpoint is byte-for-byte OpenAI Chat Completions, the official SDKs work by overriding the base URL. Point them at https://exe.krallo.com/api/v1 — the SDK appends /chat/completions itself, so do not include that suffix in the base URL.

Node.js

Node.js
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://exe.krallo.com/api/v1",
  apiKey: process.env.KRALLO_API_KEY,
});

const res = await client.chat.completions.create({
  model: "krallo-code",
  messages: [{ role: "user", content: "Write a bubble sort in Rust." }],
});
console.log(res.choices[0].message.content);

Or with plain environment variables that the SDK reads automatically:

shell
export OPENAI_BASE_URL=https://exe.krallo.com/api/v1
export OPENAI_API_KEY=$KRALLO_API_KEY

Python

python
from openai import OpenAI

client = OpenAI(
    base_url="https://exe.krallo.com/api/v1",
    api_key="krallo_live_...",
)

res = client.chat.completions.create(
    model="krallo-code",
    messages=[{"role": "user", "content": "Explain a mutex in two sentences."}],
)
print(res.choices[0].message.content)

curl

The lowest-common-denominator check — a direct request with no SDK:

shell
curl https://exe.krallo.com/api/v1/chat/completions \
  -H "Authorization: Bearer $KRALLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "krallo-code",
    "messages": [{"role": "user", "content": "Say hello in one sentence."}]
  }'

The response is a standard OpenAI chat.completion object:

json
{
  "id": "chatcmpl-4f1c9a...",
  "object": "chat.completion",
  "created": 1752566400,
  "model": "krallo-code",
  "choices": [
    {
      "index": 0,
      "finish_reason": "stop",
      "message": { "role": "assistant", "content": "Hello there!" }
    }
  ],
  "usage": { "prompt_tokens": 11, "completion_tokens": 3, "total_tokens": 14 }
}

Tools and streaming

Coding agents need two things beyond plain text, and both are supported.

When a request asks for streaming and carries tools, Krallo computes the turn and then replays it as valid SSE frames (including any tool_calls). You still receive a well-formed stream that ends in [DONE] — it just is not emitted incrementally for tool turns.

Attach your own persona

You can steer any coding agent’s behavior by attaching one of your own personas. Set a per-request persona id (or pin one to the app in the console) and its system prompt is prepended to your messages. The persona must be one you can use — your own, or a shared system/global one; an unknown or foreign explicit persona id returns a 400. See Personas.

Troubleshooting

SymptomCause & fix
.well-known/opencode returns 404 not_found The Developer API is not enabled on that host, so the auto-config document is not served. Use the manual configuration instead.
401 unauthorized Missing or invalid bearer key. Confirm KRALLO_API_KEY is exported and begins with krallo_live_. See Authentication.
403 / insufficient_scope The key lacks ai:invoke. Grant it in the console. See Scopes.
400 model_not_found The model id is not one of the four public ids. Drop any provider prefix your tool added (Aider’s openai/ prefix is stripped before it reaches Krallo).
402 insufficient_credits Your wallet balance cannot cover the request; the body reports required_units and balance. Top up. See Billing & quotas.
429 too many requests Per-key rate limit hit. Back off and retry. See Rate limits.
502 upstream_error The model provider was momentarily unavailable; the call is not charged. Retry.

Windows PowerShell: curl is an alias for Invoke-WebRequest and will reject -H flags and bash \ line-continuations. Use the real curl.exe on one line, or Invoke-RestMethod with a real header table.

Errors raised by the AI endpoints themselves (400, 402, 502, …) follow the OpenAI shape { "error": { "message", "type" } }; authentication failures (401/403) use the native { "error": { "code", "message" }, "meta" } envelope, and the 429 is a flat { "error": "rate_limited", … } body. The full catalog is on Errors.

Related pages