Claude Code
Claude Code talks to the Anthropic Messages API. ai& exposes an Anthropic-compatible /v1/messages endpoint, so any tool-calling model in our catalog can drive the agent loop.
Two ways to wire it up:
- Session —
exportthe env vars into your current shell. Lost when you close the terminal. Good for a one-off try. - Permanent — drop the same config into
settings.json. Persists across sessions, can be scoped per project or globally.
Session (current terminal only)
Section titled “Session (current terminal only)”1. Install Claude Code
Prerequisite: Node.js 22 or newer.
npm install -g @anthropic-ai/claude-codeConfirm the install — claude --version should print a version number:
claude --version2. Set the env vars in this terminal
export ANTHROPIC_BASE_URL="https://api.aiand.com"export ANTHROPIC_AUTH_TOKEN="sk-your-aiand-api-key"export ANTHROPIC_API_KEY=""export ANTHROPIC_DEFAULT_OPUS_MODEL="moonshotai/kimi-k3"export ANTHROPIC_DEFAULT_SONNET_MODEL="moonshotai/kimi-k3"export ANTHROPIC_DEFAULT_HAIKU_MODEL="google/gemma-4-31b-it"export CLAUDE_CODE_SUBAGENT_MODEL="moonshotai/kimi-k3"3. Run Claude Code
claude1. Install Claude Code
Prerequisites:
npm install -g @anthropic-ai/claude-codeConfirm the install — claude --version should print a version number:
claude --version2. Set the env vars in this terminal
$env:ANTHROPIC_BASE_URL = "https://api.aiand.com"$env:ANTHROPIC_AUTH_TOKEN = "sk-your-aiand-api-key"$env:ANTHROPIC_API_KEY = ""$env:ANTHROPIC_DEFAULT_OPUS_MODEL = "moonshotai/kimi-k3"$env:ANTHROPIC_DEFAULT_SONNET_MODEL = "moonshotai/kimi-k3"$env:ANTHROPIC_DEFAULT_HAIKU_MODEL = "google/gemma-4-31b-it"$env:CLAUDE_CODE_SUBAGENT_MODEL = "moonshotai/kimi-k3"3. Run Claude Code
claudePermanent (settings.json)
Section titled “Permanent (settings.json)”Claude Code reads its config from a settings.json file on startup. Drop the same env block in and you never have to re-export:
{ "env": { "ANTHROPIC_BASE_URL": "https://api.aiand.com", "ANTHROPIC_AUTH_TOKEN": "sk-your-aiand-api-key", "ANTHROPIC_API_KEY": "", "ANTHROPIC_DEFAULT_OPUS_MODEL": "moonshotai/kimi-k3", "ANTHROPIC_DEFAULT_SONNET_MODEL": "moonshotai/kimi-k3", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "google/gemma-4-31b-it", "CLAUDE_CODE_SUBAGENT_MODEL": "moonshotai/kimi-k3" }}Two scopes — pick one:
- Project (
.claude/settings.local.jsonin your repo) — applies only when you runclaudefrom this repo. The file holds your API key in plain text, so the command below also adds it to the repo’s.gitignore(skipped if the line is already there); commit that.gitignorechange. Recommended for trying ai& without touching your global setup. - Global (
~/.claude/settings.json) — applies machine-wide. Every Claude Code surface on your machine picks up the same ai& backend: theclaudeCLI in any terminal session, the Claude Code VS Code extension (the extension and CLI share this file by design), and the Claude Desktop app. Use this once ai& is your default everywhere.
The commands below safely merge the env block into the file — any existing keys you have (permissions, hooks, etc.) are preserved. They use Node, which is already on your machine since step 1 installed Claude Code via npm. Replace sk-your-aiand-api-key with your real key before running.
Project scope (recommended for first try)
Section titled “Project scope (recommended for first try)”Run from the root of your project:
mkdir -p .claude && node -e 'const fs = require("fs"), p = ".claude/settings.local.json";const d = fs.existsSync(p) ? JSON.parse(fs.readFileSync(p, "utf8")) : {};d.env = Object.assign(d.env || {}, { ANTHROPIC_BASE_URL: "https://api.aiand.com", ANTHROPIC_AUTH_TOKEN: "sk-your-aiand-api-key", ANTHROPIC_API_KEY: "", ANTHROPIC_DEFAULT_OPUS_MODEL: "moonshotai/kimi-k3", ANTHROPIC_DEFAULT_SONNET_MODEL: "moonshotai/kimi-k3", ANTHROPIC_DEFAULT_HAIKU_MODEL: "google/gemma-4-31b-it", CLAUDE_CODE_SUBAGENT_MODEL: "moonshotai/kimi-k3"});fs.writeFileSync(p, JSON.stringify(d, null, 2));const g = ".gitignore", gi = fs.existsSync(g) ? fs.readFileSync(g, "utf8") : "";if (!gi.split(/\r?\n/).includes(p)) fs.appendFileSync(g, (gi && !gi.endsWith("\n") ? "\n" : "") + p + "\n");'Run from the root of your project:
New-Item -ItemType Directory -Force -Path .claude | Out-Null$script = @'const fs = require("fs"), p = ".claude/settings.local.json";const d = fs.existsSync(p) ? JSON.parse(fs.readFileSync(p, "utf8")) : {};d.env = Object.assign(d.env || {}, { ANTHROPIC_BASE_URL: "https://api.aiand.com", ANTHROPIC_AUTH_TOKEN: "sk-your-aiand-api-key", ANTHROPIC_API_KEY: "", ANTHROPIC_DEFAULT_OPUS_MODEL: "moonshotai/kimi-k3", ANTHROPIC_DEFAULT_SONNET_MODEL: "moonshotai/kimi-k3", ANTHROPIC_DEFAULT_HAIKU_MODEL: "google/gemma-4-31b-it", CLAUDE_CODE_SUBAGENT_MODEL: "moonshotai/kimi-k3"});fs.writeFileSync(p, JSON.stringify(d, null, 2));const g = ".gitignore", gi = fs.existsSync(g) ? fs.readFileSync(g, "utf8") : "";if (!gi.split(/\r?\n/).includes(p)) fs.appendFileSync(g, (gi && !gi.endsWith("\n") ? "\n" : "") + p + "\n");'@node -e $scriptGlobal scope (all projects)
Section titled “Global scope (all projects)”mkdir -p ~/.claude && node -e 'const fs = require("fs"), os = require("os"), path = require("path");const p = path.join(os.homedir(), ".claude", "settings.json");const d = fs.existsSync(p) ? JSON.parse(fs.readFileSync(p, "utf8")) : {};d.env = Object.assign(d.env || {}, { ANTHROPIC_BASE_URL: "https://api.aiand.com", ANTHROPIC_AUTH_TOKEN: "sk-your-aiand-api-key", ANTHROPIC_API_KEY: "", ANTHROPIC_DEFAULT_OPUS_MODEL: "moonshotai/kimi-k3", ANTHROPIC_DEFAULT_SONNET_MODEL: "moonshotai/kimi-k3", ANTHROPIC_DEFAULT_HAIKU_MODEL: "google/gemma-4-31b-it", CLAUDE_CODE_SUBAGENT_MODEL: "moonshotai/kimi-k3"});fs.writeFileSync(p, JSON.stringify(d, null, 2));'New-Item -ItemType Directory -Force -Path $HOME\.claude | Out-Null$script = @'const fs = require("fs"), os = require("os"), path = require("path");const p = path.join(os.homedir(), ".claude", "settings.json");const d = fs.existsSync(p) ? JSON.parse(fs.readFileSync(p, "utf8")) : {};d.env = Object.assign(d.env || {}, { ANTHROPIC_BASE_URL: "https://api.aiand.com", ANTHROPIC_AUTH_TOKEN: "sk-your-aiand-api-key", ANTHROPIC_API_KEY: "", ANTHROPIC_DEFAULT_OPUS_MODEL: "moonshotai/kimi-k3", ANTHROPIC_DEFAULT_SONNET_MODEL: "moonshotai/kimi-k3", ANTHROPIC_DEFAULT_HAIKU_MODEL: "google/gemma-4-31b-it", CLAUDE_CODE_SUBAGENT_MODEL: "moonshotai/kimi-k3"});fs.writeFileSync(p, JSON.stringify(d, null, 2));'@node -e $scriptVerify
Section titled “Verify”Inside Claude Code, run:
/statusThe panel shows the active base URL and model. You should see https://api.aiand.com and moonshotai/kimi-k3.
You can also probe the wire-level path from the shell:
curl -sS https://api.aiand.com/v1/models \ -H "Authorization: Bearer sk-your-aiand-api-key" \ | grep -o 'moonshotai/kimi-k3'(Invoke-RestMethod https://api.aiand.com/v1/models ` -Headers @{ Authorization = "Bearer sk-your-aiand-api-key" }).data.id ` | Select-String "moonshotai/kimi-k3"A match means the key authenticates and the model is on your org.
What to expect
Section titled “What to expect”- Effort.
/effortandCLAUDE_CODE_EFFORT_LEVELare honoured: Claude Code sends the level asoutput_config.effort, and ai& applies it as the model’sreasoning_effort. A level the model does not list, other thannone(a 400), runs at the next listed level up, or its highest, so/effort xhighon a model whose top level ismaxruns atmaxand can cost more;X-Reasoning-Effortreports the level applied, and each model lists its levels inreasoning_efforts. When no level is sent, ai& forwards none and the model runs at its own default, which can be its most expensive level, so set one deliberately. - Context limit. When a conversation outgrows the model’s window, ai& answers with Anthropic’s own “prompt is too long” wording, so Claude Code compacts and retries on its own. Claude Code assumes a 200K window for model names it does not recognise, so a model with a smaller
context_windowreaches its limit sooner and relies on that compact-and-retry. - Thinking. Claude Code asks for adaptive thinking on its main chat requests and sends no
thinkingon background calls; ai& streams the model’s reasoning back asthinkingblocks. The block sets no level exceptthinking: { "type": "disabled" }, which turns reasoning off on a named reasoning model that listsnoneand is a 400 on one that doesn’t (details, error text); otherwise the level comes from effort. - WebSearch and other server-side tools. Anthropic’s server-side tools (web search, web fetch, code execution) run inside Anthropic’s API and are not available through ai&. A request that includes one is refused with a 400 naming the tool, so Claude Code’s
WebSearchtool reports an error rather than a made-up result. Use an MCP web-search server instead. - Screenshots. Images inside tool results (the
Readtool on a PNG, for example) reach the model on vision-capable models and are replaced by a short placeholder on text-only ones.