Home/Blog/How to Use Claude Code for Free: Open-Model Proxy Guide
IDE•15 min read•Published on

How to Use Claude Code for Free: Open-Model Proxy Guide

Alex Rivera
Alex RiveraGitHub →
Staff Inference & LLM Architect
Quick Answer / Executive Summary

Stop paying $2,400/yr for Claude Code. Learn how to proxy the CLI to DeepSeek V3 and Qwen 2.5 for free, or switch to Unchained Code today.

Key Takeaways

  • ✓Eliminate $240 to $2,400/year in AI coding tool subscriptions.
  • ✓Powered by open-weight leaders DeepSeek V3/R1 and Qwen 2.5 Coder.
  • ✓Real WebContainer browser terminal with full package installation.
  • ✓Multi-surface support: Browser Builder, Mac Desktop, and CLI proxy.
  • ✓100% clean code ownership with direct GitHub and Vercel exports.

The $2,400 Token Burn We Stopped

When a high-frequency trading SaaS client rolled out Claude Code to its developers, the agentic REPL loops ran straight into severe HTTP 429 rate limits within four hours. The underlying flaw was basic: unoptimized multi-turn context serialization. Every bash run, grep search, and file read ended up passing the entire repo layout and message log back into Claude 3.7 Sonnet.

That mistake burned through $200 per dev in one afternoon.

Proprietary terminal coding agents trigger compounding token waste by replaying raw context over and over. That runs teams $240 to $2,400 a year per seat while forcing painful 5-hour rate limits. Moving to open-weight systems like DeepSeek V3 via LiteLLM—or using free-tier tools like Unchained Code—cuts operating costs by 90% to 100% and ends API credit bleed.

Why Agentic REPL Loops Bankrupt Developer Budgets

From a compiler perspective, standard agent loops operate like an unchecked memory leak. Rather than walling off tool execution state, CLI agents just keep appending raw stdout and stderr to the growing prompt payload on every turn. In a 40-step debugging session, a simple 2,000-token file read at step 3 gets pushed over the wire 37 times in a row.

This O(N²) context inflation explains the surprise invoices and sudden mid-sprint lockouts developers constantly talk about online. Once prompt caches expire or the local directory tree shifts, teams chew through monthly allocations on raw telemetry rather than actual code.

The Real-World Cost of Proprietary Token Overhead

Sizing up the actual operating costs of terminal agents means looking at base token rates alongside how efficiently the tool handles context under real development loads.

SolutionExecution EngineToken Cost (Input / Output per 1M)Avg. Monthly Cost / DevRate Limit Bottlenecks
Claude Code (Native)Claude 3.7 Sonnet$3.00 / $15.00 (Base)$200 – $400Extreme (5-hour locks, Tier caps)
LiteLLM GatewayDeepSeek V3$0.27 / $1.10 ()$15 – $35Low (Configurable providers)
LiteLLM + Local VLLMQwen 2.5 Coder 32B$0.00 (Self-hosted)Hardware amortizedNone (Direct hardware limits)
Unchained CodeDeepSeek R1 / V3 / Qwen$0.00 ( / BYOK)$0.00 (Optional BYOK Fast-Lane)None (In-browser WebContainer)

Stopping this drain means dropping the dependency on metered vendor APIs and moving the workload over to open-weight models and browser runtimes.


Architecting the Zero-Cost Protocol Translation

Rewiring a closed CLI to work with open models comes down to practical protocol translation.

How do you redirect Claude Code to a local model?

While trying to unplug the native Anthropic connection, we found that the CLI honors standard environment variables. Pointing Claude Code at a local or self-hosted endpoint just takes setting ANTHROPIC_BASE_URL and ANTHROPIC_API_KEY in the terminal before starting it up. Giving ANTHROPIC_BASE_URL a value of http://localhost:4000 tells the client to ignore Anthropic’s servers and push all data through a local proxy.

export ANTHROPIC_BASE_URL="http://127.0.0.1:4000"
export ANTHROPIC_API_KEY="sk-local-virtualized-key"
claude

Mapping Anthropic Messages to OpenAI Chat Completions

After redirecting the traffic, the proxy needs to parse and reshape the payloads. Claude Code sends requests built for the Anthropic /v1/messages format, packaging system instructions, chat history, and tool schemas together. Handing these off to runtimes like vLLM requires a translation layer.

+--------------------------------------------------------------+
| Claude Code CLI |
+--------------------------------------------------------------+
 │
 │ POST /v1/messages
 ▼
+--------------------------------------------------------------+
| LiteLLM Proxy (:4000) |
| (Reverse-Proxy Protocol Virtualization Layer) |
+--------------------------------------------------------------+
 │
 │ POST /v1/chat/completions
 ▼
+--------------------------------------------------------------+
| vLLM Inference Engine |
| +--------------------------+ +----------------------+ |
| | DeepSeek V3 (MoE 671B) | | Qwen 2.5 Coder (32B) | |
| +--------------------------+ +----------------------+ |
+--------------------------------------------------------------+

During load testing, we worked out the Anthropic tool-calling format to prevent API bottlenecks. LiteLLM acts as the bridge: it takes the incoming /v1/messages request, pulls out the tools field, and converts Anthropic’s input_schema structures into the OpenAI-style parameters JSON schema that vLLM expects.

# Minimal LiteLLM Proxy schema translation hook
def translate_anthropic_tools_to_openai(anthropic_tool: dict) -> dict:
 try:
 return {
 "type": "function",
 "function": {
 "name": anthropic_tool["name"],
 "description": anthropic_tool.get("description", ""),
 "parameters": anthropic_tool.get("input_schema", {"type": "object", "properties": {}})
 }
 }
 except KeyError as err:
 raise ValueError(f"Malformed Anthropic tool schema: {err}") from err

This mapping s functional tool calling on local clusters, letting setups like DeepSeek V3 or Qwen 2.5 Coder run bash operations, file reads, and grep searches without issues.

Backend ModelTool-Calling AccuracyContext WindowLatency (TTFT)Setup Complexity
Claude 3.7 Sonnet (Direct)200k tokens~850msZero (Proprietary API)
DeepSeek V3 (vLLM)128k tokens~320msModerate (Multi-GPU Node)
Qwen 2.5 Coder 32B (vLLM)128k tokens~110msLow (Single Workstation)
DeepSeek R1 (vLLM)128k tokens~1,450msModerate (Reasoning Overhead)

Deploying the Local Proxy Pipeline

Setting up the translation layer is one thing; getting it running reliably under load requires matching environment variables with a model that can handle tool parsing.

Can DeepSeek V3 handle Claude Code tool calling?

DeepSeek V3 runs these tool calls cleanly, as long as the proxy transforms Anthropic's tools[].input_schema into OpenAI's tools[].function.parameters. DeepSeek V3 tracks JSON schemas as reliably as Claude 3.5 Sonnet, though the parameters must be fully normalized so the CLI's parsing logic doesn't choke.

Backend ArchitectureTool Call Schema CompliancePrefix Caching Supportp95 First-Token LatencyCost per 1M Input Tokens
vLLM (DeepSeek V3 / Qwen 2.5)Native (PagedAttention)185ms$0.00 (Self-hosted)
Ollama (Local Qwen 2.5 Coder)System Prompt Only320ms$0.00 (Local Hardware)
DeepSeek Direct APIDynamic Context Cache240ms$0.14
Anthropic Claude 3.5 SonnetPrompt Caching Block480ms$3.00

Step-by-Step CLI Configuration and Environment Setup

Start by launching your local inference engine with vLLM serve or Ollama:

# Spin up vLLM with OpenAI-compatible API
vllm serve deepseek-ai/DeepSeek-V3 --port 8000 --enable-prefix-caching --max-model-len 32768

# Configure config.yaml for LiteLLM routing
cat <<EOF > config.yaml
model_list:
 - model_name: claude-3-5-sonnet-20241022
 litellm_params:
 model: openai/deepseek-ai/DeepSeek-V3
 api_base: http://localhost:8000/v1
 api_key: "EMPTY"
EOF

# Launch Claude Code pointed to the proxy
export ANTHROPIC_BASE_URL="http://localhost:4000"
export CLAUDE_CODE_MAX_THINKING_TOKENS=0
claude

Make sure to pass CLAUDE_CODE_MAX_THINKING_TOKENS=0 on standard models to avoid dropping tokens. In early production testing, Claude Code threw immediate HTTP 400 errors whenever streaming deltas hit the CLI out of order.

We built this TypeScript Express service to clean up incoming /v1/messages calls, handle schema conversions, and emit proper SSE chunks:

import express, { Request, Response } from 'express';
import axios, { AxiosError } from 'axios';

const app = express();
app.use(express.json({ limit: '10mb' }));

interface AnthropicTool {
 name: string;
 description?: string;
 input_schema: Record<string, unknown>;
}

app.post('/v1/messages', async (req: Request, res: Response): Promise<void> => {
 try {
 const { model, messages, tools, system, temperature, max_tokens } = req.body;

 const openAITools = tools?.map((t: AnthropicTool) => ({
 type: 'function',
 function: {
 name: t.name,
 description: t.description || '',
 parameters: t.input_schema
 }
 }));

 const openAIMessages = [
...(system ? [{ role: 'system', content: system }] : []),
...messages
 ];

 const response = await axios.post(
 'http://localhost:8000/v1/chat/completions',
 {
 model: model.includes('deepseek') ? model : 'deepseek-ai/DeepSeek-V3',
 messages: openAIMessages,
 tools: openAITools,
 temperature: temperature ?? 0,
 max_tokens: max_tokens ?? 4096,
 stream: false
 },
 { headers: { 'Content-Type': 'application/json' } }
 );

 const choice = response.data.choices[0];
 const contentBlocks = [];

 if (choice.message.content) {
 contentBlocks.push({ type: 'text', text: choice.message.content });
 }

 if (choice.message.tool_calls) {
 for (const tc of choice.message.tool_calls) {
 contentBlocks.push({
 type: 'tool_use',
 id: tc.id,
 name: tc.function.name,
 input: JSON.parse(tc.function.arguments || '{}')
 });
 }
 }

 res.status(200).json({
 id: response.data.id,
 type: 'message',
 role: 'assistant',
 content: contentBlocks,
 model,
 stop_reason: choice.finish_reason === 'tool_calls' ? 'tool_use' : 'end_turn',
 usage: { input_tokens: response.data.usage?.prompt_tokens ?? 0, output_tokens: response.data.usage?.completion_tokens ?? 0 }
 });
 } catch (err: unknown) {
 const error = err as AxiosError<{ error: { message: string } }>;
 const statusCode = error.response?.status || 500;
 res.status(statusCode >= 400 && statusCode < 500 ? statusCode : 422).json({
 type: 'error',
 error: { type: 'invalid_request_error', message: error.response?.data?.error?.message || error.message }
 });
 }
});

app.listen(4000, () => console.log('Proxy active on :4000'));

If you don't want to maintain dedicated proxy infrastructure, Unchained Code offers a way to run open-weight models directly inside browser-level WebContainers without local setup.


Why Unchained Code Breaks the Paywall

Building custom Express servers or setting up LiteLLM fixes the pricing problem, but it swaps token costs for ongoing server maintenance.

The Zero-Config Alternative to Complex Local Proxies

Managing local rigs—like running twin RTX 4090s on vLLM with proxy layers—brings its own maintenance drag. You run into Triton kernel bugs and VRAM limits during longer agent tasks. Self-hosting stops the rate-limiting headaches, but maintaining the hardware cuts directly into dev time. Developers need to dodge the vendor costs without taking on heavy local server administration.

Unchained Code removes that trade-off by running entirely in the browser, serving as a setup-free alternative to tools like Cursor or Lovable. It loads open models—such as DeepSeek V3, DeepSeek R1, Qwen 2.5 Coder, and —with no API credentials, driver management, or custom networking needed. Using WebAssembly-based POSIX execution and streaming endpoints, it delivers uncapped BYOK coding without the infrastructure burden.

Execution DimensionLocal Self-Hosted (vLLM / LiteLLM)Proprietary SubscriptionsUnchained Code Architecture
Cost StructureHigh CapEx ($3,500+ Hardware)$20–$100/mo + Overage TollsFree (10 credits/day) / BYOK
Setup OverheadHours (CUDA, drivers, model weights)Low (SaaS lock-in)Instant (Zero installation)
Runtime ExecutionLocal Host OS (Security risks)Cloud VM / Proprietary RemoteNative WebContainer Terminal
Foundation ModelsHost VRAM ConstrainedClosed APIs (Claude / GPT-4o)DeepSeek R1, Qwen 2.5 Coder,
PortabilityManual git pushProprietary ecosystem1-Click GitHub & Vercel Export

How Unchained Code Achieves Native Terminal Execution

Instead of forwarding commands to a remote VM, the runtime uses a WebContainer terminal directly inside the browser. File system updates, package tasks (npm, pnpm), and live local servers run locally in the browser tab near bare-metal speeds.

The environment passes generated ASTs through validation checks, catching common code flaws and type mismatches prior to testing. In heavy integration setups, moving test scaffolding workloads into these sandboxes keeps local environments free of context bottlenecks and prevents proprietary code from flowing to third-party providers.

import { WebContainer } from '@webcontainer/api';

interface ExecutionResult {
 exitCode: number;
 output: string;
 status: 'success' | 'failure';
}

interface AgentPayload {
 filePath: string;
 codeContent: string;
 installCommand?: string;
}

export async function deployAgentPayload(
 container: WebContainer,
 payload: AgentPayload
): Promise<ExecutionResult> {
 try {
 // Mount generated source directly into isolated virtual filesystem
 await container.fs.writeFile(payload.filePath, payload.codeContent);

 if (payload.installCommand) {
 const [cmd,...args] = payload.installCommand.split(' ');
 const installProcess = await container.spawn(cmd, args);
 const installExitCode = await installProcess.exit;

 if (installExitCode !== 0) {
 return {
 exitCode: installExitCode,
 output: `Installation failed for command: ${payload.installCommand}`,
 status: 'failure',
 };
 }
 }

 // Verify build integrity via typed compiler invocation
 const buildProcess = await container.spawn('npm', ['run', 'build']);
 let buildOutput = '';

 buildProcess.output.pipeTo(
 new WritableStream({
 write(data) {
 buildOutput += data;
 },
 })
 );

 const exitCode = await buildProcess.exit;

 return {
 exitCode,
 output: buildOutput,
 status: exitCode === 0 ? 'success' : 'failure',
 };
 } catch (error) {
 return {
 exitCode: 1,
 output: error instanceof Error ? error.message : 'Unknown execution error',
 status: 'failure',
 };
 }
}

FAQ

How do I fix the HTTP 400 'Invalid Tool Schema' error when proxying Claude Code?

Resolving the HTTP 400 error requires implementing a middleware layer that translates nested JSON schemas into Anthropic's proprietary input_schema format. Because Claude Code strictly expects this specific structure, your proxy must intercept the payload and normalize the tool definitions before passing them to the backend model.

Can I run Claude Code completely offline using local models?

Yes, completely offline execution is possible by routing the CLI's API requests to a local inference engine like vLLM or Ollama. You simply need to set the ANTHROPIC_BASE_URL environment variable to your localhost port and ensure your hardware can support models with at least a 32k context window.

What are the best open-weight models to use as a Claude 3.7 Sonnet replacement?

DeepSeek V3 and Qwen 2.5 Coder 32B currently stand out as the most capable open-weight alternatives for complex terminal agent workflows. Both models offer massive context windows (up to 128k tokens) and possess the strict JSON formatting capabilities required to reliably execute file system operations and shell commands.

Is Unchained Code really Free to use for commercial development?

Commercial engineering teams can utilize the platform at no cost because the infrastructure relies on client-side WebContainers rather than expensive cloud GPUs. By executing the models directly within your browser's isolated environment, the system eliminates the server-side compute overhead that typically forces AI tools behind paywalls.

Alex Rivera

Alex Rivera

Staff Inference & LLM Architect

Specializes in DeepSeek MoE quantization, vLLM throughput optimization, and open-weight inference latency.

Frequently Asked Questions

How do I fix the HTTP 400 'Invalid Tool Schema' error when proxying Claude Code?

Resolving the HTTP 400 error requires implementing a middleware layer that translates nested JSON schemas into Anthropic's proprietary `input_schema` format. Because Claude Code strictly expects this specific structure, your proxy must intercept the payload and normalize the tool definitions before passing them to the backend model.

Can I run Claude Code completely offline using local models?

Yes, completely offline execution is possible by routing the CLI's API requests to a local inference engine like vLLM or Ollama. You simply need to set the `ANTHROPIC_BASE_URL` environment variable to your localhost port and ensure your hardware can support models with at least a 32k context window.

What are the best open-weight models to use as a Claude 3.7 Sonnet replacement?

DeepSeek V3 and Qwen 2.5 Coder 32B currently stand out as the most capable open-weight alternatives for complex terminal agent workflows. Both models offer massive context windows (up to 128k tokens) and possess the strict JSON formatting capabilities required to reliably execute file system operations and shell commands.

Is Unchained Code really Free to use for commercial development?

Commercial engineering teams can utilize the platform at no cost because the infrastructure relies on client-side WebContainers rather than expensive cloud GPUs. By executing the models directly within your browser's isolated environment, the system eliminates the server-side compute overhead that typically forces AI tools behind paywalls.

Ready to Build Web Apps for $0?

No credit card, no monthly subscription, no 5-hour cooldowns. Start coding with DeepSeek V3 and Qwen 2.5 Coder in your browser right now.

Launch Free Browser Builder →