Skip to content

OpenAI Compatible API

Use clinvk with existing OpenAI client libraries and tools.

Overview

clinvk provides OpenAI-compatible endpoints that allow you to use OpenAI SDKs with CLI backends. This enables integration with existing applications that use OpenAI's API format.

Base URL

http://localhost:8080/openai/v1

Authentication

API key authentication is optional. If keys are configured, include one of:

  • Authorization: Bearer <key>
  • X-Api-Key: <key>

If no keys are configured, requests are allowed without authentication.

Endpoints

GET /openai/v1/models

List available models (backends mapped as models).

Response:

{
  "object": "list",
  "data": [
    {
      "id": "claude",
      "object": "model",
      "created": 1704067200,
      "owned_by": "clinvoker"
    },
    {
      "id": "codex",
      "object": "model",
      "created": 1704067200,
      "owned_by": "clinvoker"
    },
    {
      "id": "gemini",
      "object": "model",
      "created": 1704067200,
      "owned_by": "clinvoker"
    }
  ]
}

POST /openai/v1/chat/completions

Create a chat completion.

Request Body:

{
  "model": "claude",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"}
  ],
  "max_tokens": 4096,
  "temperature": 0.7,
  "stream": false
}

Fields:

Field Type Required Description
model string Yes Backend selector (see mapping below)
messages array Yes Chat messages
max_tokens integer No Maximum response tokens (ignored by CLI backends today)
temperature number No Sampling temperature (ignored)
top_p number No Nucleus sampling (ignored)
n integer No Number of completions (ignored, always 1)
stream boolean No Enable streaming (SSE) when true
stop string/array No Stop sequences (ignored)
presence_penalty number No Presence penalty (ignored)
frequency_penalty number No Frequency penalty (ignored)
logit_bias object No Logit bias (ignored)
user string No User identifier (ignored)
dry_run boolean No Non-standard: simulate execution without running commands

Response:

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1704067200,
  "model": "claude",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! How can I help you today?"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 15,
    "total_tokens": 25
  }
}

Streaming Response:

When stream: true, returns Server-Sent Events (SSE):

data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1704067200,"model":"claude","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1704067200,"model":"claude","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}

data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1704067200,"model":"claude","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}

data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1704067200,"model":"claude","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]

Model Mapping

The model field determines which backend is used:

Model Value Backend Used
claude Claude
codex Codex
gemini Gemini
Contains claude Claude
Contains gpt Codex
Contains gemini Gemini
Anything else Claude (default)

Recommendation: Use the exact backend name (codex, claude, gemini) to avoid ambiguity.

Client Examples

Python (openai package)

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8080/openai/v1",
    api_key="not-needed"  # Only required if API keys are enabled
)

response = client.chat.completions.create(
    model="claude",
    messages=[
        {"role": "system", "content": "You are a helpful coding assistant."},
        {"role": "user", "content": "Write a hello world in Python"}
    ]
)

print(response.choices[0].message.content)

TypeScript/JavaScript

import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'http://localhost:8080/openai/v1',
  apiKey: 'not-needed'
});

const response = await client.chat.completions.create({
  model: 'claude',
  messages: [{ role: 'user', content: 'Hello!' }]
});

console.log(response.choices[0].message.content);

cURL

curl -X POST http://localhost:8080/openai/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "claude", "messages": [{"role": "user", "content": "Hello!"}]}'

Streaming Example (Python)

from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8080/openai/v1",
    api_key="not-needed"
)

stream = client.chat.completions.create(
    model="claude",
    messages=[{"role": "user", "content": "Tell me a story"}],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content is not None:
        print(chunk.choices[0].delta.content, end="")

Differences from OpenAI API

Feature OpenAI API clinvk Compatible
Models GPT-3.5, GPT-4 Claude, Codex, Gemini
Completions Supported Not implemented
Embeddings Supported Not implemented
Images Supported Not implemented
Audio Supported Not implemented
Error format OpenAI schema RFC 7807 Problem Details
Sessions Stateful Stateless (use REST API for sessions)

Configuration

OpenAI-compatible API uses the same server configuration:

server:
  host: "127.0.0.1"
  port: 8080
  request_timeout_secs: 300
  read_timeout_secs: 30
  write_timeout_secs: 300

Error Responses

Errors follow RFC 7807 Problem Details format:

{
  "type": "https://api.clinvk.dev/errors/backend-not-found",
  "title": "Backend Not Found",
  "status": 400,
  "detail": "The requested backend 'unknown' is not available"
}

Next Steps