Docs

FauxClaude is a small Node server that pretends to be the Anthropic Messages API in front of a local Ollama model — so Claude Code (or anything else that speaks the Claude API) runs against your own hardware for free. That's the whole app. Everything below is optional convenience on top of it.

What it is

One file, server.mjs, zero dependencies. It listens on :11435, translates each request into Ollama's /api/chat format, and translates the reply back into Anthropic's wire format (including streaming SSE). Point any Claude client at it with ANTHROPIC_BASE_URL and it can't tell the difference.

Why bother? Free local Claude Code for everyday coding, plus load-testing a Claude-compatible frontend without burning real API tokens.

Install

Three things, in order.

  1. Ollama, as the app — not ollama serve in a terminal. The app installs a background service that survives logout/reboot, so it's always there when FauxClaude needs it.
    # macOS
    brew install --cask ollama && open -a Ollama
    
    # Windows: install "Ollama for Windows" from ollama.com/download
  2. A model — see picking a model below.
    ollama pull qwen3-vl:30b-a3b-instruct
  3. FauxClaude — either the menu bar / tray app (no terminal needed day-to-day), or run the shim directly:
    git clone https://github.com/garthvh/fauxclaude && cd fauxclaude
    node server.mjs

Picking a model

Claude Code leans hard on tool calling and long context — a small chat model will flail.

qwen3-vl:30b-a3b-instruct — recommended

Mixture-of-Experts: ~30B total but only ~3B active per token, so it's fast despite the size. Also does vision (paste a screenshot) and has a 256k context window. ~19 GB on disk. Needs a roomy box (64 GB+ RAM).

qwen2.5-coder:7b / :14b

Solid dense coding models, no vision. The 7b (~4.7 GB) is the safe pick on a 32 GB machine; the 14b wants more headroom.

qwen3-coder, devstral

Larger dedicated agentic/tool-calling coders if you have the RAM/VRAM to spare and want maximum coding quality over speed.

3b models, mock mode

qwen2.5-coder:3b / llama3.2:3b for a 16 GB box, or MOCK=1 for zero-inference load testing.

Route different Claude tiers to different models with MODEL_MAP, or edit it persistently from either app's Edit Model Map… menu item. A tier pointed at a model you haven't pulled falls back automatically.

Mac app

FauxClaude.app — a native menu bar app that owns the shim process.

Drag it to /Applications and launch from Spotlight. It bundles its own copy of the shim, so it's fully self-contained. Needs Node 18+ (brew install node) and the Ollama app running.

FauxClaude menu bar dropdown, showing status, Mock Mode, Ollama Parallelism, Open Dashboard, Run Claude Code in Terminal, Open Project in VS Code, View Log, Edit Model Map, and Quit
Everything lives in the menu bar — no terminal required.
Menu itemWhat it does
Start / Stop FauxClaudethe shim runs only while the app does
Mock Modecanned replies, no Ollama needed — restarts the shim
Ollama ParallelismInteractive (1 slot) ↔ Simulation (4 slots) — persists the setting and restarts Ollama for you
Open Dashboardthe live GUI, in your default browser
Run Claude Code in Terminal…pick a project folder; opens Terminal there, wired to the shim
Open Project in VS Code…pick a folder; opens an isolated VS Code instance pointed at the shim — see VS Code
View Log~/Library/Logs/fauxclaude.log
Edit Model Map…opens ~/.fauxclaude-model-map.json for persistent per-tier routing
Rebuild after editing server.mjs / dashboard.html / the Swift source with mac-app/build-app.sh — then install it: ditto FauxClaude.app /Applications/FauxClaude.app. open -a FauxClaude launches the installed copy, so a repo rebuild alone won't take effect.

Windows app

windows-app/ — the .NET 8 WinForms system tray twin, kept in feature lock-step with the Mac app.

Same menu, same behavior: Mock Mode, Ollama Parallelism, Open Dashboard, Run Claude Code in Terminal…, Open Project in VS Code…, View Log, Edit Model Map…. Needs Node 18+ and Ollama for Windows.

FauxClaude system tray context menu on Windows, showing the same items as the Mac menu
The tray icon's context menu — identical items to the Mac app.
The FauxClaude dashboard running on Windows, showing 200 requests routed through Ollama with the cost-savings estimate
The same dashboard, live on Windows against Ollama.
cd windows-app
dotnet publish -c Release -r win-x64 --self-contained false
# exe lands in bin\Release\net8.0-windows\win-x64\publish\

VS Code

The Claude Code extension reads its endpoint from the process environment — not from settings.json.

Which means the only way to point it at the shim is to launch VS Code with ANTHROPIC_BASE_URL already set. Open Project in VS Code… does that: it starts a dedicated instance (its own profile, shared extensions) on the folder you pick.

It also installs a small bundled extension, FauxClaude Status — a 🦙 in the status bar that lights up in windows actually routed to the shim (and warns if the shim is offline). The isolated instance gets a purple status bar and a "🦙 FauxClaude" window title, so it's obvious at a glance.

macOS only has one "Visual Studio Code" app. While the FauxClaude instance is running, folders opened via Finder/Dock land inside it and inherit the local routing — even unrelated projects. Keep that window for FauxClaude work only; for normal projects, quit it first and open VS Code the regular way. The dashboard is the source of truth: if a window's activity never shows up there, it isn't routed.

Terminal / CLI

The claude-local launchers start the shim if needed and drop you into Claude Code.

# macOS / Linux
./claude-local
./claude-local -p "explain this repo"

# Windows
.\claude-local.ps1
claude-local.cmd -p "explain this repo"

The launcher only sets env vars for its own child process — your normal claude sessions (real API) are untouched. Logged into claude.ai already? Don't set a credential env var at all; your login rides through (the shim ignores auth). Setting one alongside a login just triggers Claude Code's harmless auth-conflict warning.

Dashboard

Open http://127.0.0.1:11435/ in any browser while the shim is running.

Live over SSE: request counts, tokens in/out, a tokens/sec sparkline, and an all-time "Saved at Claude API rates" estimate — cache-aware, priced per the model the client actually asked for. Below that, a paged table of up to ~2000 recent requests:

The FauxClaude live dashboard on a laptop screen: stat tiles for requests, tokens, and savings, plus a full table of recent requests with their routing, timing, and last message
Live traffic against qwen3-vl:30b-a3b-instruct, routed per Claude tier.
  • active — streaming or working
  • done
  • error — with the failure message
  • canceled — the client disconnected (e.g. you hit Esc in Claude Code) before it finished

Click any row for the full request/response. The "last user message" preview strips Claude Code's injected <system-reminder> boilerplate and interrupt markers, so it shows what was actually typed.

Config reference

All environment variables, all optional.

VarDefaultPurpose
PORT11435listen port
OLLAMA_URLhttp://localhost:11434your Ollama instance
OLLAMA_MODELfirst in /api/tagsdefault backing model
MODEL_MAPhaiku→7bJSON, per-Claude-tier routing
MODEL_MAP_FILEpath to a persistent, editable JSON routing file
NUM_CTX131072Ollama context window (clamped to the model's trained max)
NUM_PREDICT_MAX16384hard cap on generated tokens (runaway guard)
NUM_BATCH2048prompt-eval (prefill) batch size
KEEP_ALIVE-1 (forever)how long Ollama keeps the model loaded
MAX_ACTIVITY2000requests retained for the dashboard
PDF_MAX_PAGES5pages rasterized per PDF document block
PDF_RENDER_DPI150DPI used to rasterize PDF pages to images
MOCKoff1 = canned replies, no Ollama
MOCK_DELAY_MS / MOCK_TOKENS15 / 60mock pacing / response length
LOGoff1 = request logging

Endpoints

EndpointNotes
POST /v1/messagesstreaming + non-streaming; tools, images, PDF documents, thinking blocks passed through
POST /v1/messages/count_tokenschars/4 estimate
GET /v1/models, /v1/models/:idadvertises current Claude model ids
GET /the live dashboard
GET /eventsthe dashboard's SSE feed
GET /healthmode, Ollama url, default model, model map

PDF documents

Ollama's vision models take images only — a PDF is rasterized to page images first.

A Claude document block (base64 application/pdf — the shape Claude Code's document-extraction workloads send) is rasterized to page images and fed through the same path as an image block, capped at the first PDF_MAX_PAGES pages. Two rasterizers, tried in order:

  1. poppler's pdftoppm, if installed — no npm dependency at all. brew install poppler (macOS) / apt install poppler-utils (Linux).
  2. pdf-to-img (optional npm dependency, pinned to 4.5.0 — the last version supporting Node 18; 5.x+ needs Node 20+) — npm install in the repo pulls it in, for boxes without poppler. Depends on canvas (a native module with prebuilt binaries for common platforms).
Neither installed → the document is dropped (as before this feature), with a clear one-time log line telling you how to enable it, instead of silently answering from the prompt text alone. Extraction quality depends on the backing model being vision-capableqwen3-vl, qwen2.5vl, granite3.2-vision — not llama3.2-vision, which errors on some Ollama builds with unknown model architecture: 'mllama'.

Speed & RAM

Generation is memory-bandwidth bound — model size sets the pace, not the frontend.

Keep OLLAMA_NUM_PARALLEL=1 for interactive coding. Extra parallel slots split Ollama's KV cache, so consecutive turns land on empty slots and re-prefill the whole conversation instead of reusing the cached prefix — a huge latency difference on Claude Code's big prompts. Raise it only for load-testing (the app's Ollama Parallelism toggle does this for you).

Box RAMSetup
≥ 64 GBqwen3-vl:30b-a3b-instruct as the single default, or two models resident with OLLAMA_NUM_PARALLEL=4 for sims
32 GBonly qwen2.5-coder:7b pulled; keep NUM_CTX ≤ 32768
16 GBqwen2.5-coder:3b / llama3.2:3b, NUM_CTX=16384, or mock mode

Known gaps

Intentional, not bugs.

  • Input token counts are estimates — Ollama has no tokenizer endpoint.
  • No real prompt caching / batches / files API. The dashboard's savings estimate models caching; the API itself always reports cache_read_input_tokens: 0.
  • Server tools (web_search etc.) in the tools array are silently dropped.
  • Tool-call quality depends entirely on the Ollama model — pick one with tool support.
  • PDF document blocks need poppler or npm install (the pdf-to-img optional dependency) to rasterize — see PDF documents. Non-application/pdf document media types aren't supported.
  • npm install's transitive tar (via the optional canvas native dependency) has open high-severity advisories with no non-breaking fix yet; it's install-time-only (fetches a prebuilt binary from a trusted source), not exercised while the shim runs. Skip npm install entirely if you only use the poppler rasterizer.