# Claude Code

Source: https://aiand-docs-staging.pages.dev/integrations/claude-code/

[Claude Code](https://claude.com/claude-code) talks to the Anthropic Messages API. ai& exposes an Anthropic-compatible `/v1/messages` endpoint, so any tool-calling model in our [catalog](/models/catalog/) can drive the agent loop.

<Aside type="note">
  The config below maps two ai& models to Claude Code's slots: `moonshotai/kimi-k3` drives **Opus** and **Sonnet** (the heavy lifting), while the cheaper `google/gemma-4-31b-it` handles **Haiku** (lightweight background tasks). Swap any line for another `tool_calling` model in the [catalog](/models/catalog/).
</Aside>

Two ways to wire it up:

- **[Session](#session-current-terminal-only)** — `export` the env vars into your current shell. Lost when you close the terminal. Good for a one-off try.
- **[Permanent](#permanent-settingsjson)** — drop the same config into `settings.json`. Persists across sessions, can be scoped per project or globally.

## Session (current terminal only)

<Tabs syncKey="os">
<TabItem label="macOS / Linux">

**1. Install Claude Code**

Prerequisite: [Node.js 22 or newer](https://nodejs.org/).

```bash
npm install -g @anthropic-ai/claude-code
```

Confirm the install — `claude --version` should print a version number:

```bash
claude --version
```

**2. Set the env vars in this terminal**

```bash
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**

```bash
claude
```

</TabItem>
<TabItem label="Windows (PowerShell)">

**1. Install Claude Code**

Prerequisites:

- [Node.js 22 or newer](https://nodejs.org/)
- [Git for Windows](https://git-scm.com/download/win)

```powershell
npm install -g @anthropic-ai/claude-code
```

Confirm the install — `claude --version` should print a version number:

```powershell
claude --version
```

**2. Set the env vars in this terminal**

```powershell
$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**

```powershell
claude
```

</TabItem>
</Tabs>

## 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:

```json
{
  "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.json` in your repo)** — applies only when you run `claude` from 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 `.gitignore` change. 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: the `claude` CLI in any terminal session, the [Claude Code VS Code extension](https://code.claude.com/docs/en/vs-code) (the extension and CLI [share this file](https://code.claude.com/docs/en/vs-code#configure-settings) 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)

<Tabs syncKey="os">
<TabItem label="macOS / Linux">

Run from the root of your project:

```bash
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");
'
```

</TabItem>
<TabItem label="Windows (PowerShell)">

Run from the root of your project:

```powershell
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 $script
```

</TabItem>
</Tabs>

### Global scope (all projects)

<Tabs syncKey="os">
<TabItem label="macOS / Linux">

```bash
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));
'
```

</TabItem>
<TabItem label="Windows (PowerShell)">

```powershell
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 $script
```

</TabItem>
</Tabs>

## Verify

Inside Claude Code, run:

```text
/status
```

The 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:

<Tabs syncKey="os">
<TabItem label="macOS / Linux">

```bash
curl -sS https://api.aiand.com/v1/models \
  -H "Authorization: Bearer sk-your-aiand-api-key" \
  | grep -o 'moonshotai/kimi-k3'
```

</TabItem>
<TabItem label="Windows (PowerShell)">

```powershell
(Invoke-RestMethod https://api.aiand.com/v1/models `
  -Headers @{ Authorization = "Bearer sk-your-aiand-api-key" }).data.id `
  | Select-String "moonshotai/kimi-k3"
```

</TabItem>
</Tabs>

A match means the key authenticates and the model is on your org.

<Aside type="note">
  If you previously signed in to Claude Code with an Anthropic account, run `/logout` once inside `claude` — the cached OAuth credential takes priority over the env / settings.json values, and you'll silently keep hitting Anthropic instead of ai&.
</Aside>

## What to expect

- **Effort.** `/effort` and `CLAUDE_CODE_EFFORT_LEVEL` are honoured: Claude Code sends the level as `output_config.effort`, and ai& applies it as the model's [`reasoning_effort`](/models/catalog/). A level the model does not list, other than `none` (a 400), runs at the next listed level up, or its highest, so `/effort xhigh` on a model whose top level is `max` runs at `max` and can cost more; `X-Reasoning-Effort` reports the level applied, and each model lists its levels in `reasoning_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_window` reaches 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 `thinking` on background calls; ai& streams the model's reasoning back as `thinking` blocks. The block sets no level except `thinking: { "type": "disabled" }`, which turns reasoning off on a named reasoning model that lists `none` and is a 400 on one that doesn't ([details](/api/messages/#reasoning), [error text](/errors/#turning-reasoning-off)); 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 `WebSearch` tool reports an error rather than a made-up result. Use an MCP web-search server instead.
- **Screenshots.** Images inside tool results (the `Read` tool on a PNG, for example) reach the model on vision-capable models and are replaced by a short placeholder on text-only ones.
