Different APIs. One local proxy.

Your client sends Anthropic Messages, but your model server accepts OpenAI Chat Completions. A protocol bridge lets Torana translate between them: requests on the way out, JSON or streaming responses on the way back. It is built in; no plugin is required.

Translation is opt-in for each named provider route. A native route, with no bridge configured, keeps the client and upstream on the same API. Use native routes when you need their supported provider-specific features.

Connect a local model server.

Start an OpenAI-compatible server with a model loaded at http://127.0.0.1:8000. This example assumes it serves /v1/chat/completions without authentication and reports token usage. Torana does not install or start that server.

Build and start Torana using the first two steps of the quickstart. Keep Torana running on loopback. In a second terminal, use the same checkout and evaluation data directory:

export TORANA_DATA_DIR="$PWD/.torana-data"
./torana config get > bridge-settings.json

The snapshot contains revision and config. Inside its config.providers object, add the following entry alongside existing providers. This is a provider entry, not a complete settings file. Preserve the other settings, the revision, and any redacted __set__ markers.

"local-messages": {
  "url": "http://127.0.0.1:8000",
  "format": "openai",
  "auth": {"mode": "none"},
  "bridge": {
    "client": "anthropic",
    "upstream": "openai-chat",
    "model": "your-loaded-model"
  }
}

Replace your-loaded-model with the exact model name accepted by your server. If local-messages already exists, choose a new provider name and use it in the request URL too. Apply the edited snapshot:

./torana config apply --file bridge-settings.json --yes

This saves the configuration and applies it to subsequent requests without restarting. Keep the snapshot private. If another edit or restart makes its revision stale, export again and reapply your intended edits; do not copy a new revision onto old settings.

Send an Anthropic-shaped request.

curl --fail-with-body \
  "$(./torana endpoint local-messages)/v1/messages" \
  -H 'Content-Type: application/json' \
  -d '{"model":"client-model","max_tokens":128,"messages":[{"role":"user","content":"Say hello"}]}'

The local server receives /v1/chat/completions with your-loaded-model. You receive an Anthropic Messages response. Add "stream": true to the JSON body and --no-buffer to curl for an Anthropic event stream.

An Anthropic-compatible client can use the value printed by ./torana endpoint local-messages as its base URL, if it exposes that setting. Start with a short conversation, then check a tool call and its follow-up turn. The harness still executes tools and handles their approvals.

Send complete conversation history on every turn. Translation does not emulate server-managed history. A successful curl request verifies this inference path, not every feature of a coding harness.

Only this example’s provider hop stays local. A remote upstream or an approved plugin’s network calls can still send data off your machine. See data boundaries.

Choose the client and upstream APIs.

These are explicit API contracts, not model names. OpenAI Chat Completions and Responses share a provider family but use different contracts.

openai-chat
OpenAI Chat Completions · family openai
openai-responses
OpenAI Responses · family openai
anthropic
Anthropic Messages · family anthropic
gemini
Gemini generate/streamGenerateContent · family gemini
gemini-codeassist
Code Assist generate/streamGenerateContent · family gemini-codeassist

To expose the same server through Responses, create another provider entry with bridge.client: openai-responses and send requests to its /v1/responses endpoint. Separate route names let one backend serve several client APIs.

Translate what the destination can represent.

Bridges support common text conversations, function definitions and calls, tool-result follow-ups, complete JSON replies, and SSE streams. Image inputs and structured-output constraints are supported where their semantics have a matching representation. The model must support the requested capability too.

Signed reasoning, provider-native server tools, cache breakpoints, opaque continuation items, previous_response_id, and storage/background execution are not portable across these APIs. Unsupported request semantics produce a client-shaped 400 before an upstream call. Unsupported response content produces a 502, or terminates an already-started stream without a success marker.

Under any configured bridge, model discovery, token-counting, files, batch APIs, response retrieval, and other auxiliary APIs are not emulated or forwarded; they return 400. This includes bridges whose client and upstream contracts match, such as a same-API route using bridge.model for aliasing. Matching contracts avoids cross-API content conversion, not the inference-only endpoint boundary. Native routes without bridge retain ordinary auxiliary pass-through.

A harness requiring these auxiliary APIs needs a native route or additional contract support. Provider-native tools also need a compatible inference contract, not just a different base URL.

The automated suite covers all 20 cross-contract directions among the five contracts with mock HTTP upstreams, including text/function-tool loops and JSON/SSE responses. That is contract coverage, not proof that every live harness, model, or account combination works. See the support matrix and full translation surface ↗.

Inspect, change, or remove a bridge.

./torana stats
./torana feed
./torana config get

Request plugins see shared client content and the upstream model alias. Response hooks see the actual upstream’s shared response before Torana converts it for the client. Host usage accounting stays in the upstream’s native terms; the client’s usage fields are converted where representable.

Compatible bridge routes share the same bridge.client contract. A permitted routing plugin or configured fallback can choose a different upstream API behind that contract. Fallbacks rebuild the accepted request for their own model and credentials; request plugins run once.

For any edit, export a fresh settings snapshot and apply it through the CLI. To disable translation while keeping the provider, set its bridge member to null. Omitting the member preserves the existing bridge. Once removed, the client must speak the provider’s native API. Editing the original seed file does not update a managed installation.

For upstream failures, start with status and the local feed. Detailed error-body logging is a separate opt-in and can contain prompts or credentials; use the diagnostic guide ↗ only when needed.

Continue with the CLI reference ↗, plugin-author notes, or plugin registry.

Checked against the Edge source snapshot linked in this guide. SDK v0.5.1 and ABI v1 are unchanged; see upgrade notes ↗ for Responses field access and the one-time cache-prefix key change.