Guides & Tutorials9 min read

Claude Code on an Open Model, No Router: the Anthropic Messages API on Qwen3.8 27B, Measured

Claude Code speaks Anthropic's Messages API, so running it on an open model has meant putting a translating router in between. We now serve /v1/messages ourselves. Here are the seven lines of setup, what Claude Code actually sends, the two requests we refused on the first day, and what three runs of a bug-fix task measured.

7 lines
of environment variables, and no router
9 of 9
requests of a session answered, once all five model variables were set
27 to 55 s
to find and fix a bug and re-run the tests, over three runs
The Paralon capybara plugging a glowing cable from a terminal window straight into a graphics card, a small adapter box left unused beside it

Claude Code talks to its model in Anthropic's Messages format, not OpenAI's. Until now, running it on an open model meant putting a router in between to translate. Our API now answers POST /v1/messages itself, so Claude Code points at an open model with seven environment variables and nothing else installed.

Yesterday we published a guide that did this through 9Router. That route still works, and 9Router does more than translate. This one is for when all you want is Claude Code on qwen3.8-27b, the same model the chat completions and Responses endpoints serve, at the same price per token.

Everything below was run with Claude Code 2.1.296 on 13 October 2026. ParalonCloud is not affiliated with Anthropic; Claude Code is their tool, and we are describing how it behaves against our endpoint.

Setup

Make an API key on the API keys page (how keys work is in the authentication docs), then:

export ANTHROPIC_BASE_URL=https://paraloncloud.com
export ANTHROPIC_AUTH_TOKEN=sk-your-key
export ANTHROPIC_MODEL=qwen3.8-27b
export ANTHROPIC_SMALL_FAST_MODEL=qwen3.8-27b
export ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3.8-27b
export ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3.8-27b
export ANTHROPIC_DEFAULT_OPUS_MODEL=qwen3.8-27b
claude

That is all of it. The same variables can go in the env block of Claude Code's settings.json if you would rather not export them each time. The model name is the id from the model list; what is live right now is on the inference page.

Why five model variables and not one

Because Claude Code does not send everything to the model you chose. A session also makes small side requests, for a title or a summary, and sends them to other models by name.

We found this by putting a logging relay between Claude Code and our API. With ANTHROPIC_MODEL, ANTHROPIC_SMALL_FAST_MODEL and ANTHROPIC_DEFAULT_HAIKU_MODEL set, one request of the session still went out asking for claude-sonnet-5, a model we do not have, and came back "model not found". The session carried on, so you could miss it for weeks. With the Sonnet and Opus variables set as well, all 9 requests of the next session asked for qwen3.8-27b and all 9 were answered.

What Claude Code actually sends

From the same relay, one session of the task below:

Requests in the session9
Main requests (streamed)7, each with 20 tool definitions, max_tokens 32,000 and thinking: adaptive
Side requests (not streamed)2, no tools, max_tokens 2,112
Messages in the last main request20
Content blocks in usetext, thinking, tool_use, tool_result
Fields we accept and ignorecontext_management, output_config, safeguards, cache_control

Two things in there are worth knowing if you run an endpoint like this yourself.

It asks for thinking. thinking: adaptive on every main request. We leave the model's reasoning on when a request asks for it and return it in thinking blocks; a request that does not ask gets a direct answer, which is faster to the first token.

It puts a system message among the turns. The Messages API has a top-level system field, and the messages are meant to alternate between user and assistant. Claude Code also sends a message with the role system in the middle of the list. On our first day we answered that with a 400. Claude Code retried without it and carried on, at the cost of one wasted request per session. We now join such messages to the system prompt, since a chat template takes a system message at the start only.

What we measured

The task: a folder with a slugify.js that has a bug and a test.js with three cases, two of them failing. The prompt asked Claude Code to run the tests, find the bug, fix it, and run them again. That needs the whole loop: a shell command, a file read, an edit, another shell command.

Run 1Run 2Run 3
Resultfixed, 3 of 3 passfixed, 3 of 3 passfixed, 3 of 3 pass
Turns758
Wall time52 s27 s55 s
Time spent waiting on the API25 s23 s35 s
Input tokens not from cache17,55817,04730,825
Input tokens read from cache82,36865,12088,000
Output tokens1,1809201,689

All three runs made the same fix: one regular expression changed to collapse runs of separators, and a second one added to strip a dash at either end.

Three observations.

The spread is the model, not the endpoint. Same task, same prompt, 27 to 55 seconds. The model takes a different path each time: sometimes it reads the test file before the source, sometimes it runs the tests twice. Do not quote one run as the speed.

Most of the prompt comes from cache. Claude Code sends its whole system prompt and 20 tool definitions on every turn. The worker keeps those tokens from the previous turn, so four in five of the input tokens in run 1 were read from cache instead of being processed again. They come back in the usage as cache_read_input_tokens, without anything in the request being marked with cache_control. Getting a request back to the worker that holds its prefix is its own problem; we wrote up how we route to the GPU that has your KV cache.

It is cheap to try. At $0.12 per million input tokens and $1.70 per million output, the largest of the three runs comes to under two cents even if every cached token is counted at the full input price. There is no subscription: the API is pay as you go.

The endpoint from anything else

Claude Code is one client. Anything that speaks the Messages API works the same way. The key goes in x-api-key, the header Anthropic's SDKs send, or in Authorization: Bearer.

curl https://paraloncloud.com/v1/messages \
  -H "x-api-key: sk-your-key" \
  -H "content-type: application/json" \
  -d '{
    "model": "qwen3.8-27b",
    "max_tokens": 200,
    "system": "You answer in one sentence.",
    "messages": [{"role": "user", "content": "What is a KV cache?"}]
  }'

The answer is a Message: content blocks, a stop_reason of end_turn, max_tokens or tool_use, and usage. Tools with an input_schema come back as tool_use blocks and take their answers as tool_result blocks, and "stream": true gives the usual message_start, content_block_*, message_delta and message_stop events. The full list is in the Messages API reference.

Three things to watch

The context window is 131,072 tokens. Claude Code does not know this model and assumes a larger window. On a short task it makes no difference. In a long session it can be refused by the API before it thinks to compact. Run /compact yourself before that. Why the window is what it is on this model, and what a longer one costs in GPU memory, is in how much VRAM a 256k context needs.

Ignore the cost Claude Code prints. It has no price list for a model it does not know, so the figure at the end of a session is not what was charged. The real numbers are on Inference usage. It also prints unrecognized_model on stderr for the same reason, and carries on.

Server tools do not exist here. Web search, code execution and computer use run on Anthropic's side when you use their API. We answer a request that includes one with a 400 that names the tool. The tools Claude Code runs on your machine, which is all of its file and shell work, are unaffected.

What we did not test

  • A long session. Everything above is a task of under a minute on one file.
  • Images sent to the model through this endpoint, and Anthropic's Python and TypeScript SDKs. The request shape they send is the one in the curl example, which is tested; the SDKs themselves we have not run.
  • POST /v1/messages/count_tokens. It is not implemented, and we do not yet know what in a long Claude Code session depends on it.
  • Models other than qwen3.8-27b.

Other tools on the same model

Claude Code is the one that needed a new endpoint. The tools that speak OpenAI's format have worked from the start, each with its own guide: Cline, pi and, through one local address for all of them, 9Router. How fast the model itself runs on the cards behind the API is measured in two RTX 5090s on Qwen3.8 27B.

Troubleshooting

SymptomCause
401 Invalid API keythe key is not a ParalonCloud key, or ANTHROPIC_AUTH_TOKEN is not set in the shell that started claude
model not found for a Claude model nameone of the five model variables is missing
A 400 naming tools[n]the request includes a server tool; only tools with an input_schema are supported
The session stops with a context errorthe conversation passed 131,072 tokens; /compact earlier

Frequently asked questions

Can Claude Code run on a model that is not Claude?

Yes. Claude Code reads the address of its API from ANTHROPIC_BASE_URL and the model names from the ANTHROPIC_*MODEL variables. Any server that answers Anthropic's Messages API can stand in. Ours does, on Qwen3.8 27B.

Do I need a router such as LiteLLM or 9Router?

Not with an endpoint that speaks the Messages API itself. A router is still useful if you want fallback between several providers or one local address for many tools.

Is an open model as good as Claude at this?

We have not measured that and this article does not claim it. Claude Code is written for Claude models. What we measured is that an open 27B model completed a small find-and-fix task three times out of three through it.

On the network

A GPU with JupyterLab on it, in about a minute

Billed for the minutes it runs, on a machine we benchmarked before listing it. Or call open models through an OpenAI-compatible API.

Keep reading

Related articles

The Paralon capybara joining two glowing cables with differently shaped plugs through a small adapter
Guides & Tutorials

11 min read

The OpenAI Responses API on Open Models: responses.create, the Agents SDK and n8n, Measured on Qwen 3.8

Tools are moving from Chat Completions to OpenAI's Responses API, and most open-model endpoints answer it with a 404. We now serve /v1/responses on Qwen 3.8 27B and ran the official OpenAI SDK, the OpenAI Agents SDK and n8n against it unchanged: all 10 SDK checks behaved as designed, a 24-task tool-using agent correct 24 of 24 through all three paths, and no measurable latency added by the translation. What is not supported, and the one setting that cut an n8n node from 3.3 s to 1.0 s.

Read
The Paralon capybara plugging a glowing cable from a code editor into a graphics card
Guides & Tutorials

6 min read

Run Cline on Your Own LLM API: OpenAI-Compatible Setup for VS Code, JetBrains and the CLI

Cline is one of the most-installed open-source coding agents for VS Code, and it lets you bring your own model. Here is the complete setup to point it at any OpenAI-compatible endpoint, using ParalonCloud's inference API and Qwen 3.8 27B as the worked example: the extension, the Plan/Act modes, the CLI, what to put in every field of the model configuration, and what a session actually costs.

Read