Claude Code doesn't have to talk to Anthropic's servers. It reads a few environment variables to decide where to send its API requests, and if you point those at a different endpoint -- a local model, a proxy, another provider -- it just works. Here's how to do it, using a local Ollama model as the example.

Claude Code speaks the "Anthropic protocol", and so can other backends

Since Ollama v0.14 (released January 2026), Ollama's HTTP server natively speaks the Anthropic Messages API -- the same protocol Claude Code uses to talk to Anthropic. So Claude Code doesn't actually know whether the other end is api.anthropic.com or localhost:11434. As long as responses come back in the format it expects, it works.

Claude Code reads three environment variables to figure out where to send its requests:

  • ANTHROPIC_BASE_URL -- the server URL
  • ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY -- credentials
  • ANTHROPIC_MODEL -- which model name to request

By default these are unset and Claude Code uses OAuth to talk to your Anthropic subscription. Set them and it talks to whatever you point it at. The same mechanism works for any Anthropic-compatible endpoint, not just Ollama.

The minimum viable setup

The smallest change that works:

export ANTHROPIC_BASE_URL=http://localhost:11434
export ANTHROPIC_AUTH_TOKEN=ollama
export ANTHROPIC_API_KEY=
export ANTHROPIC_MODEL=qwen3.6:35b-a3b-coding-nvfp4
claude -p "what is dependency injection?"

That's it. Claude Code now sends its API request to your local Ollama, which runs the prompt through Qwen and streams the response back through the same channel Anthropic's responses would have used.

Two details matter here:

  • ANTHROPIC_AUTH_TOKEN=ollama is just a placeholder. Ollama doesn't check it, but Claude Code requires some value.
  • The empty ANTHROPIC_API_KEY= is important. If it's set, Claude Code prefers it over ANTHROPIC_AUTH_TOKEN and tries to use it as an Anthropic key, which fails.

Don't put this in your shell rc

The obvious move is to add those four export lines to ~/.zshrc and be done. Don't. If you do, every claude invocation will route to your alternate backend, including:

  • Your normal interactive Claude Code sessions
  • Anything that calls claude -p under the hood (CI scripts, git hooks, build pipelines)
  • Other tools on your system that might shell out to claude

A small judgment task you scheduled at 3am will silently run on the local model instead of Claude Opus, and you'll wonder why output quality dropped overnight.

The cleaner pattern is a shell function that opts in per-invocation:

# Per-invocation local-model switcher (doesn't affect default `claude`)
claudel() {
  ANTHROPIC_BASE_URL=http://localhost:11434 \
  ANTHROPIC_AUTH_TOKEN=ollama \
  ANTHROPIC_API_KEY= \
  ANTHROPIC_MODEL=qwen3.6:35b-a3b-coding-nvfp4 \
  command claude "$@"
}

Now claude -p "..." keeps using your Anthropic subscription, and claudel -p "..." uses the local model. You opt in explicitly when you want it, with no way to surprise yourself later.

Add the function to ~/.zshrc, source it, and you have a clean toggle:

source ~/.zshrc
type claudel
# claudel is a shell function from /Users/markshust/.zshrc

claudel -p "hello, are you running locally?"

One detail worth calling out: the command keyword in front of claude skips any aliases you have on claude (I have one that auto-loads a plugin directory). Without it the function would expand your alias instead of the real binary, and the override wouldn't apply cleanly.

Recap

Pointing Claude Code somewhere else is just three environment variables: ANTHROPIC_BASE_URL, a credential, and ANTHROPIC_MODEL. Set them inline through a small wrapper function rather than globally, so your default claude keeps talking to Anthropic and you switch backends only when you mean to.