Agent workflows · 2026-08-29

HarnessRouter LLMTR provider: one key, three harnesses

The llmtr row in HarnessRouter feeds Claude Code, Codex and Hermes from one base URL and one key. Wire shapes, the model intersection table and the four exclusion rules.

LLMTR diagram for the HarnessRouter LLMTR provider guide, showing one base URL and one key branching into three distinct wire shapes for the Claude Code, Codex and Hermes harnesses.

What the llmtr row solves in harnessrouter

harnessrouter feeds three separate coding harnesses from a single console: Claude Code, Codex and Hermes. Even when they call the same model, these three do not speak the same wire. One expects an Anthropic message envelope, one produces an OpenAI Responses body, one sends a classic chat body. The router's job is to know which harness can actually work with a provider you connect, and to offer you only the combinations that work.

The feat/llmtr-provider branch in the knowhycodata/harnessrouter repository adds one row to the provider table in the README, and that row is ticked for all three harnesses. In practice: you define a single LLMTR connection in the console and all three harnesses can use it. No separate account, key or base URL per harness.

This guide is not about installation steps. It is about the two decisions behind that row: which wire shapes the connection is wired to, and why the model list is deliberately shortened.

The connection record: a provider that asks for no extra field

The LLMTR entry in the router's integrations table carries four things: display name, base URL, the kind of secret to store and a key format hint. The field list is empty. No region, project id, account id or deployment name is requested, because the endpoint has no equivalent for them. That is the most visible difference from the cloud provider rows next to it.

The key hint shows the llmtr prefix. The console uses that hint only to sanity-check the shape of what you paste; the verification request carries the key verbatim in the Authorization header.

Fields the LLMTR entry carries in the harnessrouter integrations table

label: LLMTR
base_url: https://llmtr.com/v1
fields: []          # no region, project or account id is asked for
secret: api_key
secret_label: API Key
key_hint: "llmtr-..."

Three harnesses, three wire shapes, one base URL

Inside the router each provider and harness pair maps to a connection shape. For LLMTR the Claude Code and Codex pairs map to the tokenrouter shape, and the Hermes pair maps to the openai-api shape. Because one base URL answers on two different body shapes, the row is wired the same way as another multi-surface provider that behaves identically.

The interesting note is the source file's own: LLMTR's Anthropic surface is not separately advertised in the published catalogue, where every model lists OpenAI endpoints. The surface is nonetheless real. The branch author probed it live on 19 August 2026: a POST to /v1/messages with anthropic/claude-sonnet-4.6 returned 200 and a proper Anthropic message envelope, while a path that does not exist under /v1 answered with a structured not_found. The surface was read from a call, not from a catalogue.

The table below shows where each harness sends its request over the same connection, and which model completed a real agentic turn that day.

Wire shape per harness on the harnessrouter LLMTR connection, with the live turns recorded on 19 August 2026
HarnessConnection shapeEndpoint the request reachesModel that completed the turn
Claude Codetokenrouter/v1/messagesanthropic/claude-sonnet-4.6 and anthropic/claude-opus-4.8
Codextokenrouter/v1/responsesopenai/gpt-5.3-codex and openai/gpt-5.5
Hermesopenai-api/v1/chat/completionsanthropic/claude-haiku-4.5

The intersection: connecting adds no name to a picker

The router's LLMTR table is not everything the endpoint publishes. It is the intersection with the router's own model catalogue. That narrowing is deliberate and reduces to one sentence: connecting the provider adds no name to any picker, it only makes models that are already there reachable through Türkiye. What changes for the user is not the names in the list but the route behind them.

The measurement is on record. On 19 August 2026 the public catalogue, which needs no key to read, was fetched: of 245 published ids, 131 clear the agent-loop bar the router states. The 107 of those served only by LLMTR, including the models hosted in Türkiye, are held back as a separate proposal until the router's capability test can scan this catalogue too.

Four rules did the filtering. They are written down so the next person can re-run the measurement instead of trusting a number.

The four rules harnessrouter applies when filtering LLMTR identifiers
Exclusion ruleWhat it keeps out of the tableExample
Agent-loop barIdentifiers that do not emit text or do not declare a tools parameterEmbedding, image, video and speech models
Dated snapshotA second, date-pinned name for a model already in the listA date-pinned qwen-plus copy while qwen-plus itself is listed
Transport matchIdentifiers published on an endpoint other than the one the harness actually drives them overHermes drives the gpt-5 family over /v1/responses while the id is published for chat only
It has to answerIdentifiers that did not respond when called twice on the measurement dayA catalogue entry is an advertisement; the answer is the product, and the reading is that day's

Mapping short names to canonical identifiers

Harnesses keep model names in short form while LLMTR expects a provider-qualified canonical identifier, so the router carries a mapping between the two. The rule is simple: the canonical identifier is the short name with the provider prefix in front of it.

Two rows sit outside that rule and the file states why. When the router already defines a canonical identifier for a model, that identifier is kept instead of minting a new name. One model appearing twice in the picker under two names was judged worse than a name that reads a little oddly.

An excerpt of the mapping between harness-side short names and LLMTR canonical identifiers

claude-sonnet-5     ->  anthropic/claude-sonnet-5
claude-opus-4.8     ->  anthropic/claude-opus-4.8
claude-haiku-4.5    ->  anthropic/claude-haiku-4.5
gpt-5.3-codex       ->  openai/gpt-5.3-codex
gpt-5.5             ->  openai/gpt-5.5
gemini-3.6-flash    ->  google/gemini-3.6-flash
deepseek-v4-pro     ->  deepseek/deepseek-v4-pro
kimi-k3             ->  moonshot/kimi-k3
qwen3.8-max         ->  qwen/qwen3.8-max
minimax-m3          ->  minimax/minimax-m3

# the two rows that sit outside the rule
hunyuan-3           ->  tencent/hy3
nemotron-3-ultra    ->  nvidia/nemotron-3-ultra-550b-a55b

Deriving the intersection yourself

The list in the table is a photograph of the measurement day. Rather than waiting for it to be updated when the catalogue changes, derive the intersection yourself: the public catalogue reads without a key, so the check costs you no credentials.

The short listing below pulls the identifiers from the endpoint and writes them out for comparison with your harness-side list. Presence in the list is not sufficient on its own; check the transport match as well, because calling an identifier on the wrong endpoint produces a picker row that fails on send.

Read the public catalogue without a key and diff it against your harness list

# The public catalogue needs no key
curl -s https://llmtr.com/v1/models \
  | jq -r '.data[].id' | sort > llmtr-ids.txt

# Canonicalise your harness-side short names, then compare
sort harness-canonical-ids.txt > harness-ids.txt
comm -12 llmtr-ids.txt harness-ids.txt   # intersection: drivable today
comm -13 llmtr-ids.txt harness-ids.txt   # in the harness, absent at the endpoint

Codex 0.148.0 and the gpt-5.6 family: a limit that is not the provider's

The live turns surfaced one more thing, recorded separately so the next person does not have to rediscover it. Driven by Codex, gpt-5.6-sol, gpt-5.6-terra and gpt-5.6-luna finish a turn but are never offered tools; the model answers that it has no shell and stops.

The cause is the client, not the provider. Pointed at a local endpoint that records what it is sent, codex 0.148.0 emits the request for these three identifiers with no tools and no instructions field at all, while the same binary against the same endpoint sends eleven tools and a long instructions block for gpt-5.5. Nothing ever reaches the provider for it to drop. The family first attempts a WebSocket session and carries a window id header, so it appears to expect tools and instructions to be established on the connection; falling back to plain HTTPS it sends neither.

Driven by Hermes over the same endpoint and the same base URL, those three identifiers keep their tools. So the limit is not specific to one provider: it applies to every non-OpenAI provider. No per-vendor workaround was written into the router; the situation was recorded as it is.

  • For a tool-using turn under Codex, gpt-5.3-codex and gpt-5.5 completed real turns on the measurement day
  • To drive the gpt-5.6 family with tools, use the Hermes side instead
  • To confirm the client is at fault, point it at a local endpoint that logs requests and check whether a tools field is present
  • This observation belongs to codex 0.148.0; it was not verified on other versions

Frequently asked questions

Does enabling the LLMTR connection add new names to my harness model picker?

No. The router's LLMTR table is deliberately the intersection with its own model catalogue. The connection makes models already present in the picker reachable through Türkiye; it opens no new rows. Identifiers served only by LLMTR are held back as a separate proposal.

Do I need a separate key for Claude Code, Codex and Hermes?

No. All three harnesses use the same connection record with the same base URL and the same key. The only difference is the endpoint the request reaches: Claude Code uses the messages endpoint, Codex uses responses and Hermes uses chat completions.

Why does hunyuan-3 map to tencent/hy3 in the table?

Because the router already defined a canonical identifier for that model. Prefixing the short name would have minted a second name and shown one model as two picker rows. A single name that reads oddly causes fewer problems than a duplicate entry.

How current is the model list in that table?

It rests on the 19 August 2026 measurement and is a photograph of that day. The intersection shifts as the catalogue changes. To see the current state, read the public catalogue without a key and diff it against your own harness list; the listing in this guide gives the commands.

Related posts